filter/source/msfilter/escherex.cxx                          |    9 
 filter/source/msfilter/msdffimp.cxx                          |  121 ++-
 include/xmloff/xmltoken.hxx                                  |    1 
 offapi/UnoApi_offapi.mk                                      |    1 
 offapi/com/sun/star/drawing/EnhancedCustomShapeExtrusion.idl |   11 
 offapi/com/sun/star/drawing/EnhancedCustomShapeMetalType.idl |   36 +
 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng  |    9 
 svx/qa/unit/customshapes.cxx                                 |  109 +++
 svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc            |binary
 svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc              |binary
 svx/qa/unit/data/tdf145700_3D_NonUI.doc                      |binary
 svx/qa/unit/svdraw.cxx                                       |   54 +
 svx/source/customshapes/EnhancedCustomShape3d.cxx            |  363 ++++++++---
 svx/source/tbxctrls/extrusioncontrols.cxx                    |    8 
 svx/source/tbxctrls/extrusioncontrols.hxx                    |    1 
 svx/source/toolbars/extrusionbar.cxx                         |  126 ++-
 svx/uiconfig/ui/surfacewindow.ui                             |   25 
 xmloff/inc/EnhancedCustomShapeToken.hxx                      |    2 
 xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc |binary
 xmloff/qa/unit/draw.cxx                                      |  100 +++
 xmloff/source/core/xmltoken.cxx                              |    1 
 xmloff/source/draw/EnhancedCustomShapeToken.cxx              |    2 
 xmloff/source/draw/shapeexport.cxx                           |   20 
 xmloff/source/draw/ximpcustomshape.cxx                       |   13 
 xmloff/source/token/tokens.txt                               |    1 
 25 files changed, 831 insertions(+), 182 deletions(-)

New commits:
commit 157b027c4cfca2582b1c1bdb66992560084ac008
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Thu Jan 13 13:26:25 2022 +0100
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Thu Feb 17 14:14:01 2022 +0100

    tdf#145700 Improve lighting in extruded custom shapes
    
    The fix tries to make rendering similar to MS Office.
    
    The ODF standard follows closely the extrusion in RTF and MS binary
    format. Rendering uses the 3D scene engine.
    
    The main problem was, that the z-component of the direction was
    interpreted with opposite sign. As result the maximum of a light was at
    false position. Especially a direction from the observer to the object
    has produced a light behind the shape and so looks as if light was off.
    
    The wrong z-direction has produced lighting, which was less intensive
    than in MS Office. To compensate that, a third light source was added
    as workaround. That part is removed.
    
    Second problem was wrong use of 3D-scene D3DMaterialSpecularIntensity
    and D3DMaterialSpecular (= UI Specular color). That was not only wrong
    in OOo but in my previous patch too.
    D3DMaterialSpecularIntensity corresponds to MS property 'c3DShininess'.
    Relationship is Intensity = 2^c3DShininess.
    D3DMaterialSpecular is calculated from MS property c3DSpecularAmt and
    and c3DKeyIntensity. The light source was missing, but needs to be
    included, because c3DSpecularAmt is 'the ratio of incident to specular
    light that is reflected on a shape'.
    The old unit tests are adapted to this change.
    
    MS gives no information how it softens a light in case of harsh=false.
    ODF specifies it as 'implementation-defined'. The patch uses four
    additional lights, which have directions in 60° angle to the original
    light. The light intensity is distributed. That comes near to rendering
    in MS Office. Changing our 3D engine to provide 'soft' lights was not
    doable for me.
    
    The way MS Office renders a 'metal' surface is different from ODF
    specification. To distinguish the kinds, I have introduced a new
    property MetalType. I have discussed it with the ODF TC (see minutes
    from 2022-02-07) and got the advise to use namespaced values.
    Therefore the datatype is not boolean.
    
    The 'Surface' drop-down in the extrusion bar is changed to make the two
    kinds of rendering 'Metal' available to the user.
    
    If a user sets surface 'Metal' in the UI of MS Office, it sets not only
    fc3DMetallic but reduces the value of c3DDiffuseAmt in addition. Our
    3D-scene engine has the corresponding ODF attribute dr3d:diffuse-color
    not implemented. To get a similar rendering I change the material color
    of the 3D-objects as workaround.
    
    Change-Id: Ia986b9c318b4c79688e0c0e2d858215b9d612fdc
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128449
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/filter/source/msfilter/escherex.cxx 
b/filter/source/msfilter/escherex.cxx
index 9ea8ab91a7e0..3f817a72bcb1 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -91,6 +91,7 @@
 #include <sal/log.hxx>
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
 #include <osl/diagnose.h>
 
 #include <algorithm>
@@ -2858,7 +2859,11 @@ void 
EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT
                     {
                         double fExtrusionShininess = 0;
                         if ( rrProp.Value >>= fExtrusionShininess )
-                            AddOpt( DFF_Prop_c3DShininess, 
static_cast<sal_Int32>( fExtrusionShininess * 655.36 ) );
+                        {
+                            // ODF to MS Office conversion invers to 
msdffimp.cxx
+                            fExtrusionShininess = 
basegfx::fround(fExtrusionShininess / 10.0);
+                            AddOpt( DFF_Prop_c3DShininess, 
static_cast<sal_Int32>(fExtrusionShininess) );
+                        }
                     }
                     else if ( rrProp.Name == "Skew" )
                     {
@@ -2875,7 +2880,7 @@ void 
EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT
                     {
                         double fExtrusionSpecularity = 0;
                         if ( rrProp.Value >>= fExtrusionSpecularity )
-                            AddOpt( DFF_Prop_c3DSpecularAmt, 
static_cast<sal_Int32>( fExtrusionSpecularity * 1333 ) );
+                            AddOpt( DFF_Prop_c3DSpecularAmt, 
static_cast<sal_Int32>( fExtrusionSpecularity * 655.36 ) );
                     }
                     else if ( rrProp.Name == "ProjectionMode" )
                     {
diff --git a/filter/source/msfilter/msdffimp.cxx 
b/filter/source/msfilter/msdffimp.cxx
index a0ecad074ac6..76813d38df24 100644
--- a/filter/source/msfilter/msdffimp.cxx
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -149,6 +149,7 @@
 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <com/sun/star/beans/PropertyValues.hpp>
 #include <com/sun/star/beans/XPropertySetInfo.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -1675,14 +1676,20 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
         aExtrusionPropVec.push_back( aProp );
 
         // "Brightness"
+        // MS Office default 0x00004E20 16.16 FixedPoint, 20000/65536=0.30517, 
ODF default 33%.
+        // Thus must set value even if default.
+        double fBrightness = 20000.0;
         if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) )
         {
-            double fBrightness = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DAmbientIntensity, 0 ));
-            fBrightness /= 655.36;
-            aProp.Name = "Brightness";
-            aProp.Value <<= fBrightness;
-            aExtrusionPropVec.push_back( aProp );
+            // Value must be in range 0.0 to 1.0 in MS Office binary 
specification, but larger
+            // values are in fact interpreted.
+            fBrightness = GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 );
         }
+        fBrightness /= 655.36;
+        aProp.Name = "Brightness";
+        aProp.Value <<= fBrightness;
+        aExtrusionPropVec.push_back( aProp );
+
         // "Depth" in 1/100mm
         if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( 
DFF_Prop_c3DExtrudeForward ) )
         {
@@ -1700,14 +1707,17 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
             aExtrusionPropVec.push_back( aProp );
         }
         // "Diffusion"
+        // ODF default is 0%, MS Office default is 100%. Thus must set value 
even if default.
+        double fDiffusion = 100;
         if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) )
         {
-            double fDiffusion = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DDiffuseAmt, 0 ));
+            fDiffusion = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DDiffuseAmt, 0 ));
             fDiffusion /= 655.36;
-            aProp.Name = "Diffusion";
-            aProp.Value <<= fDiffusion;
-            aExtrusionPropVec.push_back( aProp );
         }
+        aProp.Name = "Diffusion";
+        aProp.Value <<= fDiffusion;
+        aExtrusionPropVec.push_back( aProp );
+
         // "NumberOfLineSegments"
         if ( IsProperty( DFF_Prop_c3DTolerance ) )
         {
@@ -1730,24 +1740,35 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
         aProp.Name = "SecondLightHarsh";
         aProp.Value <<= bExtrusionSecondLightHarsh;
         aExtrusionPropVec.push_back( aProp );
+
         // "FirstLightLevel"
+        // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 
0.5798, ODF default 66%.
+        // Thus must set value even if default.
+        double fFirstLightLevel = 38000.0;
         if ( IsProperty( DFF_Prop_c3DKeyIntensity ) )
         {
-            double fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DKeyIntensity, 0 ));
-            fFirstLightLevel /= 655.36;
-            aProp.Name = "FirstLightLevel";
-            aProp.Value <<= fFirstLightLevel;
-            aExtrusionPropVec.push_back( aProp );
+            // value<0 and value>1 are allowed in MS Office. Clamp such in ODF 
export, not here.
+            fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DKeyIntensity, 0 ));
         }
+        fFirstLightLevel /= 655.36;
+        aProp.Name = "FirstLightLevel";
+        aProp.Value <<= fFirstLightLevel;
+        aExtrusionPropVec.push_back( aProp );
+
         // "SecondLightLevel"
+        // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 
0.5798, ODF default 66%.
+        // Thus must set value even if default.
+        double fSecondLightLevel = 38000.0;
         if ( IsProperty( DFF_Prop_c3DFillIntensity ) )
         {
-            double fSecondLightLevel = 
static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 ));
-            fSecondLightLevel /= 655.36;
-            aProp.Name = "SecondLightLevel";
-            aProp.Value <<= fSecondLightLevel;
-            aExtrusionPropVec.push_back( aProp );
+            // value<0 and value>1 are allowed in MS Office. Clamp such in ODF 
export, not here.
+            fSecondLightLevel = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DFillIntensity, 0 ));
         }
+        fSecondLightLevel /= 655.36;
+        aProp.Name = "SecondLightLevel";
+        aProp.Value <<= fSecondLightLevel;
+        aExtrusionPropVec.push_back( aProp );
+
         // "FirstLightDirection"
         if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) 
