[Libreoffice-commits] core.git: 2 commits - include/oox oox/source sw/qa

Jacobo Aragunde Pérez jaragunde at igalia.com
Tue Jan 28 02:08:12 PST 2014


 include/oox/drawingml/color.hxx                             |   11 
 include/oox/drawingml/lineproperties.hxx                    |    9 
 include/oox/export/drawingml.hxx                            |    1 
 oox/source/drawingml/color.cxx                              |  101 +++++++
 oox/source/drawingml/lineproperties.cxx                     |   25 +
 oox/source/drawingml/shape.cxx                              |   41 ++-
 oox/source/export/drawingml.cxx                             |  152 ++++++++----
 sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx                    |   53 +++-
 9 files changed, 340 insertions(+), 53 deletions(-)

New commits:
commit 5391d4872e71d1edba7acc4ad2d2e3b5b97e1723
Author: Jacobo Aragunde Pérez <jaragunde at igalia.com>
Date:   Mon Jan 27 19:46:37 2014 +0100

    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

diff --git a/include/oox/drawingml/lineproperties.hxx b/include/oox/drawingml/lineproperties.hxx
index 7cc31a3..2b6494e 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 df0ce89..2fca061 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 47e84d9..41fe7fd 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 dd16546..70f4f3b 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 8fdbd06..74db64e 100644
Binary files a/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx and b/sw/qa/extras/ooxmlexport/data/shape-theme-preservation.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 6b72c4e..ae31250 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")
commit 007f260e0ba31b2449debd0329487679a851cb12
Author: Jacobo Aragunde Pérez <jaragunde at igalia.com>
Date:   Mon Jan 27 19:32:55 2014 +0100

    ooxml: Preserve color transformations in shape style definitions
    
    Color tags like <a:schemeClr> can have children tags that modify the
    specified color. These modifications were applied on import time in
    the Color object, but they were not preserved.
    
    We added a member to Color object to preserve the unaltered list of
    transformations. The method getTransformations() returns that member,
    and the methods getColorTransformationName and
    getColorTransformationToken were added to transform the tokens into
    strings that can be added to an InteropGrabBag and viceversa.
    
    The transformations are added to the Shape InteropGrabBag in the
    method Shape::createAndInsert, and they are written back on export
    time at DrawingML::WriteStyleProperties.
    
    The data files for some /sd/qa/ unit tests were updated to reflect
    the new properties inside the Shape InteropGrabBag.
    
    Change-Id: Ieb164268c3b79f2d9b7ed3a4954b5de3b7a5811c

diff --git a/include/oox/drawingml/color.hxx b/include/oox/drawingml/color.hxx
index 481113b..d3cd6a6 100644
--- a/include/oox/drawingml/color.hxx
+++ b/include/oox/drawingml/color.hxx
@@ -22,6 +22,8 @@
 
 #include <vector>
 #include <boost/shared_ptr.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
 #include <sal/types.h>
 #include <rtl/instance.hxx>
 #include <rtl/ustring.hxx>
@@ -94,6 +96,13 @@ public:
 
     /** Returns the scheme name from the a:schemeClr element for interoperability purposes */
     OUString            getSchemeName() const { return msSchemeName; }
+    /** Returns the unaltered list of transformations for interoperability purposes */
+    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > getTransformations() const;
+
+    /** Translates between color transformation tokens and their names */
+    static OUString     getColorTransformationName( sal_Int32 nElement );
+    /** Translates between color transformation token names and the corresponding token */
+    static sal_Int32    getColorTransformationToken( OUString sName );
 
 private:
     /** Internal helper for getColor(). */
@@ -137,6 +146,8 @@ private:
     sal_Int32           mnAlpha;        /// Alpha value (color opacity).
 
     OUString            msSchemeName;   /// Scheme name from the a:schemeClr element for interoperability purposes
+    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >
+                        maInteropTransformations;   /// Unaltered list of transformations for interoperability purposes
 };
 
 typedef boost::shared_ptr< Color > ColorPtr;
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 31c6f20..445e895 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -100,6 +100,7 @@ protected:
     const char* GetFieldType( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > rRun, sal_Bool& bIsField );
 
     OUString WriteImage( const OUString& rURL );
+    void WriteStyleProperties( sal_Int32 nTokenId, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aProperties );
 
     const char* GetComponentDir();
     const char* GetRelationCompPrefix();
