diff options
author | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-01-31 14:02:12 +0100 |
---|---|---|
committer | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-02-05 02:00:03 +0100 |
commit | 2fcf3a871c94feeca11619ef5c8c0466ce61eb74 (patch) | |
tree | be65c549156c3dea9c5b4d8ceadd7f3e43280c71 /oox | |
parent | c482da1cf440beb1464b9ae1b992e3d0e7a4ab8d (diff) |
ooxml: preserve gradient shape fill
LibreOffice is unable to properly import the custom gradient fills
defined in ooxml documents. To prevent data loss, we save the
original gradient fill definition in the shape interopgrabbag and we
write it back to the document on export.
In case the user has changed the fill properties of a shape, the
original fill will be discarded in favor of the new fill.
We have added a new ooxmlexport unit test to test this feature.
We have also added some missing transformations to the methods
getColorTransformationName and getColorTransformationToken in Color
class, and refactored some code in class DrawingML to the method
WriteColor( OUString, Sequence ).
Change-Id: Ie71f89eaa20313561aa9180ea33b76f3fb5e5df6
Diffstat (limited to 'oox')
-rw-r--r-- | oox/source/drawingml/color.cxx | 9 | ||||
-rw-r--r-- | oox/source/drawingml/shape.cxx | 41 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 120 |
3 files changed, 158 insertions, 12 deletions
diff --git a/oox/source/drawingml/color.cxx b/oox/source/drawingml/color.cxx index 4a878273b30c..84dbd35774d0 100644 --- a/oox/source/drawingml/color.cxx +++ b/oox/source/drawingml/color.cxx @@ -358,6 +358,9 @@ OUString Color::getColorTransformationName( sal_Int32 nElement ) case XML_blue: return OUString( "blue" ); case XML_blueMod: return OUString( "blueMod" ); case XML_blueOff: return OUString( "blueOff" ); + case XML_alpha: return OUString( "alpha" ); + case XML_alphaMod: return OUString( "alphaMod" ); + case XML_alphaOff: return OUString( "alphaOff" ); case XML_hue: return OUString( "hue" ); case XML_hueMod: return OUString( "hueMod" ); case XML_hueOff: return OUString( "hueOff" ); @@ -399,6 +402,12 @@ sal_Int32 Color::getColorTransformationToken( OUString sName ) return XML_blueMod; else if( sName == "blueOff" ) return XML_blueOff; + else if( sName == "alpha" ) + return XML_alpha; + else if( sName == "alphaMod" ) + return XML_alphaMod; + else if( sName == "alphaOff" ) + return XML_alphaOff; else if( sName == "hue" ) return XML_hue; else if( sName == "hueMod" ) diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 3259f72b8a06..99940ab790d4 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -799,6 +799,47 @@ Reference< XShape > Shape::createAndInsert( PUT_PROP( aProperties, nSize - 1, "SpPrLnSolidFillSchemeClr", sLnColorFillScheme ); } putPropertiesToGrabBag( aProperties ); + + // Store original gradient fill of the shape to InteropGrabBag + // LibreOffice doesn't support all the kinds of gradient so we save its complete definition + if( aShapeProps.hasProperty( PROP_FillGradient ) ) + { + Sequence< PropertyValue > aGradientStops( aFillProperties.maGradientProps.maGradientStops.size() ); + ::std::map< double, Color >::iterator aIt = aFillProperties.maGradientProps.maGradientStops.begin(); + for( sal_uInt32 i = 0; i < aFillProperties.maGradientProps.maGradientStops.size(); ++i ) + { // for each stop in the gradient definition: + + // save position + Sequence< PropertyValue > aGradientStop( 3 ); + PUT_PROP( aGradientStop, 0, "Pos", aIt->first ); + + OUString sStopColorScheme = aIt->second.getSchemeName(); + if( sStopColorScheme.isEmpty() ) + { + // save RGB color + PUT_PROP( aGradientStop, 1, "RgbClr", aIt->second.getColor( rGraphicHelper, nFillPhClr ) ); + // in the case of a RGB color, transformations are already applied to + // the color with the exception of alpha transformations. We only need + // to keep the transparency value to calculate the alpha value later. + if( aIt->second.hasTransparency() ) + { + PUT_PROP( aGradientStop, 2, "Transparency", aIt->second.getTransparency() ); + } + } + else + { + // save color with scheme name + PUT_PROP( aGradientStop, 1, "SchemeClr", sStopColorScheme ); + // save all color transformations + PUT_PROP( aGradientStop, 2, "Transformations", aIt->second.getTransformations() ); + } + + PUT_PROP( aGradientStops, i, OUString::number( i ), aGradientStop ); + ++aIt; + } + putPropertyToGrabBag( "GradFillDefinition", Any( aGradientStops ) ); + putPropertyToGrabBag( "OriginalGradFill", Any( aShapeProps[PROP_FillGradient] ) ); + } } // These can have a custom geometry, so position should be set here, diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 3db4c04a10bc..9fc0ec9a2120 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -179,6 +179,34 @@ void DrawingML::WriteColor( sal_uInt32 nColor, sal_Int32 nAlpha ) } } +void DrawingML::WriteColor( OUString sColorSchemeName, Sequence< PropertyValue > aTransformations ) +{ + if( aTransformations.hasElements() ) + { + mpFS->startElementNS( XML_a, XML_schemeClr, + XML_val, USS( sColorSchemeName ), + FSEND ); + WriteColorTransformations( aTransformations ); + mpFS->endElementNS( XML_a, XML_schemeClr ); + } + else + mpFS->singleElementNS( XML_a, XML_schemeClr, + XML_val, USS( sColorSchemeName ), + FSEND ); +} + +void DrawingML::WriteColorTransformations( Sequence< PropertyValue > aTransformations ) +{ + for( sal_Int32 i = 0; i < aTransformations.getLength(); i++ ) + { + sal_Int32 nToken = Color::getColorTransformationToken( aTransformations[i].Name ); + sal_Int32 nValue; aTransformations[i].Value >>= nValue; + + if( nToken != XML_TOKEN_INVALID ) + mpFS->singleElementNS( XML_a, nToken, XML_val, I32S( nValue ), FSEND ); + } +} + void DrawingML::WriteSolidFill( sal_uInt32 nColor, sal_Int32 nAlpha ) { mpFS->startElementNS( XML_a, XML_solidFill, FSEND ); @@ -283,14 +311,93 @@ sal_uInt32 DrawingML::ColorWithIntensity( sal_uInt32 nColor, sal_uInt32 nIntensi | ( ( ( ( ( nColor & 0xff0000 ) >> 8 ) * nIntensity ) / 100 ) << 8 ); } +bool DrawingML::EqualGradients( awt::Gradient aGradient1, awt::Gradient aGradient2 ) +{ + return aGradient1.Style == aGradient2.Style && + aGradient1.StartColor == aGradient2.StartColor && + aGradient1.EndColor == aGradient2.EndColor && + aGradient1.Angle == aGradient2.Angle && + aGradient1.Border == aGradient2.Border && + aGradient1.XOffset == aGradient2.XOffset && + aGradient1.YOffset == aGradient2.YOffset && + aGradient1.StartIntensity == aGradient2.StartIntensity && + aGradient1.EndIntensity == aGradient2.EndIntensity && + aGradient1.StepCount == aGradient2.StepCount; +} + void DrawingML::WriteGradientFill( Reference< XPropertySet > rXPropSet ) { awt::Gradient aGradient; if( GETA( FillGradient ) ) { aGradient = *static_cast< const awt::Gradient* >( mAny.getValue() ); + // get InteropGrabBag and search the relevant attributes + awt::Gradient aOriginalGradient; + Sequence< PropertyValue > aGradientStops; + if ( GetProperty( rXPropSet, "InteropGrabBag" ) ) + { + Sequence< PropertyValue > aGrabBag; + mAny >>= aGrabBag; + for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i ) + if( aGrabBag[i].Name == "GradFillDefinition" ) + aGrabBag[i].Value >>= aGradientStops; + else if( aGrabBag[i].Name == "OriginalGradFill" ) + aGrabBag[i].Value >>= aOriginalGradient; + } + mpFS->startElementNS( XML_a, XML_gradFill, FSEND ); + // check if an ooxml gradient had been imported and if the user has modified it + if( aGradientStops.hasElements() && EqualGradients( aOriginalGradient, aGradient ) ) + { + // write back the original gradient + mpFS->startElementNS( XML_a, XML_gsLst, FSEND ); + + // get original stops and write them + for( sal_Int32 i=0; i < aGradientStops.getLength(); ++i ) + { + Sequence< PropertyValue > aGradientStop; + aGradientStops[i].Value >>= aGradientStop; + + // get values + OUString sSchemeClr; + double nPos = 0; + sal_Int16 nTransparency = 0; + sal_Int32 nRgbClr = 0; + Sequence< PropertyValue > aTransformations; + for( sal_Int32 j=0; j < aGradientStop.getLength(); ++j ) + if( aGradientStop[j].Name == "SchemeClr" ) + aGradientStop[j].Value >>= sSchemeClr; + else if( aGradientStop[j].Name == "RgbClr" ) + aGradientStop[j].Value >>= nRgbClr; + else if( aGradientStop[j].Name == "Pos" ) + aGradientStop[j].Value >>= nPos; + else if( aGradientStop[j].Name == "Transparency" ) + aGradientStop[j].Value >>= nTransparency; + else if( aGradientStop[j].Name == "Transformations" ) + aGradientStop[j].Value >>= aTransformations; + + // write stop + mpFS->startElementNS( XML_a, XML_gs, + XML_pos, OString::number( nPos * 100000.0 ).getStr(), + FSEND ); + if( sSchemeClr.isEmpty() ) + { + // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency()) + sal_Int32 nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) ); + WriteColor( nRgbClr, nAlpha ); + } + else + WriteColor( sSchemeClr, aTransformations ); + mpFS->endElementNS( XML_a, XML_gs ); + } + mpFS->endElementNS( XML_a, XML_gsLst ); + + mpFS->singleElementNS( XML_a, XML_lin, + XML_ang, I32S( ( ( ( 3600 - aGradient.Angle + 900 ) * 6000 ) % 21600000 ) ), + FSEND ); + } + else switch( aGradient.Style ) { default: case GradientStyle_LINEAR: @@ -1798,18 +1905,7 @@ void DrawingML::WriteStyleProperties( sal_Int32 nTokenId, Sequence< PropertyValu else if( aProperties[i].Name == "Transformations" ) aProperties[i].Value >>= aTransformations; mpFS->startElementNS( XML_a, nTokenId, XML_idx, I32S( nIdx ), FSEND ); - mpFS->startElementNS( XML_a, XML_schemeClr, - XML_val, USS( sSchemeClr ), - FSEND ); - for( sal_Int32 i = 0; i < aTransformations.getLength(); i++ ) - { - sal_Int32 nValue; - aTransformations[i].Value >>= nValue; - mpFS->singleElementNS( XML_a, Color::getColorTransformationToken( aTransformations[i].Name ), - XML_val, I32S( nValue ), - FSEND ); - } - mpFS->endElementNS( XML_a, XML_schemeClr ); + WriteColor( sSchemeClr, aTransformations ); mpFS->endElementNS( XML_a, nTokenId ); } else |