|| IsProperty( DFF_Prop_c3DKeyZ ) )
         {
@@ -1776,6 +1797,10 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
         aProp.Name = "Metal";
         aProp.Value <<= bExtrusionMetal;
         aExtrusionPropVec.push_back( aProp );
+        aProp.Name = "MetalType";
+        aProp.Value <<= 
css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
+        aExtrusionPropVec.push_back(aProp);
+
         // "ShadeMode"
         if ( IsProperty( DFF_Prop_c3DRenderMode ) )
         {
@@ -1788,7 +1813,7 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
             aProp.Value <<= eExtrusionShadeMode;
             aExtrusionPropVec.push_back( aProp );
         }
-        // "RotateAngle" in Grad
+        // "RotateAngle" in Degree
         if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( 
DFF_Prop_c3DYRotationAngle ) )
         {
             double fAngleX = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0;
@@ -1821,34 +1846,44 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
             }
         }
         // "Shininess"
+        // MS Office default 5, ODF default 50%.
         if ( IsProperty( DFF_Prop_c3DShininess ) )
         {
             double fShininess = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DShininess, 0 ));
-            fShininess /= 655.36;
+            fShininess *= 10.0; // error in [MS ODRAW] (2021), type is not 
FixedPoint but long.
             aProp.Name = "Shininess";
             aProp.Value <<= fShininess;
             aExtrusionPropVec.push_back( aProp );
         }
+
         // "Skew"
+        // MS Office angle file value is 16.16 FixedPoint, default 0xFF790000,
+        // -8847360/65536=-135, ODF default 45. Thus must set value even if 
default.
+        double fSkewAngle = -135.0;
+        // MS Office amount file value is signed integer in range 0xFFFFFF9C 
to 0x00000064,
+        // default 0x00000032, ODF default 50.0
+        double fSkewAmount = 50.0;
         if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( 
DFF_Prop_c3DSkewAngle ) )
         {
-            double fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DSkewAmount, 50 ));
-            double fSkewAngle = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ))) / 
65536.0;
+            fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DSkewAmount, 50 ));
+            fSkewAngle = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ));
+            fSkewAngle /= 65536.0;
+        }
+        EnhancedCustomShapeParameterPair aSkewPair;
+        aSkewPair.First.Value <<= fSkewAmount;
+        aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+        aSkewPair.Second.Value <<= fSkewAngle;
+        aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+        aProp.Name = "Skew";
+        aProp.Value <<= aSkewPair;
+        aExtrusionPropVec.push_back( aProp );
 
-            EnhancedCustomShapeParameterPair aSkewPair;
-            aSkewPair.First.Value <<= fSkewAmount;
-            aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
-            aSkewPair.Second.Value <<= fSkewAngle;
-            aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
-            aProp.Name = "Skew";
-            aProp.Value <<= aSkewPair;
-            aExtrusionPropVec.push_back( aProp );
-        }
         // "Specularity"
+        // Type Fixed point 16.16, percent in API
         if ( IsProperty( DFF_Prop_c3DSpecularAmt ) )
         {
             double fSpecularity = static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DSpecularAmt, 0 ));
-            fSpecularity /= 1333;
+            fSpecularity /= 655.36;
             aProp.Name = "Specularity";
             aProp.Value <<= fSpecularity;
             aExtrusionPropVec.push_back( aProp );
@@ -1860,16 +1895,22 @@ void 
DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxIt
         aExtrusionPropVec.push_back( aProp );
 
         // "ViewPoint" in 1/100mm
+        // MS Office default 1250000 EMU=3472.222 Hmm, ODF default 3.5cm
+        // Thus must set value even if default.
+        double fViewX = 1250000.0 / 360.0;
+        double fViewY = -1250000.0 / 360.0;;
+        double fViewZ = 9000000.0 / 360.0;
         if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( 
DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) )
         {
-            double fViewX = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
-            double fViewY = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
-            double fViewZ = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
-            css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, 
fViewZ );
-            aProp.Name = "ViewPoint";
-            aProp.Value <<= aExtrusionViewPoint;
-            aExtrusionPropVec.push_back( aProp );
+            fViewX = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
+            fViewY = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
+            fViewZ = 
static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( 
DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
         }
+        css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ );
+        aProp.Name = "ViewPoint";
+        aProp.Value <<= aExtrusionViewPoint;
+        aExtrusionPropVec.push_back( aProp );
+
         // "Origin"
         if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( 
DFF_Prop_c3DOriginY ) )
         {
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index c17ffe8af69a..7e278b4cffc3 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -2455,6 +2455,7 @@ namespace xmloff::token {
         XML_EXTRUSION_FIRST_LIGHT_DIRECTION,
         XML_EXTRUSION_SECOND_LIGHT_DIRECTION,
         XML_EXTRUSION_METAL,
+        XML_EXTRUSION_METAL_TYPE,
         XML_EXTRUSION_ROTATION_ANGLE,
         XML_EXTRUSION_ROTATION_CENTER,
         XML_EXTRUSION_SHININESS,
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 2f4240e75e33..28b3a41f280b 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -2295,6 +2295,7 @@ $(eval $(call 
gb_UnoApi_add_idlfiles,offapi,com/sun/star/drawing,\
        EnhancedCustomShapeSegmentCommand \
        EnhancedCustomShapeTextFrame \
        EnhancedCustomShapeTextPathMode \
+    EnhancedCustomShapeMetalType \
        EscapeDirection \
        FillStyle \
        FlagSequence \
diff --git a/offapi/com/sun/star/drawing/EnhancedCustomShapeExtrusion.idl 
b/offapi/com/sun/star/drawing/EnhancedCustomShapeExtrusion.idl
index bfe99f4029fd..4b589c4aa1d8 100644
--- a/offapi/com/sun/star/drawing/EnhancedCustomShapeExtrusion.idl
+++ b/offapi/com/sun/star/drawing/EnhancedCustomShapeExtrusion.idl
@@ -94,11 +94,20 @@ service EnhancedCustomShapeExtrusion
     */
     [optional, property] boolean Metal;
 
+    /** Specifies in case of Metal=true the way the rendering of the shape is 
modified.
+        <p>Note: Currently not usable in ODF strict.</p>
+
+        @see EnhancedCustomShapeMetalType
+
+        @since LibreOffice 7.4
+    */
+    [optional, property] short MetalType;
+
     /** This property defines the shade mode.
     */
     [optional, property] ::com::sun::star::drawing::ShadeMode ShadeMode;
 
-    /** This attributes specifies the rotation angle about the x-axis in grad.
+    /** This attributes specifies the rotation angle about the x-axis in 
degrees.
         The order of rotation is: z-axis, y-axis and then x-axis. The z-axis is
         specified by the draw:rotate-angle.
     */
diff --git a/offapi/com/sun/star/drawing/EnhancedCustomShapeMetalType.idl 
b/offapi/com/sun/star/drawing/EnhancedCustomShapeMetalType.idl
new file mode 100755
index 000000000000..aea502ccd31b
--- /dev/null
+++ b/offapi/com/sun/star/drawing/EnhancedCustomShapeMetalType.idl
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef __com_sun_star_drawing_EnhancedCustomShapeMetalType_idl__
+#define __com_sun_star_drawing_EnhancedCustomShapeMetalType_idl__
+
+
+ module com {  module sun {  module star {  module drawing {
+
+/** These constants define the way the attribute Metal of service
+    EnhancedCustomShapeExtrusion is interpreted for rendering the shape.
+    @since LibreOffice 7.4
+ */
+constants EnhancedCustomShapeMetalType
+{
+    /** The rendering of the shape is modified as specified in the ODF 
standard.
+     */
+     const short MetalODF = 0;
+
+    /** The rendering of the shape is modified to get a similar rendering as 
in Microsoft Office for objects, which have the fc3DMetallic flag in Rich Text 
Format or binary MS Office format set.
+     */
+     const short MetalMSCompatible = 1;
+};
+
+
+}; }; }; };
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
\ No newline at end of file
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index ce941afd1b77..2df8d41c5eb9 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2395,6 +2395,15 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
     </rng:optional>
   </rng:define>
 
+  <!-- https://issues.oasis-open.org/browse/OFFICE-4123 -->
+  <rng:define name="draw-enhanced-geometry-attlist" combine="interleave">
+    <rng:optional>
+      <rng:attribute name="loext:extrusion-metal-type">
+        <rng:ref name="namespacedToken"/>
+      </rng:attribute>
+    </rng:optional>
+  </rng:define>
+
   <!-- TODO no proposal -->
   <rng:define name="draw-custom-shape-attlist" combine="interleave">
     <rng:ref name="common-draw-rel-size-attlist"/>
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
index b420ecebe2e4..081a6b7789e0 100644
--- a/svx/qa/unit/customshapes.cxx
+++ b/svx/qa/unit/customshapes.cxx
@@ -14,16 +14,18 @@
 #include <test/bootstrapfixture.hxx>
 #include <unotest/macros_test.hxx>
 #include <rtl/ustring.hxx>
-#include <editeng/unoprnms.hxx>
 #include <basegfx/polygon/b2dpolypolygon.hxx>
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <basegfx/point/b2dpoint.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <editeng/unoprnms.hxx>
 #include <sfx2/request.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <sfx2/viewsh.hxx>
 #include <svl/intitem.hxx>
 #include <svx/EnhancedCustomShape2d.hxx>
 #include <svx/extrusionbar.hxx>
+#include <svx/graphichelper.hxx>
 #include <svx/svdoashp.hxx>
 #include <svx/svdopath.hxx>
 #include <svx/svdview.hxx>
@@ -31,13 +33,16 @@
 #include <svx/unoapi.hxx>
 #include <unotools/mediadescriptor.hxx>
 #include <unotools/tempfile.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/BitmapReadAccess.hxx>
 
 #include <cppunit/TestAssert.h>
 
+#include <com/sun/star/awt/Rectangle.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
 #include <com/sun/star/drawing/XDrawPage.hpp>
-#include <com/sun/star/awt/Rectangle.hpp>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
 
@@ -127,6 +132,106 @@ void lcl_AssertRectEqualWithTolerance(std::string_view 
sInfo, const tools::Recta
                            std::abs(rExpected.GetHeight() - 
rActual.GetHeight()) <= nTolerance);
 }
 
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_NonUI)
+{
+    // The document contains first light soft, no ambient color, no second 
light and shininess 6.
+    // Such settings are not available in the UI. It tests the actual color, 
not the geometry.
+    // Load document
+    OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + 
"tdf145700_3D_NonUI.doc";
+    mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+    // Generate bitmap from shape
+    uno::Reference<drawing::XShape> xShape = getShape(0);
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", 
aTempFile.GetURL());
+
+    // Read bitmap and test color
+    // The expected values are taken from an image generated by Word
+    // Without the changed methods the colors were in range RGB(17,11,17) to 
RGB(87,55,89).
+    SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+    vcl::PngImageReader aPNGReader(aFileStream);
+    BitmapEx aBMPEx = aPNGReader.read();
+    Bitmap aBMP = aBMPEx.GetBitmap();
+    Bitmap::ScopedReadAccess pRead(aBMP);
+    Size aSize = aBMP.GetSizePixel();
+    // GetColor(Y,X)
+    Color aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 
0.125);
+    Color aExpectedColor(107, 67, 109);
+    sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+    // The current solution for soft light still can be improved. 
nColorDistance is high.
+    aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.45);
+    aExpectedColor = Color(179, 113, 183);
+    nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(54), nColorDistance);
+    // This point tests whether shininess is read and used. With default 
shininess it would be white.
+    aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.72);
+    aExpectedColor = Color(255, 231, 255);
+    nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(14), nColorDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_FrontLightDim)
+{
+    // This tests the actual color, not the geometry.
+    // Load document
+    OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + 
"tdf145700_3D_FrontLightDim.doc";
+    mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+    // Generate bitmap from shape
+    uno::Reference<drawing::XShape> xShape = getShape(0);
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", 
aTempFile.GetURL());
+
+    // Read bitmap and test color
+    // The expected values are taken from an image generated by Word
+    // Without the changed methods the nColorDistance was 476 and 173 
respecitively.
+    SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+    vcl::PngImageReader aPNGReader(aFileStream);
+    BitmapEx aBMPEx = aPNGReader.read();
+    Bitmap aBMP = aBMPEx.GetBitmap();
+    Bitmap::ScopedReadAccess pRead(aBMP);
+    Size aSize = aBMP.GetSizePixel();
+    // GetColor(Y,X)
+    Color aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 
0.4);
+    Color aExpectedColor(240, 224, 229);
+    sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(9), nColorDistance);
+    aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.9);
+    aExpectedColor = Color(96, 90, 92);
+    nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_FirstLightHarsh)
+{
+    // Load document
+    OUString aURL
+        = m_directories.getURLFromSrc(sDataDirectory) + 
"tdf145700_3D_FirstLightHarsh.doc";
+    mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+    // Generate bitmap from shape
+    uno::Reference<drawing::XShape> xShape = getShape(0);
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", 
aTempFile.GetURL());
+
+    // Read bitmap and test color in center
+    SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+    vcl::PngImageReader aPNGReader(aFileStream);
+    BitmapEx aBMPEx = aPNGReader.read();
+    Bitmap aBMP = aBMPEx.GetBitmap();
+    Bitmap::ScopedReadAccess pRead(aBMP);
+    Size aSize = aBMP.GetSizePixel();
+    // GetColor(Y,X)
+    const Color aActualColor = pRead->GetColor(aSize.Height() / 2, 
aSize.Width() / 2);
+    const Color aExpectedColor(211, 247, 255); // from image generated by Word
+    sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+    CPPUNIT_ASSERT_LESS(sal_uInt16(3), nColorDistance);
+}
+
 CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145956_Origin_Relative_BoundRect)
 {
     // The ViewPoint is relative to point Origin. The coordinates of point 
Origin are fractions of
diff --git a/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc 
b/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc
new file mode 100644
index 000000000000..28b8b018d4e6
Binary files /dev/null and b/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc 
differ
diff --git a/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc 
b/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc
new file mode 100644
index 000000000000..5849e3eac6ba
Binary files /dev/null and b/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc 
differ
diff --git a/svx/qa/unit/data/tdf145700_3D_NonUI.doc 
b/svx/qa/unit/data/tdf145700_3D_NonUI.doc
new file mode 100644
index 000000000000..d62d57cf02cc
Binary files /dev/null and b/svx/qa/unit/data/tdf145700_3D_NonUI.doc differ
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
index cab6b56b0ae7..275f75507d64 100644
--- a/svx/qa/unit/svdraw.cxx
+++ b/svx/qa/unit/svdraw.cxx
@@ -398,8 +398,9 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testFontWorks)
     assertXPath(pXmlDoc, "//scene", "projectionMode", "Perspective");
     assertXPath(pXmlDoc, "//scene/extrude3D[1]/fill", "color", "#ff0000");
     assertXPath(pXmlDoc, "//scene/extrude3D[1]/object3Dattributes/material", 
"color", "#ff0000");
+    // ODF default 50% is repesented by Specular Intensity = 2^5. The 
relationship is not linear.
     assertXPath(pXmlDoc, "//scene/extrude3D[1]/object3Dattributes/material", 
"specularIntensity",
-                "20");
+                "32");
 }
 
 CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMetal)
