diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2023-05-24 12:31:48 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2023-05-26 10:08:52 +0200 |
commit | c2bea1bedd2ee8bc4007fd23c6cb839a692297a7 (patch) | |
tree | cabb61287db769cae2f412e45125ddba9110249b /oox | |
parent | 7d87770986fdfc43dd5d4b514f68026ff6ededcf (diff) |
MCGR: Border restoration support
Due to tdf#155362 I added code to be able in case we
would need it to convert a BGradient using added
tooling from having offsets in the GradientSteps
and no border to adapted GradientSteps and border.
This is preferrable due to our GradientStyle_RECT
(and GradientStyle_ELLIPTICAL too) use that 'non-
linear' paint aka move-two-pixels-inside, someone
else called it 'frame-paint'. This does not bode
well with the border being applied 'linear' at the
same time (argh). Thus - while in principle all is
correct when re-importing a GradientStyle_RECT
with a border after export to pptx, it looks
slightly better ('correcter') wen doing so. That is
because when being able to and restoring a border
at least that border part *is* applied linearly.
I took the chance to further apply tooling, move
it to classes involved and instead of awt::Gradient2
use more basegfx::BGradient since it can and does
host tooling. This is also a preparation to be
able to adapt (restore) border in case of turn-
around in ODF where the importing instance is before
MCGR existance and has to handle Start/EndColor.
Needed to take more care with using BGradient instead
of awt::Gradient2 for initialization, also better
dividing/organization of tooling, already preparation
to use for other purposes.
Change-Id: I2d3a4240a5ac6fff9211b46642ee80366dc09e3d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152194
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/source/drawingml/fillproperties.cxx | 98 |
1 files changed, 44 insertions, 54 deletions
diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index a42418198c12..705f2dc3b55a 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -458,19 +458,11 @@ void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelp // do not create gradient struct if property is not supported... if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) ) { - // use awt::Gradient2, prepare ColorStops - awt::Gradient2 aGradient; - assert(aGradient.ColorStops.get() && "cid#1524676 aGradient.ColorStops._pSequence won't be null here"); + // prepare ColorStops basegfx::BColorStops aColorStops; basegfx::BColorStops aTransparencyStops; bool bContainsTransparency(false); - // set defaults - aGradient.Angle = 900; - aGradient.StartIntensity = 100; - aGradient.EndIntensity = 100; - aGradient.Style = awt::GradientStyle_LINEAR; - // convert to BColorStops, check for contained transparency for (const auto& rCandidate : maGradientProps.maGradientStops) { @@ -489,6 +481,20 @@ void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelp } } + // prepare BGradient with some defaults + // CAUTION: This used awt::Gradient2 before who's empty constructor + // (see workdir/UnoApiHeadersTarget/offapi/normal/com/sun/ + // star/awt/Gradient.hpp) initializes all to zeros, so reflect + // this here. OTOH set all that were set, e.g. Start/EndIntens + // were set to 100, so just use default of BGradient constructor + basegfx::BGradient aGradient( + aColorStops, + awt::GradientStyle_LINEAR, + Degree10(900), + 0, // border + 0, // OfsX -> 0, not 50 (!) + 0); // OfsY -> 0, not 50 (!) + // "rotate with shape" set to false -> do not rotate if (!maGradientProps.moRotateWithShape.value_or(true)) { @@ -499,77 +505,61 @@ void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelp { IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; - aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterX / PER_PERCENT, 0, 100); + aGradient.SetXOffset(getLimitedValue<sal_Int16, sal_Int32>( + nCenterX / PER_PERCENT, 0, 100)); sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; - aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterY / PER_PERCENT, 0, 100); + aGradient.SetYOffset(getLimitedValue<sal_Int16, sal_Int32>( + nCenterY / PER_PERCENT, 0, 100)); if( maGradientProps.moGradientPath.value() == XML_circle ) { // Style should be radial at least when the horizontal center is at 50%. // Otherwise import as a linear gradient, because it is the most similar to the MSO radial style. - // aGradient.Style = awt::GradientStyle_LINEAR; - if( aGradient.XOffset == 100 && aGradient.YOffset == 100 ) - aGradient.Angle = 450; - else if( aGradient.XOffset == 0 && aGradient.YOffset == 100 ) - aGradient.Angle = 3150; - else if( aGradient.XOffset == 100 && aGradient.YOffset == 0 ) - aGradient.Angle = 1350; - else if( aGradient.XOffset == 0 && aGradient.YOffset == 0 ) - aGradient.Angle = 2250; + // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR); + if( 100 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(450) ); + else if( 0 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(3150) ); + else if( 100 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(1350) ); + else if( 0 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() ) + aGradient.SetAngle( Degree10(2250) ); else - aGradient.Style = awt::GradientStyle_RADIAL; + aGradient.SetGradientStyle(awt::GradientStyle_RADIAL); } else { - aGradient.Style = awt::GradientStyle_RECT; + aGradient.SetGradientStyle(awt::GradientStyle_RECT); } aColorStops.reverseColorStops(); + aGradient.SetColorStops(aColorStops); aTransparencyStops.reverseColorStops(); } else if (!maGradientProps.maGradientStops.empty()) { - // aGradient.Style = awt::GradientStyle_LINEAR; - sal_Int32 nShadeAngle = maGradientProps.moShadeAngle.value_or( 0 ); + // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR); + sal_Int32 nShadeAngle(maGradientProps.moShadeAngle.value_or( 0 )); // Adjust for flips if ( bFlipH ) nShadeAngle = 180*60000 - nShadeAngle; if ( bFlipV ) nShadeAngle = -nShadeAngle; const sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation; + // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) - aGradient.Angle = static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); + aGradient.SetAngle(Degree10(static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ))); } - // set BColorStops using UNO API - aGradient.ColorStops = aColorStops.getAsColorStopSequence(); - - // for compatibility, still set StartColor/EndColor - // NOTE: All code after adapting to multi color gradients works - // using the ColorSteps, so in principle Start/EndColor might - // be either - // (a) ignored consequently everywhere or - // (b) be set/added consequently everywhere - // since this is - in principle - redundant data. - // Be aware that e.g. cases like DrawingML::EqualGradients - // and others would have to be identified and adapted (!) - // Since awt::Gradient2 is UNO API data there might - // be cases where just awt::Gradient is transferred, so (b) - // is far better backwards compatible and thus more safe, so - // all changes will make use of additionally using/setting - // these additionally, but will only make use of the given - // ColorSteps if these are not empty, assuming that these - // already contain Start/EndColor. - // In principle that redundancy and that it is conflict-free - // could even be checked and asserted, but consequently using - // (b) methodically should be safe. - aGradient.StartColor = static_cast<sal_Int32>(::Color(aColorStops.front().getStopColor())); - aGradient.EndColor = static_cast<sal_Int32>(::Color(aColorStops.back().getStopColor())); + if (awt::GradientStyle_RECT == aGradient.GetGradientStyle()) + { + // MCGR: tdf#155362: better support border + // CAUTION: Need to handle TransparencyStops if used + aGradient.tryToRecreateBorder(aTransparencyStops.empty() ? nullptr : &aTransparencyStops); + } // push gradient or named gradient to property map - if (rPropMap.setProperty(ShapeProperty::FillGradient, aGradient)) + if (rPropMap.setProperty(ShapeProperty::FillGradient, aGradient.getAsGradient2())) { eFillStyle = FillStyle_GRADIENT; } @@ -577,8 +567,8 @@ void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelp // push gradient transparency to property map if it exists if (!aTransparencyStops.empty()) { - aGradient.ColorStops = aTransparencyStops.getAsColorStopSequence(); - rPropMap.setProperty(ShapeProperty::GradientTransparency, aGradient); + aGradient.SetColorStops(aTransparencyStops); + rPropMap.setProperty(ShapeProperty::GradientTransparency, aGradient.getAsGradient2()); } } break; |