diff --git a/oox/source/drawingml/color.cxx b/oox/source/drawingml/color.cxx
index 52d5465..4a87827 100644
--- a/oox/source/drawingml/color.cxx
+++ b/oox/source/drawingml/color.cxx
@@ -312,6 +312,10 @@ void Color::addTransformation( sal_Int32 nElement, sal_Int32 nValue )
         case XML_alphaOff:  lclOffValue( mnAlpha, nValue ); break;
         default:            maTransforms.push_back( Transformation( nToken, nValue ) );
     }
+    sal_Int32 nSize = maInteropTransformations.getLength();
+    maInteropTransformations.realloc(nSize + 1);
+    maInteropTransformations[nSize].Name = getColorTransformationName( nToken );
+    maInteropTransformations[nSize].Value = ::com::sun::star::uno::Any( nValue );
 }
 
 void Color::addChartTintTransformation( double fTint )
@@ -332,9 +336,106 @@ void Color::addExcelTintTransformation( double fTint )
 void Color::clearTransformations()
 {
     maTransforms.clear();
+    maInteropTransformations.realloc(0);
     clearTransparence();
 }
 
+::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > Color::getTransformations() const
+{
+    return maInteropTransformations;
+}
+
+OUString Color::getColorTransformationName( sal_Int32 nElement )
+{
+    switch( nElement )
+    {
+        case XML_red:       return OUString( "red" );
+        case XML_redMod:    return OUString( "redMod" );
+        case XML_redOff:    return OUString( "redOff" );
+        case XML_green:     return OUString( "green" );
+        case XML_greenMod:  return OUString( "greenMod" );
+        case XML_greenOff:  return OUString( "greenOff" );
+        case XML_blue:      return OUString( "blue" );
+        case XML_blueMod:   return OUString( "blueMod" );
+        case XML_blueOff:   return OUString( "blueOff" );
+        case XML_hue:       return OUString( "hue" );
+        case XML_hueMod:    return OUString( "hueMod" );
+        case XML_hueOff:    return OUString( "hueOff" );
+        case XML_sat:       return OUString( "sat" );
+        case XML_satMod:    return OUString( "satMod" );
+        case XML_satOff:    return OUString( "satOff" );
+        case XML_lum:       return OUString( "lum" );
+        case XML_lumMod:    return OUString( "lumMod" );
+        case XML_lumOff:    return OUString( "lumOff" );
+        case XML_shade:     return OUString( "shade" );
+        case XML_tint:      return OUString( "tint" );
+        case XML_gray:      return OUString( "gray" );
+        case XML_comp:      return OUString( "comp" );
+        case XML_inv:       return OUString( "inv" );
+        case XML_gamma:     return OUString( "gamma" );
+        case XML_invGamma:  return OUString( "invGamma" );
+    }
+    SAL_WARN( "oox.drawingml", "Color::getColorTransformationName - unexpected transformation type" );
+    return OUString();
+}
+
+sal_Int32 Color::getColorTransformationToken( OUString sName )
+{
+    if( sName == "red" )
+        return XML_red;
+    else if( sName == "redMod" )
+        return XML_redMod;
+    else if( sName == "redOff" )
+        return XML_redOff;
+    else if( sName == "green" )
+        return XML_green;
+    else if( sName == "greenMod" )
+        return XML_greenMod;
+    else if( sName == "greenOff" )
+        return XML_greenOff;
+    else if( sName == "blue" )
+        return XML_blue;
+    else if( sName == "blueMod" )
+        return XML_blueMod;
+    else if( sName == "blueOff" )
+        return XML_blueOff;
+    else if( sName == "hue" )
+        return XML_hue;
+    else if( sName == "hueMod" )
+        return XML_hueMod;
+    else if( sName == "hueOff" )
+        return XML_hueOff;
+    else if( sName == "sat" )
+        return XML_sat;
+    else if( sName == "satMod" )
+        return XML_satMod;
+    else if( sName == "satOff" )
+        return XML_satOff;
+    else if( sName == "lum" )
+        return XML_lum;
+    else if( sName == "lumMod" )
+        return XML_lumMod;
+    else if( sName == "lumOff" )
+        return XML_lumOff;
+    else if( sName == "shade" )
+        return XML_shade;
+    else if( sName == "tint" )
+        return XML_tint;
+    else if( sName == "gray" )
+        return XML_gray;
+    else if( sName == "comp" )
+        return XML_comp;
+    else if( sName == "inv" )
+        return XML_inv;
+    else if( sName == "gamma" )
+        return XML_gamma;
+    else if( sName == "invGamma" )
+        return XML_invGamma;
+
+    SAL_WARN( "oox.drawingml", "Color::getColorTransformationToken - unexpected transformation type" );
+    return XML_TOKEN_INVALID;
+}
+
 void Color::clearTransparence()
 {
     mnAlpha = MAX_PERCENT;
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 78b3f35..47e84d9 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -565,13 +565,15 @@ Reference< XShape > Shape::createAndInsert(
                 OUString sColorScheme = pFillRef->maPhClr.getSchemeName();
                 if( !sColorScheme.isEmpty() )
                 {
-                    Sequence< PropertyValue > aProperties(3);
+                    Sequence< PropertyValue > aProperties(4);
                     aProperties[0].Name = "SchemeClr";
                     aProperties[0].Value = Any( sColorScheme );
                     aProperties[1].Name = "Idx";
                     aProperties[1].Value = Any( pFillRef->mnThemedIdx );
                     aProperties[2].Name = "Color";
                     aProperties[2].Value = Any( nFillPhClr );
+                    aProperties[3].Name = "Transformations";
+                    aProperties[3].Value = Any( pFillRef->maPhClr.getTransformations() );
 
                     PropertyValue pStyleFillRef;
                     pStyleFillRef.Name = "StyleFillRef";
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index db05030..dd16546 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -20,6 +20,7 @@
 #include "oox/core/xmlfilterbase.hxx"
 #include "oox/export/drawingml.hxx"
 #include "oox/export/utils.hxx"
+#include <oox/drawingml/color.hxx>
 #include <oox/token/tokens.hxx>
 
 #include <cstdio>
@@ -1698,6 +1699,40 @@ void DrawingML::WriteFill( Reference< XPropertySet > xPropSet )
     return;
 }
 
+void DrawingML::WriteStyleProperties( sal_Int32 nTokenId, Sequence< PropertyValue > aProperties )
+{
+    if( aProperties.getLength() > 0 )
+    {
+        OUString sSchemeClr;
+        sal_uInt32 nIdx = 0;
+        Sequence< PropertyValue > aTransformations;
+        for( sal_Int32 i=0; i < aProperties.getLength(); ++i)
+            if( aProperties[i].Name == "SchemeClr" )
+                aProperties[i].Value >>= sSchemeClr;
+            else if( aProperties[i].Name == "Idx" )
+                aProperties[i].Value >>= nIdx;
+            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 );
+        mpFS->endElementNS( XML_a, nTokenId );
+    }
+    else
+        // write mock <a:*Ref> tag
+        mpFS->singleElementNS( XML_a, nTokenId, XML_idx, I32S( 0 ), FSEND );
+}
+
 void DrawingML::WriteShapeStyle( Reference< XPropertySet > xPropSet )
 {
     // check existence of the grab bag
@@ -1718,25 +1753,7 @@ void DrawingML::WriteShapeStyle( Reference< XPropertySet > xPropSet )
     // write mock <a:lnRef>
     mpFS->singleElementNS( XML_a, XML_lnRef, XML_idx, I32S( 0 ), FSEND );
 
-    // write <a:fillRef>
-    if( aFillRefProperties.getLength() > 0 )
-    {
-        OUString sSchemeClr;
-        sal_uInt32 nIdx = 0;
-        for( sal_Int32 i=0; i < aFillRefProperties.getLength(); ++i)
-            if( aFillRefProperties[i].Name == "SchemeClr" )
-                aFillRefProperties[i].Value >>= sSchemeClr;
-            else if( aFillRefProperties[i].Name == "Idx" )
-                aFillRefProperties[i].Value >>= nIdx;
-        mpFS->startElementNS( XML_a, XML_fillRef, XML_idx, I32S( nIdx ), FSEND );
-        mpFS->singleElementNS( XML_a, XML_schemeClr, XML_val,
-                               OUStringToOString( sSchemeClr, RTL_TEXTENCODING_ASCII_US ).getStr(),
-                               FSEND );
-        mpFS->endElementNS( XML_a, XML_fillRef );
-    }
-    else
-        // write mock <a:fillRef>
-        mpFS->singleElementNS( XML_a, XML_fillRef, XML_idx, I32S( 0 ), FSEND );
+    WriteStyleProperties( XML_fillRef, aFillRefProperties );
 
     // write mock <a:effectRef>
     mpFS->singleElementNS( XML_a, XML_effectRef, XML_idx, I32S( 0 ), FSEND );


More information about the Libreoffice-commits mailing list