@@ -411,12 +412,12 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMetal)
 
     xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
 
-    // ODF specifies specular color as rgb(200,200,200) and adding 15 to 
specularity for metal=true
-    // without patch the specular color was #ffffff
-    assertXPath(pXmlDoc, "(//material)[1]", "specular", "#c8c8c8");
-    // specularIntensity = 100 - (80 + 15), with nominal value 80 in the file
-    // without patch specularIntensity was 15
-    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "5");
+    // ODF specifies for metal = true specular color as rgb(200,200,200) and 
adding 15 to specularity
+    // Together with extrusion-first-light-level 67% and extrusion-specularity 
80% factor is
+    // 0.67*0.8 * 200/255 = 0.42 and color #6b6b6b
+    assertXPath(pXmlDoc, "(//material)[1]", "specular", "#6b6b6b");
+    // 3D specularIntensity = 2^(50/10) + 15 = 47, with default 
extrusion-shininess 50%
+    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "47");
 }
 
 CPPUNIT_TEST_FIXTURE(SvdrawTest, testExtrusionPhong)
@@ -442,16 +443,20 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMattePPT)
 
     xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
 
-    // The preset 'matte' in the PPT user interface sets the specularity of 
material to 0. To get the
-    // same effect in LO, specular of the lights need to be false in addition. 
Without patch the
-    // lights 1, 2, 3 are used, with patch lights 2, 3, 4. Thereby light 4 has 
the same color and
-    // direction as light 1, but without being specular. The dump has in both 
cases three lights, but
-    // without number. So we test as ersatz, that the third of them has the 
color of light 1. Being
-    // not light 1, it is never specular in LO, so no need to test.
-    // 'color' was "#464646" without patch.
-    assertXPath(pXmlDoc, "(//light)[3]", "color", "#aaaaaa");
-    // 'specularIntensity' was "15" without patch. specularIntensity = 100 - 
specularity of material.
-    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "100");
+    // The preset 'matte' sets the specularity of material to 0. But that 
alone does not make the
+    // rendering 'matte' in LO. To get a 'matte' effect in LO, specularity of 
the light need to be
+    // false in addition. To get this, first light is set off and values from 
first light are copied
+    // to forth light, as only first light is specular. Because first and 
third lights are off, the
+    // forth light is the second one in the dump. The gray color corresponding 
to
+    // FirstLightLevel = 38000/2^16 is #949494.
+    assertXPath(pXmlDoc, "(//material)[1]", "specular", "#000000");
+    assertXPath(pXmlDoc, "(//light)[2]", "color", "#949494");
+    // To make the second light soft, part of its intensity is moved to lights 
5,6,7 and 8.
+    assertXPath(pXmlDoc, "(//light)[1]", "color", "#1e1e1e");
+    assertXPath(pXmlDoc, "(//light)[3]", "color", "#3b3b3b");
+    // The 3D property specularIntensity is not related to 
'extrusion-specularity' but to
+    // 'extrusion-shininess'. specularIntensity = 2^(shininess/10), here 
default 32.
+    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "32");
 }
 
 CPPUNIT_TEST_FIXTURE(SvdrawTest, testMaterialSpecular)
@@ -465,10 +470,17 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testMaterialSpecular)
     xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
     CPPUNIT_ASSERT(pXmlDoc);
 
-    // The material property 'draw:extrusion-specularity' was not applied to 
the object but to the
-    // scene. Without patch the object has always a default value 15 of 
specularIntensity. The file
-    // has specularity=77%. It should be specularIntensity = 100-77=23 with 
patch.
-    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "23");
+    // 3D specular color is derived from properties 'extrusion-specularity' 
and 'extrusion-first-light
+    // -level'. 3D specularIntensity is dervied from property 
'draw:extrusion-shininess'. Both are
+    // object properties, not scene properties. Those were wrong in various 
forms before the patch.
+    // Specularity = 77% * first-light-level 67% = 0.5159, which corresponds 
to gray color #848484.
+    assertXPath(pXmlDoc, "(//material)[1]", "specular", "#848484");
+    // extrusion-shinines 50% corresponds to 3D specularIntensity 32, use 
2^(50/10).
+    assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "32");
+    // extrusion-first-light-level 67% corresponds to gray color #ababab, use 
255 * 0.67.
+    assertXPath(pXmlDoc, "(//light)[1]", "color", "#ababab");
+    // The first light is harsh, the second light soft. So the 3D scene should 
have 6 lights (1+1+4).
+    assertXPath(pXmlDoc, "//light", 6);
 }
 }
 
diff --git a/svx/source/customshapes/EnhancedCustomShape3d.cxx 
b/svx/source/customshapes/EnhancedCustomShape3d.cxx
index c967261cfd22..0d8078fe6bd3 100644
--- a/svx/source/customshapes/EnhancedCustomShape3d.cxx
+++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx
@@ -45,6 +45,7 @@
 #include <com/sun/star/drawing/ShadeMode.hpp>
 #include <svx/sdr/properties/properties.hxx>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/range/b2drange.hxx>
 #include <sdr/primitive2d/sdrattributecreator.hxx>
@@ -53,6 +54,7 @@
 #include <svx/xlnwtit.hxx>
 #include <svx/xlntrit.hxx>
 #include <svx/xfltrit.hxx>
+#include <basegfx/color/bcolor.hxx>
 
 using namespace com::sun::star;
 using namespace com::sun::star::uno;
