From c2bea1bedd2ee8bc4007fd23c6cb839a692297a7 Mon Sep 17 00:00:00 2001 From: "Armin Le Grand (allotropia)" Date: Wed, 24 May 2023 12:31:48 +0200 Subject: 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 --- oox/source/drawingml/fillproperties.cxx | 98 +++++++++++++++------------------ 1 file changed, 44 insertions(+), 54 deletions(-) (limited to 'oox') 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( - nCenterX / PER_PERCENT, 0, 100); + aGradient.SetXOffset(getLimitedValue( + nCenterX / PER_PERCENT, 0, 100)); sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; - aGradient.YOffset = getLimitedValue( - nCenterY / PER_PERCENT, 0, 100); + aGradient.SetYOffset(getLimitedValue( + 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(::Color(aColorStops.front().getStopColor())); - aGradient.EndColor = static_cast(::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; -- cgit v1.2.3