summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacobo Aragunde Pérez <jaragunde@igalia.com>2014-01-27 19:46:37 +0100
committerJacobo Aragunde Pérez <jaragunde@igalia.com>2014-01-28 11:00:37 +0100
commit5391d4872e71d1edba7acc4ad2d2e3b5b97e1723 (patch)
tree494d32ae4520eafa5137bd5b03a0b45afe5332c3
parent007f260e0ba31b2449debd0329487679a851cb12 (diff)
ooxml: Preserve shape style and theme attributes for line
Line style and color can be defined by the shape style attributes or can be directly assigned by the user (and even using a theme color in the case of color attribute). This patch aims to preserve the relevant attributes of this feature after a roundtrip. For style attributes (wps:style/a:lnRef), they are kept and preserved in the "StyleLnRef" property of the shape InteropGrabBag. To be able to access to some of them, the methods getLineStyle, getLineJoint and getLineWidth were added to LineProperties object. For the line theme color (a:ln/a:solidFill/a:schemeClr), the original line color and the theme color name are preserved in the properties "OriginalLnSolidFillClr" and "SpPrLnSolidFillSchemeClr"of the Shape InteropGrabBag. On export time, we must check if the user has changed any properties of the shape line, this is done comparing the new shape attributes with the original values coming from the style and theme definitions. In case some of the attributes is different, the new attribute must be saved overwriting the old one. The data files for some /sd/qa/ unit tests were updated to reflect the new properties inside the Shape InteropGrabBag. Besides, an existing unit test in ooxmlexport was modified to include checks for the preservation of line style, line theme color and custom line style that override the style attributes. Change-Id: Iabb0cef9e3cc433676c201bc296fb7b373839a3f
-rw-r--r--include/oox/drawingml/lineproperties.hxx9
-rw-r--r--oox/source/drawingml/lineproperties.cxx25
-rw-r--r--oox/source/drawingml/shape.cxx37
-rw-r--r--oox/source/export/drawingml.cxx97
-rw-r--r--sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docxbin18425 -> 18703 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport.cxx53
6 files changed, 188 insertions, 33 deletions
diff --git a/include/oox/drawingml/lineproperties.hxx b/include/oox/drawingml/lineproperties.hxx
index 7cc31a35a77f..2b6494e13cfe 100644
--- a/include/oox/drawingml/lineproperties.hxx
+++ b/include/oox/drawingml/lineproperties.hxx
@@ -20,6 +20,8 @@
#ifndef INCLUDED_OOX_DRAWINGML_LINEPROPERTIES_HXX
#define INCLUDED_OOX_DRAWINGML_LINEPROPERTIES_HXX
+#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
#include <oox/drawingml/fillproperties.hxx>
namespace oox {
@@ -62,6 +64,13 @@ struct OOX_DLLPUBLIC LineProperties
ShapePropertyMap& rPropMap,
const GraphicHelper& rGraphicHelper,
sal_Int32 nPhClr = API_RGB_TRANSPARENT ) const;
+
+ /** Calculates the line style attribute from the internal state of the object */
+ ::com::sun::star::drawing::LineStyle getLineStyle() const;
+ /** Calculates the line joint attribute from the internal state of the object */
+ ::com::sun::star::drawing::LineJoint getLineJoint() const;
+ /** Calculates the line width attribute from the internal state of the object */
+ sal_Int32 getLineWidth() const;
};
// ============================================================================
diff --git a/oox/source/drawingml/lineproperties.cxx b/oox/source/drawingml/lineproperties.cxx
index df0ce89ac689..2fca061a8482 100644
--- a/oox/source/drawingml/lineproperties.cxx
+++ b/oox/source/drawingml/lineproperties.cxx
@@ -370,7 +370,7 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
drawing::LineStyle eLineStyle = (maLineFill.moFillType.get() == XML_noFill) ? drawing::LineStyle_NONE : drawing::LineStyle_SOLID;
// convert line width from EMUs to 1/100mm
- sal_Int32 nLineWidth = convertEmuToHmm( moLineWidth.get( 0 ) );
+ sal_Int32 nLineWidth = getLineWidth();
// create line dash from preset dash token (not for invisible line)
if( (eLineStyle != drawing::LineStyle_NONE) && (moPresetDash.differsFrom( XML_solid ) || !maCustomDash.empty()) )
@@ -419,6 +419,29 @@ void LineProperties::pushToPropMap( ShapePropertyMap& rPropMap,
}
}
+drawing::LineStyle LineProperties::getLineStyle() const
+{
+ // rules to calculate the line style inferred from the code in LineProperties::pushToPropMap
+ return (maLineFill.moFillType.get() == XML_noFill) ?
+ drawing::LineStyle_NONE :
+ (moPresetDash.differsFrom( XML_solid ) || (!moPresetDash && !maCustomDash.empty())) ?
+ drawing::LineStyle_DASH :
+ drawing::LineStyle_SOLID;
+}
+
+drawing::LineJoint LineProperties::getLineJoint() const
+{
+ if( moLineJoint.has() )
+ return lclGetLineJoint( moLineJoint.get() );
+
+ return drawing::LineJoint_NONE;
+}
+
+sal_Int32 LineProperties::getLineWidth() const
+{
+ return convertEmuToHmm( moLineWidth.get( 0 ) );
+}
+
// ============================================================================
} // namespace drawingml
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 47e84d9c8527..41fe7fd429d2 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -79,6 +79,10 @@ using namespace ::com::sun::star::style;
namespace oox { namespace drawingml {
+#define PUT_PROP( aProperties, nPos, sPropName, aPropValue ) \
+ aProperties[nPos].Name = sPropName; \
+ aProperties[nPos].Value = Any( aPropValue );
+
Shape::Shape( const sal_Char* pServiceName, bool bDefaultHeight )
: mbIsChild( false )
, mpLinePropertiesPtr( new LineProperties )
@@ -555,6 +559,20 @@ Reference< XShape > Shape::createAndInsert(
if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
aLineProperties.assignUsed( *pLineProps );
nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
+
+ // Store style-related properties to InteropGrabBag to be able to export them back
+ Sequence< PropertyValue > aProperties( 7 );
+ PUT_PROP( aProperties, 0, "SchemeClr", pLineRef->maPhClr.getSchemeName() );
+ PUT_PROP( aProperties, 1, "Idx", pLineRef->mnThemedIdx );
+ PUT_PROP( aProperties, 2, "Color", nLinePhClr );
+ PUT_PROP( aProperties, 3, "LineStyle", aLineProperties.getLineStyle() );
+ PUT_PROP( aProperties, 4, "LineJoint", aLineProperties.getLineJoint() );
+ PUT_PROP( aProperties, 5, "LineWidth", aLineProperties.getLineWidth() );
+ PUT_PROP( aProperties, 6, "Transformations", pLineRef->maPhClr.getTransformations() );
+ PropertyValue pStyleFillRef;
+ pStyleFillRef.Name = "StyleLnRef";
+ pStyleFillRef.Value = Any( aProperties );
+ putPropertyToGrabBag( pStyleFillRef );
}
if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
{
@@ -766,15 +784,22 @@ Reference< XShape > Shape::createAndInsert(
mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
}
- Sequence< PropertyValue > aProperties( 1 );
- aProperties[0].Name = "OriginalSolidFillClr";
- aProperties[0].Value = aShapeProps[PROP_FillColor];
+ // Store original fill and line colors of the shape and the theme color name to InteropGrabBag
+ sal_Int32 nSize = 2;
+ Sequence< PropertyValue > aProperties( nSize );
+ PUT_PROP( aProperties, 0, "OriginalSolidFillClr", aShapeProps[PROP_FillColor] );
+ PUT_PROP( aProperties, 1, "OriginalLnSolidFillClr", aShapeProps[PROP_LineColor] );
OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeName();
if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
{
- aProperties.realloc( 2 );
- aProperties[1].Name = "SpPrSolidFillSchemeClr";
- aProperties[1].Value = Any( sColorFillScheme );
+ aProperties.realloc( ++nSize );
+ PUT_PROP( aProperties, nSize - 1, "SpPrSolidFillSchemeClr", sColorFillScheme );
+ }
+ OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeName();
+ if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
+ {
+ aProperties.realloc( ++nSize );
+ PUT_PROP( aProperties, nSize - 1, "SpPrLnSolidFillSchemeClr", sLnColorFillScheme );
}
putPropertiesToGrabBag( aProperties );
}
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index dd165466b5e9..70f4f3b5d0cf 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -386,6 +386,37 @@ void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
sal_Bool bDashSet = sal_False;
bool bNoFill = false;
+ // get InteropGrabBag and search the relevant attributes
+ OUString sColorFillScheme;
+ sal_uInt32 nOriginalColor( 0 ), nStyleColor( 0 ), nStyleLineWidth( 0 );
+ Sequence< PropertyValue > aStyleProperties;
+ drawing::LineStyle aStyleLineStyle( drawing::LineStyle_NONE );
+ drawing::LineJoint aStyleLineJoint( drawing::LineJoint_NONE );
+ if ( GetProperty( rXPropSet, "InteropGrabBag" ) )
+ {
+ Sequence< PropertyValue > aGrabBag;
+ mAny >>= aGrabBag;
+ for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i )
+ if( aGrabBag[i].Name == "SpPrLnSolidFillSchemeClr" )
+ aGrabBag[i].Value >>= sColorFillScheme;
+ else if( aGrabBag[i].Name == "OriginalLnSolidFillClr" )
+ aGrabBag[i].Value >>= nOriginalColor;
+ else if( aGrabBag[i].Name == "StyleLnRef" )
+ aGrabBag[i].Value >>= aStyleProperties;
+ if( aStyleProperties.hasElements() )
+ {
+ for( sal_Int32 i=0; i < aStyleProperties.getLength(); ++i )
+ if( aStyleProperties[i].Name == "Color" )
+ aStyleProperties[i].Value >>= nStyleColor;
+ else if( aStyleProperties[i].Name == "LineStyle" )
+ aStyleProperties[i].Value >>= aStyleLineStyle;
+ else if( aStyleProperties[i].Name == "LineJoint" )
+ aStyleProperties[i].Value >>= aStyleLineJoint;
+ else if( aStyleProperties[i].Name == "LineWidth" )
+ aStyleProperties[i].Value >>= nStyleLineWidth;
+ }
+ }
+
GET( nLineWidth, LineWidth );
switch( aLineStyle ) {
@@ -414,12 +445,32 @@ void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
mpFS->startElementNS( XML_a, XML_ln,
XML_cap, cap,
- XML_w, nLineWidth > 1 ? I64S( MM100toEMU( nLineWidth ) ) : NULL,
+ XML_w, nLineWidth > 1 && nStyleLineWidth != nLineWidth ?
+ I64S( MM100toEMU( nLineWidth ) ) :NULL,
FSEND );
+
if( bColorSet )
- WriteSolidFill( nColor );
+ {
+ if( nColor != nOriginalColor )
+ // the user has set a different color for the line
+ WriteSolidFill( nColor );
+ else if( !sColorFillScheme.isEmpty() )
+ // the line had a scheme color and the user didn't change it
+ WriteSolidFill( sColorFillScheme );
+ else if( aStyleProperties.hasElements() )
+ {
+ if( nColor != nStyleColor )
+ // the line style defines some color but it wasn't being used
+ WriteSolidFill( nColor );
+ // in case the shape used the style color and the user didn't change it,
+ // we must not write a <a: solidFill> tag.
+ }
+ else
+ WriteSolidFill( nColor );
+ }
- if( bDashSet ) {
+ if( bDashSet && aStyleLineStyle != drawing::LineStyle_DASH ) {
+ // line style is a dash and it was not set by the shape style
mpFS->startElementNS( XML_a, XML_custDash, FSEND );
int i;
for( i = 0; i < aLineDash.Dots; i ++ )
@@ -439,20 +490,22 @@ void DrawingML::WriteOutline( Reference< XPropertySet > rXPropSet )
LineJoint eLineJoint;
mAny >>= eLineJoint;
- switch( eLineJoint ) {
- case LineJoint_NONE:
- case LineJoint_MIDDLE:
- case LineJoint_BEVEL:
- mpFS->singleElementNS( XML_a, XML_bevel, FSEND );
- break;
- default:
- case LineJoint_MITER:
- mpFS->singleElementNS( XML_a, XML_miter, FSEND );
- break;
- case LineJoint_ROUND:
- mpFS->singleElementNS( XML_a, XML_round, FSEND );
- break;
- }
+ if( aStyleLineJoint == LineJoint_NONE || aStyleLineJoint != eLineJoint )
+ // style-defined line joint does not exist, or is different from the shape's joint
+ switch( eLineJoint ) {
+ case LineJoint_NONE:
+ case LineJoint_MIDDLE:
+ case LineJoint_BEVEL:
+ mpFS->singleElementNS( XML_a, XML_bevel, FSEND );
+ break;
+ default:
+ case LineJoint_MITER:
+ mpFS->singleElementNS( XML_a, XML_miter, FSEND );
+ break;
+ case LineJoint_ROUND:
+ mpFS->singleElementNS( XML_a, XML_round, FSEND );
+ break;
+ }
}
if( !bNoFill )
@@ -1742,17 +1795,15 @@ void DrawingML::WriteShapeStyle( Reference< XPropertySet > xPropSet )
// extract the relevant properties from the grab bag
Sequence< PropertyValue > aGrabBag;
Sequence< PropertyValue > aFillRefProperties;
+ Sequence< PropertyValue > aLnRefProperties;
mAny >>= aGrabBag;
for( sal_Int32 i=0; i < aGrabBag.getLength(); ++i)
if( aGrabBag[i].Name == "StyleFillRef" )
- {
aGrabBag[i].Value >>= aFillRefProperties;
- break;
- }
-
- // write mock <a:lnRef>
- mpFS->singleElementNS( XML_a, XML_lnRef, XML_idx, I32S( 0 ), FSEND );
+ else if( aGrabBag[i].Name == "StyleLnRef" )
+ aGrabBag[i].Value >>= aLnRefProperties;
+ WriteStyleProperties( XML_lnRef, aLnRefProperties );
WriteStyleProperties( XML_fillRef, aFillRefProperties );
// write mock <a:effectRef>
diff --git a/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx b/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx
index 8fdbd06526c1..74db64e7f95a 100644
--- a/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx
+++ b/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 6b72c4efec58..ae3125091761 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -13,6 +13,7 @@
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineJoint.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/style/TabStop.hpp>
@@ -2537,27 +2538,73 @@ DECLARE_OOXMLEXPORT_TEST(testShapeThemePreservation, "shape-theme-preservation.d
assertXPath(pXmlDocument,
"/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:style/a:fillRef/a:schemeClr",
"val", "accent1");
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:style/a:lnRef",
+ "idx", "2");
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:style/a:lnRef/a:schemeClr",
+ "val", "accent1");
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:style/a:lnRef/a:schemeClr/a:shade",
+ "val", "50000");
// check shape style hasn't been overwritten
assertXPath(pXmlDocument,
"/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:solidFill",
0);
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[1]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:solidFill",
+ 0);
// check direct theme assignments have been preserved
assertXPath(pXmlDocument,
"/w:document/w:body/w:p[3]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:solidFill/a:schemeClr",
"val", "accent6");
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[3]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:solidFill/a:schemeClr",
+ "val", "accent3");
// check direct color assignments have been preserved
OUString sFillColor = getXPath(pXmlDocument,
"/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:solidFill/a:srgbClr",
"val");
CPPUNIT_ASSERT_EQUAL(sFillColor.toInt32(16), sal_Int32(0x00b050));
+ sal_Int32 nLineColor = getXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:solidFill/a:srgbClr",
+ "val").toInt32(16);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0xff0000), nLineColor);
+
+ // check direct line type assignments have been preserved
+ sal_Int32 nLineWidth = getXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln",
+ "w").toInt32();
+ CPPUNIT_ASSERT(abs(63500 - nLineWidth) < 1000); //some rounding errors in the conversion ooxml -> libo -> ooxml are tolerated
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:miter",
+ 1);
+ assertXPath(pXmlDocument,
+ "/w:document/w:body/w:p[5]/w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:ln/a:custDash",
+ 1);
+
+ uno::Reference<drawing::XShape> xShape1 = getShape(1);
+ uno::Reference<drawing::XShape> xShape2 = getShape(2);
+ uno::Reference<drawing::XShape> xShape3 = getShape(3);
// check colors are properly applied to shapes on import
- CPPUNIT_ASSERT_EQUAL(sal_Int32(0x4f81bd), getProperty<sal_Int32>(getShape(1), "FillColor"));
- CPPUNIT_ASSERT_EQUAL(sal_Int32(0xf79646), getProperty<sal_Int32>(getShape(2), "FillColor"));
- CPPUNIT_ASSERT_EQUAL(sal_Int32(0x00b050), getProperty<sal_Int32>(getShape(3), "FillColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0x4f81bd), getProperty<sal_Int32>(xShape1, "FillColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0xf79646), getProperty<sal_Int32>(xShape2, "FillColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0x00b050), getProperty<sal_Int32>(xShape3, "FillColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0x3a5f8b), getProperty<sal_Int32>(xShape1, "LineColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0x9bbb59), getProperty<sal_Int32>(xShape2, "LineColor"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0xff0000), getProperty<sal_Int32>(xShape3, "LineColor"));
+
+ // check line properties are properly applied to shapes on import
+ CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_SOLID, getProperty<drawing::LineStyle>(xShape1, "LineStyle"));
+ CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_SOLID, getProperty<drawing::LineStyle>(xShape2, "LineStyle"));
+ CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_DASH, getProperty<drawing::LineStyle>(xShape3, "LineStyle"));
+ CPPUNIT_ASSERT_EQUAL(drawing::LineJoint_ROUND, getProperty<drawing::LineJoint>(xShape1, "LineJoint"));
+ CPPUNIT_ASSERT_EQUAL(drawing::LineJoint_ROUND, getProperty<drawing::LineJoint>(xShape2, "LineJoint"));
+ CPPUNIT_ASSERT_EQUAL(drawing::LineJoint_MITER, getProperty<drawing::LineJoint>(xShape3, "LineJoint"));
}
DECLARE_OOXMLEXPORT_TEST(testTOCFlag_u,"testTOCFlag_u.docx")