@@ -90,6 +92,9 @@ void GetSkew( const SdrCustomShapeGeometryItem& rItem, 
double& rSkewAmount, doub
     if ( ! ( pAny && ( *pAny >>= aSkewParaPair ) && ( 
aSkewParaPair.First.Value >>= rSkewAmount ) && ( aSkewParaPair.Second.Value >>= 
rSkewAngle ) ) )
     {
         rSkewAmount = 50;
+        // ODF default is 45, but older ODF documents expect -135 as default. 
For intermediate
+        // solution see tdf#141301 and tdf#141127.
+        // MS Office default -135 is set in msdffimp.cxx to make import 
independent from setting here.
         rSkewAngle = -135;
     }
     rSkewAngle = basegfx::deg2rad(rSkewAngle);
@@ -170,6 +175,56 @@ drawing::Direction3D GetDirection3D( const 
SdrCustomShapeGeometryItem& rItem, co
     return aRetValue;
 }
 
+sal_Int16 GetMetalType(const SdrCustomShapeGeometryItem& rItem, const 
sal_Int16 eDefault)
+{
+    sal_Int16 aRetValue(eDefault);
+    const Any* pAny = rItem.GetPropertyValueByName("Extrusion", "MetalType");
+    if (pAny)
+        *pAny >>= aRetValue;
+    return aRetValue;
+}
+
+// Calculates the light directions for the additional lights, which are used 
to emulate soft
+// lights of MS Office. Method needs to be documented in the Wiki
+// https://wiki.documentfoundation.org/Development/ODF_Implementer_Notes in 
part
+// List_of_LibreOffice_ODF_implementation-defined_items
+// The method expects vector rLight to be normalized and results normalized 
vectors.
+void lcl_SoftLightsDirection(const basegfx::B3DVector& rLight, 
basegfx::B3DVector& rSoftUp,
+                             basegfx::B3DVector& rSoftDown, 
basegfx::B3DVector& rSoftRight,
+                             basegfx::B3DVector& rSoftLeft)
+{
+    constexpr double fAngle = basegfx::deg2rad(60); // angle between regular 
light and soft light
+
+    // We first create directions around (0|0|1) and then rotate them to the 
light position.
+    rSoftUp = basegfx::B3DVector(0.0, sin(fAngle), cos(fAngle));
+    rSoftDown = basegfx::B3DVector(0.0, -sin(fAngle), cos(fAngle));
+    rSoftRight = basegfx::B3DVector(sin(fAngle), 0.0, cos(fAngle));
+    rSoftLeft = basegfx::B3DVector(-sin(fAngle), 0.0, cos(fAngle));
+
+    basegfx::B3DHomMatrix aRotateMat;
+    aRotateMat.rotate(0.0, 0.0, M_PI_4);
+    if (rLight.getX() == 0.0 && rLight.getZ() == 0.0)
+    {
+        // Special case with light from top or bottom
+        if (rLight.getY() >= 0.0)
+            aRotateMat.rotate(-M_PI_2, 0.0, 0.0);
+        else
+            aRotateMat.rotate(M_PI_2, 0.0, 0.0);
+    }
+    else
+    {
+        // Azimuth from z-axis to x-axis. (0|0|1) to (1|0|0) is 90deg.
+        double fAzimuth = atan2(rLight.getX(), rLight.getZ());
+        // Elevation from xz-plane to y-axis. (0|0|1) to (0|1|0) is 90deg.
+        double fElevation = atan2(rLight.getY(), std::hypot(rLight.getX(), 
rLight.getZ()));
+        aRotateMat.rotate(-fElevation, fAzimuth, 0.0);
+    }
+
+    rSoftUp = aRotateMat * rSoftUp;
+    rSoftDown = aRotateMat * rSoftDown;
+    rSoftRight = aRotateMat * rSoftRight;
+    rSoftLeft = aRotateMat * rSoftLeft;
+}
 }
 
 SdrObject* EnhancedCustomShape3d::Create3DObject(
@@ -256,7 +311,7 @@ SdrObject* EnhancedCustomShape3d::Create3DObject(
         pScene->GetProperties().SetObjectItem( 
Svx3DShadeModeItem(static_cast<sal_uInt16>(eShadeMode)));
         aSet.Put( makeSvx3DPercentDiagonalItem( 0 ) );
         aSet.Put( Svx3DTextureModeItem( 1 ) );
-         // SPECIFIC needed for ShadeMode_SMOOTH and ShadeMode_PHONG, 
otherwise FLAT is faster
+        // SPECIFIC needed for ShadeMode_SMOOTH and ShadeMode_PHONG, otherwise 
FLAT is faster.
         if (eShadeMode == drawing::ShadeMode_SMOOTH || eShadeMode == 
drawing::ShadeMode_PHONG)
             aSet.Put( 
Svx3DNormalsKindItem(static_cast<sal_uInt16>(drawing::NormalsKind_SPECIFIC)));
         else
@@ -703,105 +758,259 @@ SdrObject* EnhancedCustomShape3d::Create3DObject(
             pScene->SetLogicRect(a2DProjectionResult.GetBoundRect());
 
 
-            // light
-
-
-            drawing::Direction3D aFirstLightDirectionDefault( 50000, 0, 10000 
);
-            drawing::Direction3D aFirstLightDirection( GetDirection3D( 
rGeometryItem, "FirstLightDirection", aFirstLightDirectionDefault ) );
-            if ( aFirstLightDirection.DirectionZ == 0.0 )
-                aFirstLightDirection.DirectionZ = 1.0;
-
-            double fLightIntensity = GetDouble( rGeometryItem, 
"FirstLightLevel", 43712.0 / 655.36 ) / 100.0;
+            // light and material
 
-            bool bFirstLightHarsh = GetBool( rGeometryItem, "FirstLightHarsh", 
true );
+            // "LightFace" has nothing corresponding in 3D rendering engine.
+            /* bool bLightFace = */ GetBool(rGeometryItem, "LightFace", true); 
// default in ODF
 
-            drawing::Direction3D aSecondLightDirectionDefault( -50000, 0, 
10000 );
-            drawing::Direction3D aSecondLightDirection( GetDirection3D( 
rGeometryItem, "SecondLightDirection", aSecondLightDirectionDefault ) );
-            if ( aSecondLightDirection.DirectionZ == 0.0 )
-                aSecondLightDirection.DirectionZ = -1;
+            // Light directions
 
-            double fLight2Intensity = GetDouble( rGeometryItem, 
"SecondLightLevel", 43712.0 / 655.36 ) / 100.0;
+            drawing::Direction3D aFirstLightDirectionDefault(50000.0, 0.0, 
10000.0);
+            drawing::Direction3D aFirstLightDirection(GetDirection3D( 
rGeometryItem, "FirstLightDirection", aFirstLightDirectionDefault));
+            if (aFirstLightDirection.DirectionX == 0.0 && 
aFirstLightDirection.DirectionY == 0.0
+                && aFirstLightDirection.DirectionZ == 0.0)
+                aFirstLightDirection.DirectionZ = 1.0;
+            basegfx::B3DVector aLight1Vector(aFirstLightDirection.DirectionX, 
-aFirstLightDirection.DirectionY, aFirstLightDirection.DirectionZ);
+            aLight1Vector.normalize();
+
+            drawing::Direction3D aSecondLightDirectionDefault(-50000.0, 0.0, 
10000.0);
+            drawing::Direction3D aSecondLightDirection(GetDirection3D( 
rGeometryItem, "SecondLightDirection", aSecondLightDirectionDefault));
+            if (aSecondLightDirection.DirectionX == 0.0 && 
aSecondLightDirection.DirectionY == 0.0
+                && aSecondLightDirection.DirectionZ == 0.0)
+                aSecondLightDirection.DirectionZ = 1.0;
+            basegfx::B3DVector aLight2Vector(aSecondLightDirection.DirectionX, 
-aSecondLightDirection.DirectionY, aSecondLightDirection.DirectionZ);
+            aLight2Vector.normalize();
+
+            // Light Intensity
+
+            // For "FirstLight" the 3D-Scene light "1" is regulary used. In 
case of surface "Matte"
+            // the light 4 is used instead. For "SecondLight" the 3D-Scene 
light "2" is regulary used.
+            // In case first or second light is not harsh, the lights 5 to 8 
are used in addition
+            // to get a soft light appearance.
+            // The 3D-Scene light "3" is currently not used.
+
+            // ODF default 66%. MS Office default 38000/65536=0.579 is set in 
import filter.
+            double fLight1Intensity = GetDouble(rGeometryItem, 
"FirstLightLevel", 66) / 100.0;
+            // ODF and MS Office have both default 'true'.
+            bool bFirstLightHarsh = GetBool(rGeometryItem, "FirstLightHarsh", 
true);
+            // ODF default 66%. MS Office default 38000/65536=0.579 is set in 
import filter
+            double fLight2Intensity = GetDouble(rGeometryItem, 
"SecondLightLevel", 66) / 100.0;
+            // ODF has default 'true'. MS Office default 'false' is set in 
import.
+            bool bSecondLightHarsh = GetBool(rGeometryItem, 
"SecondLightHarsh", true);
+
+            // ODF default 33%. MS Office default 20000/65536=0.305 is set in 
import filter.
+            double fAmbientIntensity = GetDouble(rGeometryItem, "Brightness", 
33) / 100.0;
+
+            double fLight1IntensityForSpecular(fLight1Intensity); // remember 
original value
+            if (!bFirstLightHarsh || !bSecondLightHarsh) // might need softing 
lights
+            {
+                bool bNeedSoftLights(false); // catch case of lights with zero 
intensity.
+                basegfx::B3DVector aLight5Vector;
+                basegfx::B3DVector aLight6Vector;
+                basegfx::B3DVector aLight7Vector;
+                basegfx::B3DVector aLight8Vector;
+                // The needed light intensities depend on the angle between 
regular light and
+                // additional lights, currently for 60deg.
+                Color aHoriSoftLightColor;
+                Color aVertSoftLightColor;
+
+                if (!bSecondLightHarsh && fLight2Intensity > 0.0
+                    && (bFirstLightHarsh || fLight1Intensity == 0.0)) // only 
second light soft
+                {
+                    // That is default for shapes generated in the UI, for LO 
and MS Office as well.
+                    bNeedSoftLights = true;
+                    double fLight2SoftIntensity = fLight2Intensity * 0.40;
+                    aHoriSoftLightColor = 
Color(basegfx::BColor(fLight2SoftIntensity).clamp());
+                    aVertSoftLightColor = aHoriSoftLightColor;
+                    fLight2Intensity *= 0.2;
+
+                    lcl_SoftLightsDirection(aLight2Vector, aLight5Vector, 
aLight6Vector,
+                                            aLight7Vector, aLight8Vector);
+                }
+                else if (!bFirstLightHarsh && fLight1Intensity > 0.0
+                         && (bSecondLightHarsh || fLight2Intensity == 0.0)) // 
only first light soft
+                {
+                    bNeedSoftLights = true;
+                    double fLight1SoftIntensity = fLight1Intensity * 0.40;
+                    aHoriSoftLightColor = 
Color(basegfx::BColor(fLight1SoftIntensity).clamp());
+                    aVertSoftLightColor = aHoriSoftLightColor;
+                    fLight1Intensity *= 0.2;
+
+                    lcl_SoftLightsDirection(aLight1Vector, aLight5Vector, 
aLight6Vector,
+                                            aLight7Vector, aLight8Vector);
+                }
+                else if (!bFirstLightHarsh && fLight1Intensity > 0.0 && 
!bSecondLightHarsh
+                         && fLight2Intensity > 0.0) // both lights soft
+                {
+                    bNeedSoftLights = true;
+                    // We do not hat enough lights. We use two soft lights for 
FirstLight and two for
+                    // SecondLight and double intensity.
+                    double fLight1SoftIntensity = fLight1Intensity * 0.8;
+                    fLight1Intensity *= 0.4;
+                    aHoriSoftLightColor = 
Color(basegfx::BColor(fLight1SoftIntensity).clamp());
+                    basegfx::B3DVector aDummy1, aDummy2;
+                    lcl_SoftLightsDirection(aLight1Vector, aDummy1, aDummy2, 
aLight7Vector,
+                                            aLight8Vector);
+
+                    double fLight2SoftIntensity = fLight2Intensity * 0.8;
+                    aVertSoftLightColor = 
Color(basegfx::BColor(fLight2SoftIntensity).clamp());
+                    fLight2Intensity *= 0.4;
+                    lcl_SoftLightsDirection(aLight2Vector, aLight5Vector, 
aLight6Vector, aDummy1,
+                                            aDummy2);
+                }
 
-            /* sal_Bool bLight2Harsh = */ GetBool( rGeometryItem, 
"SecondLightHarsh", false );
-            /* sal_Bool bLightFace = */ GetBool( rGeometryItem, "LightFace", 
false );
+                if (bNeedSoftLights)
+                {
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightDirection5Item(aLight5Vector));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightcolor5Item(aVertSoftLightColor));
+                    
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff5Item(true));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightDirection6Item(aLight6Vector));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightcolor6Item(aVertSoftLightColor));
+                    
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff6Item(true));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightDirection7Item(aLight7Vector));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightcolor7Item(aHoriSoftLightColor));
+                    
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff7Item(true));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightDirection8Item(aLight8Vector));
+                    pScene->GetProperties().SetObjectItem(
+                        makeSvx3DLightcolor8Item(aHoriSoftLightColor));
+                    
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff8Item(true));
+                }
+            }
 
-            double fAmbientIntensity = GetDouble( rGeometryItem, "Brightness", 
22178.0 / 655.36 ) / 100.0;
-            bool bMetal = GetBool( rGeometryItem, "Metal", false );
+            // ToDo: MSO seems to add half of the surplus to ambient color. 
ODF restricts value to <1.
+            if (fLight1Intensity > 1.0)
+            {
+                fAmbientIntensity += (fLight1Intensity - 1.0) / 2.0;
+            }
 
-            // Currently needed for import from binary MS Office.
-            // ToDo: Create a solution in the filters.
-            // MS Office adds black to diffuse and ambient color in case of 
metal. Use an
-            // approximating ersatz.
-            if (bMetal)
+            // ToDo: How to handle fAmbientIntensity larger 1.0 ? Perhaps 
lighten object color?
+
+            // Now set the regulary 3D-scene light attributes.
+            Color aAmbientColor(basegfx::BColor(fAmbientIntensity).clamp());
+            
pScene->GetProperties().SetObjectItem(makeSvx3DAmbientcolorItem(aAmbientColor));
+
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection1Item(aLight1Vector));
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff1Item(fLight1Intensity 
> 0.0));
+            Color aLight1Color(basegfx::BColor(fLight1Intensity).clamp());
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor1Item(aLight1Color));
+
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection2Item(aLight2Vector));
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff2Item(fLight2Intensity 
> 0.0));
+            Color aLight2Color(basegfx::BColor(fLight2Intensity).clamp());
+            
pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor2Item(aLight2Color));
+
+            // Object reactions on light
+            // Diffusion, Specular-Color and -Intensity are object properties, 
not scene properties.
+            // Surface flag "Metal" is an object property too.
+
+            // Property "Diffusion" would correspond to style attribute 
"drd3:diffuse-color".
+            // But that is not implemented. We cannot ignore the attribute 
because MS Office sets
+            // attribute c3DDiffuseAmt to 43712 (Type Fixed 16.16, approx 
66,9%) instead of MSO
+            // default 65536 (100%), if the user sets surface 'Metal' in the 
UI of MS Office.
+            // We will change the material color of the 3D object as ersatz.
+            // ODF data type is percent with default 0%. MSO default is set in 
import filter.
+            double fDiffusion = GetDouble(rGeometryItem, "Diffusion", 0.0) / 
100.0;
+
+            // ODF standard specifies for value true: "the specular color for 
the shading of an
+            // extruded shape is gray (red, green and blue values of 200) 
instead of white and 15% is
+            // added to the specularity."
+            // Neither 'specularity' nor 'specular color' is clearly defined 
in the standard. ODF term
+            // 'specularity' seems to correspond to UI field 'Specular 
Intensity' for 3D scenes.
+            // MS Office uses current material color in case 'Metal' is set. 
To detect, whether
+            // rendering similar to MS Office has to be used the property 
'MetalType' is used. It is
+            // set on import and in the extrusion bar.
+            bool bMetal = GetBool(rGeometryItem, "Metal", false);
+            sal_Int16 eMetalType(
+                GetMetalType(rGeometryItem, 
drawing::EnhancedCustomShapeMetalType::MetalODF));
+            bool bMetalMSCompatible
+                = eMetalType == 
drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
+
+            // Property "Specularity" corresponds to 3D object style attribute 
dr3d:specular-color.
+            double fSpecularity = GetDouble(rGeometryItem, "Specularity", 0) / 
100.0;
+
+            if (bMetal && !bMetalMSCompatible)
             {
-                fAmbientIntensity -= 0.15; // Estimated value. Adapt it if 
necessary.
-                fAmbientIntensity = std::clamp(fAmbientIntensity, 0.0, 1.0);
-                fLight2Intensity -= 0.15;
-                fLight2Intensity = std::clamp(fLight2Intensity, 0.0, 1.0);
+                fSpecularity *= 200.0 / 255.0;
             }
 
-            sal_uInt16 nAmbientColor = static_cast<sal_uInt16>( 
fAmbientIntensity * 255.0 );
-            if ( nAmbientColor > 255 )
-                nAmbientColor = 255;
-            Color aGlobalAmbientColor( static_cast<sal_uInt8>(nAmbientColor), 
static_cast<sal_uInt8>(nAmbientColor), static_cast<sal_uInt8>(nAmbientColor) );
-            pScene->GetProperties().SetObjectItem( makeSvx3DAmbientcolorItem( 
aGlobalAmbientColor ) );
-
-            sal_uInt8 nSpotLight1 = static_cast<sal_uInt8>( fLightIntensity * 
255.0 );
-            basegfx::B3DVector aSpotLight1( aFirstLightDirection.DirectionX, - 
( aFirstLightDirection.DirectionY ), -( aFirstLightDirection.DirectionZ ) );
-            aSpotLight1.normalize();
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff1Item( 
true ) );
-            Color aAmbientSpot1Color( nSpotLight1, nSpotLight1, nSpotLight1 );
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor1Item( 
aAmbientSpot1Color ) );
-            pScene->GetProperties().SetObjectItem( 
makeSvx3DLightDirection1Item( aSpotLight1 ) );
-
-            sal_uInt8 nSpotLight2 = static_cast<sal_uInt8>( fLight2Intensity * 
255.0 );
-            basegfx::B3DVector aSpotLight2( aSecondLightDirection.DirectionX, 
-aSecondLightDirection.DirectionY, -aSecondLightDirection.DirectionZ );
-            aSpotLight2.normalize();
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff2Item( 
true ) );
-            Color aAmbientSpot2Color( nSpotLight2, nSpotLight2, nSpotLight2 );
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor2Item( 
aAmbientSpot2Color ) );
-            pScene->GetProperties().SetObjectItem( 
makeSvx3DLightDirection2Item( aSpotLight2 ) );
-
-            // Currently needed for import from binary MS Office.
-            // ToDo: Create a solution in the filters.
-            // Binary MS Office creates brighter shapes than our 3D engine 
with same values.
-            sal_uInt8 nSpotLight3 = 70;
-            basegfx::B3DVector aSpotLight3( 0.0, 0.0, 1.0 );
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff3Item( 
true ) );
-            Color aAmbientSpot3Color( nSpotLight3, nSpotLight3, nSpotLight3 );
-            pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor3Item( 
aAmbientSpot3Color ) );
-            pScene->GetProperties().SetObjectItem( 
makeSvx3DLightDirection3Item( aSpotLight3 ) );
-
-            double fSpecular = GetDouble( rGeometryItem, "Specularity", 0 );
-            // ODF specifies 'white', OOXML uses shape fill color in some 
presets
-            Color aSpecularCol(255, 255, 255);
-            if ( bMetal )
+            // MS Office seems to render as if 'Specular Color' = Specularity 
* Light1Intensity.
+            double fShadingFactor = fLight1IntensityForSpecular * fSpecularity;
+            Color aSpecularCol(basegfx::BColor(fShadingFactor).clamp());
+            // In case of bMetalMSCompatible the color will be recalculated in 
the below loop.
+
+            // Shininess ODF default 50 (unit %). MS Office default 5, import 
filter makes *10.
+            // Shininess corresponds to "Specular Intensity" with the 
nonlinear relationship
+            // "Specular Intensity" = 2^c3DShininess = 2^("Shininess" / 10)
+            double fShininess = GetDouble(rGeometryItem, "Shininess", 50) / 
10.0;
+            fShininess = std::clamp<double>(pow(2, fShininess), 0.0, 100.0);
+            sal_uInt16 nIntensity = 
static_cast<sal_uInt16>(basegfx::fround(fShininess));
+            if (bMetal && !bMetalMSCompatible)
             {
-                // values as specified in ODF
-                aSpecularCol = Color( 200, 200, 200 );
-                fSpecular += 15.0;
+                nIntensity += 15; // as specified in ODF
+                nIntensity = std::clamp<sal_uInt16>(nIntensity, 0, 100);
             }
-            sal_Int32 nIntensity = 100 - static_cast<sal_Int32>(fSpecular);
-            nIntensity = std::clamp<sal_Int32>(nIntensity, 0, 100);
 
-            // specularity is an object property, not a scene property
-            SdrObjListIter aSceneIter( *pScene, SdrIterMode::DeepNoGroups );
+            SdrObjListIter aSceneIter(*pScene, SdrIterMode::DeepNoGroups);
             while (aSceneIter.IsMore())
             {
                 const SdrObject* pNext = aSceneIter.Next();
+
+                // Change material color as ersatz for missing style attribute 
"drd3:diffuse-color".
+                // For this ersatz we exclude case fDiffusion == 0.0, because 
for older documents this
+                // attribute is not written out to draw:extrusion-diffusion 
and ODF default 0 would
+                // produce black objects.
+                const Color& rMatColor
+                    = 
pNext->GetProperties().GetItem(XATTR_FILLCOLOR).GetColorValue();
+                Color aOldMatColor(rMatColor);
+                if (basegfx::fTools::more(fDiffusion, 0.0)
+                    && !basegfx::fTools::equal(fDiffusion, 1.0))
+                {
+                    // Occurs e.g. with MS surface preset 'Metal'.
+                    sal_uInt16 nHue;
+                    sal_uInt16 nSaturation;
+                    sal_uInt16 nBrightness;
+                    rMatColor.RGBtoHSB(nHue, nSaturation, nBrightness);
+                    nBrightness
+                        = 
static_cast<sal_uInt16>(static_cast<double>(nBrightness) * fDiffusion);
+                    nBrightness = std::clamp<sal_uInt16>(nBrightness, 0, 100);
+                    Color aNewMatColor = Color::HSBtoRGB(nHue, nSaturation, 
nBrightness);
+                    pNext->GetProperties().SetObjectItem(XFillColorItem("", 
aNewMatColor));
+                }
+
+                // Using material color instead of gray in case of MS Office 
compatible rendering.
+                if (bMetal && bMetalMSCompatible)
+                {
+                    sal_uInt16 nHue;
+                    sal_uInt16 nSaturation;
+                    sal_uInt16 nBrightness;
+                    aOldMatColor.RGBtoHSB(nHue, nSaturation, nBrightness);
+                    nBrightness = 
static_cast<sal_uInt16>(static_cast<double>(nBrightness)
+                                                          * fShadingFactor);
+                    nBrightness = std::clamp<sal_uInt16>(nBrightness, 0, 100);
+                    aSpecularCol = Color::HSBtoRGB(nHue, nSaturation, 
nBrightness);
+                }
+
                 
pNext->GetProperties().SetObjectItem(makeSvx3DMaterialSpecularItem(aSpecularCol));
-                
pNext->GetProperties().SetObjectItem(makeSvx3DMaterialSpecularIntensityItem(static_cast<sal_uInt16>(nIntensity)));
+                pNext->GetProperties().SetObjectItem(
+                    makeSvx3DMaterialSpecularIntensityItem(nIntensity));
             }
 
-            // fSpecular = 0 is used to indicate surface preset "matte".
-            if (!bFirstLightHarsh || basegfx::fTools::equalZero(fSpecular, 
0.0001))
+            // fSpecularity = 0 is used to indicate surface preset "Matte".
+            if (basegfx::fTools::equalZero(fSpecularity))
             {
                 // First light in LO 3D engine is always specular, all other 
lights are never specular.
                 // We copy light1 values to light4 and use it instead of 
light1 in the 3D scene.
                 
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff1Item(false));
                 
pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff4Item(true));
-                
pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor4Item(aAmbientSpot1Color));
-                
pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection4Item(aSpotLight1));
+                
pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor4Item(aLight1Color));
+                
pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection4Item(aLight1Vector));
             }
 
             // removing placeholder objects
diff --git a/svx/source/tbxctrls/extrusioncontrols.cxx 
b/svx/source/tbxctrls/extrusioncontrols.cxx
index c54004b24cec..b0d8a1238610 100644
--- a/svx/source/tbxctrls/extrusioncontrols.cxx
+++ b/svx/source/tbxctrls/extrusioncontrols.cxx
@@ -829,11 +829,13 @@ 
ExtrusionSurfaceWindow::ExtrusionSurfaceWindow(svt::PopupWindowController* pCont
     , mxMatt(m_xBuilder->weld_radio_button("matt"))
     , mxPlastic(m_xBuilder->weld_radio_button("plastic"))
     , mxMetal(m_xBuilder->weld_radio_button("metal"))
+    , mxMetalMSO(m_xBuilder->weld_radio_button("metalMSO"))
 {
     mxWireFrame->connect_toggled(LINK(this, ExtrusionSurfaceWindow, 
SelectHdl));
     mxMatt->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
     mxPlastic->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
     mxMetal->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+    mxMetalMSO->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
 
     AddStatusListener( g_sExtrusionSurface );
 }
@@ -853,6 +855,8 @@ void ExtrusionSurfaceWindow::implSetSurface( int nSurface, 
bool bEnabled )
     mxPlastic->set_sensitive(bEnabled);
     mxMetal->set_active(nSurface == 3 && bEnabled);
     mxMetal->set_sensitive(bEnabled);
+    mxMetalMSO->set_active(nSurface == 4 && bEnabled);
+    mxMetalMSO->set_sensitive(bEnabled);
 }
 
 void ExtrusionSurfaceWindow::statusChanged(
@@ -886,8 +890,10 @@ IMPL_LINK(ExtrusionSurfaceWindow, SelectHdl, 
weld::Toggleable&, rButton, void)
         nSurface = 1;
     else if (mxPlastic->get_active())
         nSurface = 2;
-    else
+    else if (mxMetal->get_active())
         nSurface = 3;
+    else
+        nSurface = 4;
 
     Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
         OUString(g_sExtrusionSurface).copy(5), nSurface) };
diff --git a/svx/source/tbxctrls/extrusioncontrols.hxx 
b/svx/source/tbxctrls/extrusioncontrols.hxx
index 7e0043487274..8b7c2e8afcc7 100644
--- a/svx/source/tbxctrls/extrusioncontrols.hxx
+++ b/svx/source/tbxctrls/extrusioncontrols.hxx
@@ -188,6 +188,7 @@ private:
     std::unique_ptr<weld::RadioButton> mxMatt;
     std::unique_ptr<weld::RadioButton> mxPlastic;
     std::unique_ptr<weld::RadioButton> mxMetal;
+    std::unique_ptr<weld::RadioButton> mxMetalMSO;
 
     DECL_LINK( SelectHdl, weld::Toggleable&, void );
 
diff --git a/svx/source/toolbars/extrusionbar.cxx 
b/svx/source/toolbars/extrusionbar.cxx
index 659af238d77e..26ac4805cde0 100644
--- a/svx/source/toolbars/extrusionbar.cxx
+++ b/svx/source/toolbars/extrusionbar.cxx
@@ -18,6 +18,7 @@
  */
 
 
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
 #include <com/sun/star/drawing/ShadeMode.hpp>
@@ -126,9 +127,9 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
     {
         css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( 
sExtrusion, sExtrusion );
 
+        bool bOn(false);
         if( pAny )
         {
-            bool bOn(false);
             (*pAny) >>= bOn;
             bOn = !bOn;
             (*pAny) <<= bOn;
@@ -139,6 +140,23 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
             aPropValue.Name = sExtrusion;
             aPropValue.Value <<= true;
             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
+            bOn = true;
+        }
+        // draw:extrusion-diffusion has default 0% and c3DDiffuseAmt has 
default 100%. We set property
+        // "Diffusion" with value 100% here if it does not exist already. This 
forces, that the
+        // property is written to file in case an extrusion is newly created, 
and users of old
+        // documents, which usually do not have this property, can force the 
value to 100% by toggling
+        // the extrusion off and on.
+        if (bOn)
+        {
+            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, 
u"Diffusion");
+            if (!pAny)
+            {
+                css::beans::PropertyValue aPropValue;
+                aPropValue.Name = u"Diffusion";
+                aPropValue.Value <<= 100.0;
+                rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
+            }
         }
     }
     break;
@@ -335,52 +353,75 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
                     break;
                 case 1: // matte
                 case 2: // plastic
-                case 3: // metal
+                case 3: // metal ODF
+                case 4: // metal MS Office
                     if (eOldShadeMode == ShadeMode_DRAFT)
                         eShadeMode = ShadeMode_FLAT; // ODF default
                     break;
             }
 
-            bool bMetal = nSurface == 3;
-
             // ODF has no dedicated property for 'surface'. MS Office binary 
format uses attribute
             // c3DSpecularAmt to distinguish between 'matte' (=0) and 
'plastic'.
-            // From point of ODF, using not harsh light has similar effect.
+            // We do the same.
             double fOldSpecularity = 0.0;
             pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, 
u"Specularity");
             if (pAny)
                 *pAny >>= fOldSpecularity;
             double fSpecularity = fOldSpecularity;
-            bool bOldIsFirstLightHarsh = true;
-            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, 
u"FirstLightHarsh");
-            if (pAny)
-                *pAny >>= bOldIsFirstLightHarsh;
-            bool bIsFirstLightHarsh = bOldIsFirstLightHarsh;
             switch( nSurface )
             {
             case 0: // wireframe
                 break;
             case 1: // matte
                 fSpecularity = 0.0;
-                bIsFirstLightHarsh = false;
                 break;
             case 2: // plastic
-            case 3: // metal
+            case 3: // metal ODF
+            case 4: // metal MS Office
                 if (basegfx::fTools::equalZero(fOldSpecularity, 0.0001))
-                    fSpecularity = 80; // estimated value, can be changed if 
necessary
-                if (!bOldIsFirstLightHarsh)
-                    bIsFirstLightHarsh = true;
+                    // MS Office uses 80000/65536. That is currently not 
allowed in ODF.
+                    // But the ODF error will be catched in xmloff.
+                    fSpecularity = 80000.0 / 655.36; // interpreted as %
                 break;
             }
 
+            // MS Office binary format uses attribute c3DDiffuseAmt with value 
=43712 (Fixed 16.16) in
+            // addition to the 'metal' flag. For other surface kinds default = 
65536 is used.
+            // We toggle between 100 and 43712.0 / 655.36 here, to get better 
ODF -> MSO binary.
+            // We keep other values, those might be set outside regular UI, 
e.g by macro.
+            double fOldDiffusion = 100.0;
+            pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, 
u"Diffusion");
+            if (pAny)
+                *pAny >>= fOldDiffusion;
+            double fDiffusion = fOldDiffusion;
+            if (nSurface == 4)
+            {
+                if (fOldDiffusion == 100.0)
+                    fDiffusion = 43712.0 / 655.36; // interpreted as %
+            }
+            else
+            {
+                if (basegfx::fTools::equalZero(fOldDiffusion - 43712.0 / 
655.36, 0.0001))
+                    fDiffusion = 100.0;
+            }
+
             css::beans::PropertyValue aPropValue;
             aPropValue.Name = "ShadeMode";
             aPropValue.Value <<= eShadeMode;
             rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
 
             aPropValue.Name = "Metal";
-            aPropValue.Value <<= bMetal;
-            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
+            aPropValue.Value <<= nSurface == 3 || nSurface == 4;
+            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+
+            if (nSurface == 3 || nSurface == 4)
+            {
+                aPropValue.Name = "MetalType";
+                aPropValue.Value <<= nSurface == 4
+                                         ? 
EnhancedCustomShapeMetalType::MetalMSCompatible
+                                         : 
EnhancedCustomShapeMetalType::MetalODF;
+                rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+            }
 
             if (!basegfx::fTools::equalZero(fOldSpecularity - fSpecularity, 
0.0001))
             {
@@ -389,10 +430,10 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
                 rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
             }
 
-            if (bOldIsFirstLightHarsh != bIsFirstLightHarsh)
+            if (!basegfx::fTools::equalZero(fOldDiffusion - fDiffusion, 
0.0001))
             {
-                aPropValue.Name = "FirstLightHarsh";
-                aPropValue.Value <<= bIsFirstLightHarsh;
+                aPropValue.Name = "Diffusion";
+                aPropValue.Value <<= fDiffusion;
                 rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
             }
         }
@@ -404,16 +445,17 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
         {
             sal_Int32 nLevel = 
rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_INTENSITY)->GetValue();
 
-            double fBrightness;
-            double fLevel1;
-            double fLevel2;
+            double fBrightness; // c3DAmbientIntensity in MS Office
+            double fLevel1; // c3DKeyIntensity in MS Office
+            double fLevel2; // c3DFillIntensity in MS Office
 
+            // ToDo: "bright" values are different from MS Office. Should they 
be kept?
             switch( nLevel )
             {
             case 0: // bright
-                fBrightness = 34.0;
-                fLevel1 = 66.0;
-                fLevel2 = 66.0;
+                fBrightness = 33.0; // ODF default.
+                fLevel1 = 66.0; // ODF default
+                fLevel2 = 66.0; // ODF default
                 break;
             case 1: // normal
                 fBrightness = 15.0;
@@ -432,10 +474,6 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
             aPropValue.Value <<= fBrightness;
             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
 
-            aPropValue.Name = "SecondLightHarsh";
-            aPropValue.Value <<= false;
-            rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
-
             aPropValue.Name = "FirstLightLevel";
             aPropValue.Value <<= fLevel1;
             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
@@ -443,6 +481,12 @@ static void impl_execute( SfxRequest const & rReq, 
SdrCustomShapeGeometryItem& r
             aPropValue.Name = "SecondLightLevel";
             aPropValue.Value <<= fLevel2;
             rGeometryItem.SetPropertyValue( sExtrusion,  aPropValue );
+
+            // If a user sets light preset 'Dim' in MS Office, MS Office sets 
second light to harsh.
+            // In other cases it is soft.
+            aPropValue.Name = "SecondLightHarsh";
+            aPropValue.Value <<= nLevel == 2;
+            rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
         }
     }
     break;
@@ -665,8 +709,8 @@ static void getExtrusionDirectionState( SdrView const * 
pSdrView, SfxItemSet& rS
             }
 
             bool        bParallel = true;
-            Position3D  aViewPoint( 3472, -3472, 25000 );
-            double      fSkewAngle = -135;
+            Position3D  aViewPoint( 3472, -3472, 25000 ); // MSO default
+            double      fSkewAngle = -135; // MSO default
 
             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
"ProjectionMode" );
             sal_Int16 nProjectionMode = sal_Int16();
@@ -869,25 +913,33 @@ static void getExtrusionSurfaceState( SdrView const * 
pSdrView, SfxItemSet& rSet
             sal_Int32 nSurface = 0; // wire frame
 
             ShadeMode eShadeMode( ShadeMode_FLAT );
-            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
"ShadeMode" );
+            pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
u"ShadeMode" );
             if( pAny )
                 *pAny >>= eShadeMode;
 
             if (eShadeMode != ShadeMode_DRAFT)
             {
                 bool bMetal = false;
-                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
"Metal" );
+                pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
u"Metal" );
                 if( pAny )
                     *pAny >>= bMetal;
 
                 if( bMetal )
                 {
-                    nSurface = 3; // metal
+                    nSurface = 3; // metal ODF
+                    sal_Int16 eMetalType;
+                    pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
u"MetalType" );
+                    if (pAny)
+                    {
+                        *pAny >>= eMetalType;
+                        if (eMetalType == 
EnhancedCustomShapeMetalType::MetalMSCompatible)
+                            nSurface = 4; // metal MS Office
+                    }
                 }
                 else
                 {
                     double fSpecularity = 0;
-                    pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
"Specularity" );
+                    pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, 
u"Specularity" );
                     if( pAny )
                         *pAny >>= fSpecularity;
 
@@ -951,7 +1003,7 @@ static void getExtrusionDepthState( SdrView const * 
pSdrView, SfxItemSet& rSet )
                     continue;
             }
 
-            double fDepth = 1270.0;
+            double fDepth = 1270.0; // =36pt ODF default
             pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Depth" );
             if( pAny )
             {
diff --git a/svx/uiconfig/ui/surfacewindow.ui b/svx/uiconfig/ui/surfacewindow.ui
index e7f612b8e7a9..52688d176f47 100644
--- a/svx/uiconfig/ui/surfacewindow.ui
+++ b/svx/uiconfig/ui/surfacewindow.ui
@@ -22,6 +22,11 @@
     <property name="can_focus">False</property>
     <property name="icon_name">svx/res/wireframe_16.png</property>
   </object>
+  <object class="GtkImage" id="image5">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="icon_name">svx/res/metal_16.png</property>
+  </object>
   <object class="GtkPopover" id="SurfaceWindow">
     <property name="can_focus">False</property>
     <property name="no_show_all">True</property>
@@ -89,7 +94,7 @@
         </child>
         <child>
           <object class="GtkRadioButton" id="metal">
-            <property name="label" translatable="yes" 
context="surfacewindow|RID_SVXSTR_METAL">Me_tal</property>
+            <property name="label" translatable="yes" 
context="surfacewindow|RID_SVXSTR_METAL">Me_tal ODF</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
@@ -105,6 +110,24 @@
             <property name="position">3</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkRadioButton" id="metalMSO">
+            <property name="label" translatable="yes" 
context="surfacewindow|RID_SVXSTR_METALMSO">Meta_l MS compatible</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="image">image5</property>
+            <property name="use_underline">True</property>
+            <property name="always_show_image">True</property>
+            <property name="draw_indicator">True</property>
+            <property name="group">wireframe</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
       </object>
     </child>
   </object>
diff --git a/xmloff/inc/EnhancedCustomShapeToken.hxx 
b/xmloff/inc/EnhancedCustomShapeToken.hxx
index 328704f9b889..7fd86f5a5126 100644
--- a/xmloff/inc/EnhancedCustomShapeToken.hxx
+++ b/xmloff/inc/EnhancedCustomShapeToken.hxx
@@ -47,6 +47,7 @@ namespace xmloff::EnhancedCustomShapeToken {
         EAS_extrusion_first_light_direction,
         EAS_extrusion_second_light_direction,
         EAS_extrusion_metal,
+        EAS_extrusion_metal_type,
         EAS_shade_mode,
         EAS_extrusion_rotation_angle,
         EAS_extrusion_rotation_center,
@@ -115,6 +116,7 @@ namespace xmloff::EnhancedCustomShapeToken {
         EAS_FirstLightDirection,
         EAS_SecondLightDirection,
         EAS_Metal,
+        EAS_MetalType,
         EAS_ShadeMode,
         EAS_RotateAngle,
         EAS_RotationCenter,
diff --git a/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc 
b/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc
new file mode 100644
index 000000000000..99c433654dcd
Binary files /dev/null and 
b/xmloff/qa/unit/data/tdf145700_3D_metal_type_MSCompatible.doc differ
diff --git a/xmloff/qa/unit/draw.cxx b/xmloff/qa/unit/draw.cxx
index fc07053cbacf..04c7178ca6bf 100644
--- a/xmloff/qa/unit/draw.cxx
+++ b/xmloff/qa/unit/draw.cxx
@@ -16,15 +16,19 @@
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
 #include <com/sun/star/util/Color.hpp>
 #include <com/sun/star/text/XTextRange.hpp>
 #include <com/sun/star/text/XTextTable.hpp>
 
+#include <comphelper/configuration.hxx>
+#include <officecfg/Office/Common.hxx>
 #include <unotools/mediadescriptor.hxx>
 #include <unotools/tempfile.hxx>
 #include <unotools/ucbstreamhelper.hxx>
+#include <unotools/saveopt.hxx>
 
 using namespace ::com::sun::star;
 
@@ -44,6 +48,7 @@ public:
     void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
     uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
     void save(const OUString& rFilterName, utl::TempFile& rTempFile);
+    uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex);
 };
 
 void XmloffDrawTest::setUp()
@@ -76,6 +81,17 @@ void XmloffDrawTest::save(const OUString& rFilterName, 
utl::TempFile& rTempFile)
     validate(rTempFile.GetFileName(), test::ODF);
 }
 
+uno::Reference<drawing::XShape> XmloffDrawTest::getShape(sal_uInt8 nShapeIndex)
+{
+    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+                                                                   
uno::UNO_QUERY_THROW);
+    uno::Reference<drawing::XDrawPages> 
xDrawPages(xDrawPagesSupplier->getDrawPages());
+    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), 
uno::UNO_QUERY_THROW);
+    uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex),
+                                           uno::UNO_QUERY_THROW);
+    return xShape;
+}
+
 CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextBoxLoss)
 {
     // Load a document that has a shape with a textbox in it. Save it to ODF 
and reload.
@@ -242,6 +258,90 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTableInShape)
     CPPUNIT_ASSERT_EQUAL(OUString("A1"), xCell->getString());
 }
 
+// Tests for save/load of new (LO 7.4) attribute loext:extrusion-metal-type
+namespace
+{
+void lcl_assertMetalProperties(std::string_view sInfo, 
uno::Reference<drawing::XShape>& rxShape)
+{
+    uno::Reference<beans::XPropertySet> xShapeProps(rxShape, uno::UNO_QUERY);
+    uno::Sequence<beans::PropertyValue> aGeoPropSeq;
+    xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeoPropSeq;
+    comphelper::SequenceAsHashMap aGeoPropMap(aGeoPropSeq);
+    uno::Sequence<beans::PropertyValue> aExtrusionSeq;
+    aGeoPropMap.getValue("Extrusion") >>= aExtrusionSeq;
+    comphelper::SequenceAsHashMap aExtrusionPropMap(aExtrusionSeq);
+
+    bool bIsMetal(false);
+    aExtrusionPropMap.getValue("Metal") >>= bIsMetal;
+    OString sMsg = OString::Concat(sInfo) + " Metal";
+    CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(), bIsMetal);
+
+    sal_Int16 nMetalType(-1);
+    aExtrusionPropMap.getValue("MetalType") >>= nMetalType;
+    sMsg = OString::Concat(sInfo) + " MetalType";
+    CPPUNIT_ASSERT_EQUAL_MESSAGE(
+        sMsg.getStr(), 
css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible, nMetalType);
+}
+}
+
+CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionMetalTypeExtended)
+{
+    // import
+    getComponent() = 
loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY)
+                                         + 
"tdf145700_3D_metal_type_MSCompatible.doc",
+                                     "com.sun.star.text.TextDocument");
+    // verify properties
+    uno::Reference<drawing::XShape> xShape(getShape(0));
+    lcl_assertMetalProperties("from doc", xShape);
+
+    // Test, that new attribute is written with loext namespace. Adapt when 
attribute is added to ODF.
+    utl::TempFile aTempFile;
+    // The file has set c3DSpecularAmt="65536" to prevent validation error in 
attribute
+    // draw:extrusion-specularity. The error, that 122% is written in case of 
c3DSpecularAmt="80000" is
+    // not yet fixed.
+    save("writer8", aTempFile);
+
+    // assert XML.
+    std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, 
"content.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    assertXPath(pXmlDoc, "//draw:enhanced-geometry", "extrusion-metal", 
"true");
+    assertXPath(pXmlDoc,
+                
"//draw:enhanced-geometry[@loext:extrusion-metal-type='loext:MetalMSCompatible']");
+
+    // reload
+    getComponent()->dispose();
+    getComponent() = loadFromDesktop(aTempFile.GetURL(), 
"com.sun.star.text.TextDocument");
+    // verify properties
+    uno::Reference<drawing::XShape> xShapeReload(getShape(0));
+    lcl_assertMetalProperties("from ODF 1.3 extended", xShapeReload);
+}
+
+CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testExtrusionMetalTypeStrict)
+{
+    // import
+    getComponent() = 
loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY)
+                                         + 
"tdf145700_3D_metal_type_MSCompatible.doc",
+                                     "com.sun.star.text.TextDocument");
+
+    // save ODF 1.3 strict and test, that new attribute is not written. Adapt 
when attribute is
+    // added to ODF.
+    const SvtSaveOptions::ODFDefaultVersion 
nCurrentODFVersion(GetODFDefaultVersion());
+    SetODFDefaultVersion(SvtSaveOptions::ODFVER_013);
+    // The file has set c3DSpecularAmt="65536" to prevent validation error in 
attribute
+    // draw:extrusion-specularity. The error, that 122% is written in case of 
c3DSpecularAmt="80000" is
+    // not yet fixed.
+    utl::TempFile aTempFile;
+    save("writer8", aTempFile);
+
+    // assert XML.
+    std::unique_ptr<SvStream> pStream = parseExportStream(aTempFile, 
"content.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    assertXPath(pXmlDoc, "//draw:enhanced-geometry", "extrusion-metal", 
"true");
+    assertXPath(pXmlDoc, 
"//draw:enhanced-geometry[@loext:extrusion-metal-type]", 0);
+
+    SetODFDefaultVersion(nCurrentODFVersion);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 298dd431a0fe..f3ae86566e43 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -2473,6 +2473,7 @@ namespace xmloff::token {
         TOKEN( "extrusion-first-light-direction" ,      
XML_EXTRUSION_FIRST_LIGHT_DIRECTION ),
         TOKEN( "extrusion-second-light-direction" , 
XML_EXTRUSION_SECOND_LIGHT_DIRECTION ),
         TOKEN( "extrusion-metal" ,                      XML_EXTRUSION_METAL ),
+        TOKEN( "extrusion-metal-type" ,                 
XML_EXTRUSION_METAL_TYPE ),
         TOKEN( "extrusion-rotation-angle" ,         
XML_EXTRUSION_ROTATION_ANGLE ),
         TOKEN( "extrusion-rotation-center" ,            
XML_EXTRUSION_ROTATION_CENTER ),
         TOKEN( "extrusion-shininess" ,                  
XML_EXTRUSION_SHININESS ),
diff --git a/xmloff/source/draw/EnhancedCustomShapeToken.cxx 
b/xmloff/source/draw/EnhancedCustomShapeToken.cxx
index 38ca0df48e6a..700e29fc71fd 100644
--- a/xmloff/source/draw/EnhancedCustomShapeToken.cxx
+++ b/xmloff/source/draw/EnhancedCustomShapeToken.cxx
@@ -59,6 +59,7 @@ const TokenTable pTokenTableArray[] =
     { "extrusion-first-light-direction",    
EAS_extrusion_first_light_direction },
     { "extrusion-second-light-direction",   
EAS_extrusion_second_light_direction },
     { "extrusion-metal",                    EAS_extrusion_metal },
+    { "extrusion-metal-type",               EAS_extrusion_metal_type },
     { "shade-mode",                         EAS_shade_mode },
     { "extrusion-rotation-angle",           EAS_extrusion_rotation_angle },
     { "extrusion-rotation-center",          EAS_extrusion_rotation_center },
@@ -127,6 +128,7 @@ const TokenTable pTokenTableArray[] =
     { "FirstLightDirection",                EAS_FirstLightDirection },
     { "SecondLightDirection",               EAS_SecondLightDirection },
     { "Metal",                              EAS_Metal },
+    { "MetalType",                          EAS_MetalType },
     { "ShadeMode",                          EAS_ShadeMode },
     { "RotateAngle",                        EAS_RotateAngle },
     { "RotationCenter",                     EAS_RotationCenter },
diff --git a/xmloff/source/draw/shapeexport.cxx 
b/xmloff/source/draw/shapeexport.cxx
index f1c23d3ed0b2..ea33330994b1 100644
--- a/xmloff/source/draw/shapeexport.cxx
+++ b/xmloff/source/draw/shapeexport.cxx
@@ -46,6 +46,7 @@
 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
@@ -4453,6 +4454,25 @@ static void ImpExportEnhancedGeometry( SvXMLExport& 
rExport, const uno::Referenc
                                                 bExtrusionMetal ? GetXMLToken( 
XML_TRUE ) : GetXMLToken( XML_FALSE ) );
                                     }
                                     break;
+                                    case EAS_MetalType :
+                                    {
+                                        // export only if ODF extensions are 
enabled
+                                        sal_Int16 eMetalType;
+                                        if (rProp.Value >>= eMetalType)
+                                        {
+                                            
SvtSaveOptions::ODFSaneDefaultVersion eVersion = 
rExport.getSaneDefaultVersion();
+                                            if (eVersion > 
SvtSaveOptions::ODFSVER_013
+                                                && (eVersion & 
SvtSaveOptions::ODFSVER_EXTENDED))
+                                            {
+                                                if (eMetalType == 
drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
+                                                    aStr = 
"loext:MetalMSCompatible";
+                                                else
+                                                    aStr = "draw:MetalODF";
+                                                
rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr);
+                                            }
+                                        }
+                                    }
+                                    break;
                                     case EAS_ShadeMode :
                                     {
                                         // shadeMode
diff --git a/xmloff/source/draw/ximpcustomshape.cxx 
b/xmloff/source/draw/ximpcustomshape.cxx
index c8dbf70ba143..df86901b9635 100644
--- a/xmloff/source/draw/ximpcustomshape.cxx
+++ b/xmloff/source/draw/ximpcustomshape.cxx
@@ -40,6 +40,7 @@
 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
 #include <com/sun/star/drawing/ProjectionMode.hpp>
 #include <com/sun/star/drawing/Position3D.hpp>
 #include <sax/tools/converter.hxx>
@@ -982,6 +983,18 @@ void XMLEnhancedCustomShapeContext::startFastElement(
             case EAS_extrusion_metal :
                 GetBool( maExtrusion, aIter.toView(), EAS_Metal );
             break;
+            case EAS_extrusion_metal_type :
+            {
+                OUString rValue = aIter.toString();
+                sal_Int16 
eMetalType(drawing::EnhancedCustomShapeMetalType::MetalODF);
+                if (rValue == "loext:MetalMSCompatible")
+                    eMetalType = 
drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
+                beans::PropertyValue aProp;
+                aProp.Name = EASGet(EAS_MetalType);
+                aProp.Value <<= eMetalType;
+                maExtrusion.push_back(aProp);
+            }
+            break;
             case EAS_shade_mode :
             {
                 drawing::ShadeMode eShadeMode( drawing::ShadeMode_FLAT );
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index a23326c71f17..f610bfbff47e 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -2320,6 +2320,7 @@ extrusion-second-light-level
 extrusion-first-light-direction
 extrusion-second-light-direction
 extrusion-metal
+extrusion-metal-type
 extrusion-rotation-angle
 extrusion-rotation-center
 extrusion-shininess

Reply via email to