include/editeng/unoprnms.hxx                     |    4 +
 include/editeng/unotext.hxx                      |    5 -
 oox/source/drawingml/textcharacterproperties.cxx |    6 +
 oox/source/token/properties.txt                  |    2 
 sw/qa/extras/ooxmlexport/data/tdf155945.docx     |binary
 sw/qa/extras/ooxmlexport/ooxmlexport19.cxx       |   11 +++
 sw/source/core/unocore/unoobj.cxx                |   48 ++++++++-------
 sw/source/filter/ww8/docxattributeoutput.cxx     |   28 ++++++---
 writerfilter/source/dmapper/CellColorHandler.cxx |   70 ++++++++++++++++++++++-
 writerfilter/source/dmapper/CellColorHandler.hxx |   15 ++++
 writerfilter/source/dmapper/PropertyIds.cxx      |    7 +-
 writerfilter/source/dmapper/PropertyIds.hxx      |    3 
 12 files changed, 163 insertions(+), 36 deletions(-)

New commits:
commit 79b17173296c00f2292240c2304cdbd6c4a97b06
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Sun Jun 11 00:57:36 2023 +0900
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Jun 22 21:03:15 2023 +0200

    ooxml: import and export background and fill theme colors props.
    
    This adds support to import and export background and fill theme
    color properties.
    
    Change-Id: I0f40615fe2d06cdcb4f2f9752602fe2ec699c7b3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152835
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit 9e121f3a6b95dab7525aa1583f810b2b504ce1b3)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153421
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/include/editeng/unoprnms.hxx b/include/editeng/unoprnms.hxx
index 8859dfe5a4a5..214b8fd53dea 100644
--- a/include/editeng/unoprnms.hxx
+++ b/include/editeng/unoprnms.hxx
@@ -350,6 +350,10 @@ inline constexpr OUStringLiteral 
UNO_NAME_EDIT_CHAR_SHADOWED = u"CharShadowed";
 inline constexpr OUStringLiteral UNO_NAME_EDIT_CHAR_UNDERLINE = 
u"CharUnderline";
 inline constexpr OUStringLiteral UNO_NAME_EDIT_CHAR_OVERLINE = u"CharOverline";
 
+inline constexpr OUStringLiteral UNO_NAME_EDIT_CHAR_BACKGROUND_COLOR = 
u"CharBackColor";
+inline constexpr OUStringLiteral UNO_NAME_EDIT_CHAR_BACKGROUND_COMPLEX_COLOR = 
u"CharBackgroundComplexColor";
+inline constexpr OUStringLiteral UNO_NAME_EDIT_CHAR_BACKGROUND_TRANSPARENT = 
u"CharBackTransparent";
+
 inline constexpr OUStringLiteral UNO_NAME_BITMAP = u"Bitmap";
 
 inline constexpr OUStringLiteral UNO_NAME_LINKDISPLAYNAME = u"LinkDisplayName";
diff --git a/include/editeng/unotext.hxx b/include/editeng/unotext.hxx
index 84dc7d9fdb6f..a027e331ae00 100644
--- a/include/editeng/unotext.hxx
+++ b/include/editeng/unotext.hxx
@@ -93,8 +93,9 @@ struct SfxItemPropertyMapEntry;
     { UNO_NAME_EDIT_CHAR_COLOR_LUM_MOD,       EE_CHAR_COLOR, 
::cppu::UnoType<sal_Int16>::get(),     0, MID_COLOR_LUM_MOD }, \
     { UNO_NAME_EDIT_CHAR_COLOR_LUM_OFF,       EE_CHAR_COLOR, 
::cppu::UnoType<sal_Int16>::get(),     0, MID_COLOR_LUM_OFF }, \
     { UNO_NAME_EDIT_CHAR_COMPLEX_COLOR, EE_CHAR_COLOR,    
::cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_COMPLEX_COLOR }, \
-    { u"CharBackColor",                EE_CHAR_BKGCOLOR,   
::cppu::UnoType<sal_Int32>::get(),        0, 0 }, \
-    { u"CharBackTransparent",          EE_CHAR_BKGCOLOR,   
::cppu::UnoType<bool>::get(),             0, MID_GRAPHIC_TRANSPARENT }, \
+    { UNO_NAME_EDIT_CHAR_BACKGROUND_COLOR, EE_CHAR_BKGCOLOR,   
::cppu::UnoType<sal_Int32>::get(),        0, MID_COLOR_RGB }, \
+    { UNO_NAME_EDIT_CHAR_BACKGROUND_COMPLEX_COLOR, EE_CHAR_BKGCOLOR, 
::cppu::UnoType<css::util::XComplexColor>::get(), 0, MID_COMPLEX_COLOR }, \
+    { UNO_NAME_EDIT_CHAR_BACKGROUND_TRANSPARENT, EE_CHAR_BKGCOLOR,   
::cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT }, \
     { UNO_NAME_EDIT_CHAR_ESCAPEMENT,  EE_CHAR_ESCAPEMENT, 
::cppu::UnoType<sal_Int16>::get(),        0, MID_ESC }, \
     { UNO_NAME_EDIT_CHAR_UNDERLINE,   EE_CHAR_UNDERLINE,  
::cppu::UnoType<sal_Int16>::get(),        0, MID_TL_STYLE }, \
     { u"CharUnderlineColor",           EE_CHAR_UNDERLINE,  
::cppu::UnoType<sal_Int32>::get(),        0, MID_TL_COLOR }, \
diff --git a/oox/source/drawingml/textcharacterproperties.cxx 
b/oox/source/drawingml/textcharacterproperties.cxx
index 1217c19441ae..c3dde4889a64 100644
--- a/oox/source/drawingml/textcharacterproperties.cxx
+++ b/oox/source/drawingml/textcharacterproperties.cxx
@@ -216,7 +216,11 @@ void TextCharacterProperties::pushToPropMap( PropertyMap& 
rPropMap, const XmlFil
     }
 
     if (maHighlightColor.isUsed() && maHighlightColor.getTransparency() != 100)
-        rPropMap.setProperty( PROP_CharBackColor, maHighlightColor.getColor( 
rFilter.getGraphicHelper() ));
+    {
+        rPropMap.setProperty(PROP_CharBackColor, maHighlightColor.getColor( 
rFilter.getGraphicHelper() ));
+        model::ComplexColor aComplexColor = maHighlightColor.getComplexColor();
+        rPropMap.setProperty(PROP_CharBackgroundComplexColor, 
model::color::createXComplexColor(aComplexColor));
+    }
     else
         rPropMap.setProperty( PROP_CharBackColor, sal_Int32(-1));
 }
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index 025b0628b9d8..a6de5458b663 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -24,6 +24,7 @@ BackGraphicLocation
 BackGraphic
 Background
 BackgroundColor
+BackgroundComplexColor
 BasicLibraries
 BlackDay
 BlockIncrement
@@ -52,6 +53,7 @@ CenterHorizontally
 CenterVertically
 Change
 CharBackColor
+CharBackgroundComplexColor
 CharCaseMap
 CharColor
 CharContoured
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index ba5d14bd8c90..3b095a96aea6 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -290,7 +290,9 @@ auto 
detachFrom(rtl::Reference<sax_fastparser::FastAttributeList>& src)
     return rtl::Reference(std::move(src));
 }
 
-void 
lclAddThemeColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList>& 
pAttrList, model::ComplexColor const& rComplexColor)
+void lclAddThemeValuesToCustomAttributes(
+    rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, 
model::ComplexColor const& rComplexColor,
+    sal_Int32 nThemeAttrId, sal_Int32 nThemeTintAttrId, sal_Int32 
nThemeShadeAttrId)
 {
     static std::unordered_map<model::ThemeColorType, const char*> 
constThemeColorTypeTokenMap = {
         { model::ThemeColorType::Dark1, "dark1" },
@@ -326,7 +328,7 @@ void 
lclAddThemeColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList
                 sSchemeType = "background2";
         }
 
-        DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
XML_themeColor), sSchemeType);
+        DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
nThemeAttrId), sSchemeType);
 
         sal_Int16 nLumMod = 10'000;
         sal_Int16 nLumOff = 0;
@@ -350,13 +352,13 @@ void 
lclAddThemeColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList
             {
                 // Convert from 0-100 into 0-255
                 sal_Int16 nTint255 = std::round(255.0 - (double(nTint) / 
10000.0) * 255.0);
-                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
XML_themeTint), OString::number(nTint255, 16));
+                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
nThemeTintAttrId), OString::number(nTint255, 16));
             }
             else if (nShade != 0)
             {
                 // Convert from 0-100 into 0-255
                 sal_Int16 nShade255 = std::round(255.0 - (double(nShade) / 
10000.0) * 255.0);
-                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
XML_themeShade), OString::number(nShade255, 16));
+                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
nThemeShadeAttrId), OString::number(nShade255, 16));
             }
         }
         else
@@ -372,13 +374,23 @@ void 
lclAddThemeColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList
             sal_Int16 nTintShade255 = std::round(255.0 - 
(std::abs(nPercentage) / 100.0) * 255.0);
 
             if (nPercentage > 0)
-                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
XML_themeTint), OString::number(nTintShade255, 16));
+                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
nThemeTintAttrId), OString::number(nTintShade255, 16));
             else if (nPercentage < 0)
-                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
XML_themeShade), OString::number(nTintShade255, 16));
+                DocxAttributeOutput::AddToAttrList(pAttrList, FSNS(XML_w, 
nThemeShadeAttrId), OString::number(nTintShade255, 16));
         }
     }
 }
 
+void 
lclAddThemeFillColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList>&
 pAttrList, model::ComplexColor const& rComplexColor)
+{
+    lclAddThemeValuesToCustomAttributes(pAttrList, rComplexColor, 
XML_themeFill, XML_themeFillTint, XML_themeFillShade);
+}
+
+void 
lclAddThemeColorAttributes(rtl::Reference<sax_fastparser::FastAttributeList>& 
pAttrList, model::ComplexColor const& rComplexColor)
+{
+    lclAddThemeValuesToCustomAttributes(pAttrList, rComplexColor, 
XML_themeColor, XML_themeTint, XML_themeShade);
+}
+
 } // end anonymous namespace
 
 void DocxAttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 /*nScript*/ )
@@ -9476,6 +9488,7 @@ static std::optional<sal_Int32> lcl_getDmlAlpha(const 
SvxBrushItem& rBrush)
 void DocxAttributeOutput::FormatBackground( const SvxBrushItem& rBrush )
 {
     const Color aColor = rBrush.GetColor();
+    model::ComplexColor const& rComplexColor = rBrush.getComplexColor();
     OString sColor = msfilter::util::ConvertColor( aColor.GetRGBColor() );
     std::optional<sal_Int32> oAlpha = lcl_getDmlAlpha(rBrush);
     if (m_rExport.SdrExporter().getTextFrameSyntax())
@@ -9490,7 +9503,8 @@ void DocxAttributeOutput::FormatBackground( const 
SvxBrushItem& rBrush )
             AddToAttrList( m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_opacity, OString::number(fOpacity) + "f" );
         }
 
-        AddToAttrList( m_rExport.SdrExporter().getFlyAttrList(), 
XML_fillcolor, "#" + sColor );
+        AddToAttrList(m_rExport.SdrExporter().getFlyAttrList(), XML_fillcolor, 
"#" + sColor );
+        
lclAddThemeFillColorAttributes(m_rExport.SdrExporter().getFlyAttrList(), 
rComplexColor);
     }
     else if (m_rExport.SdrExporter().getDMLTextFrameSyntax())
     {
diff --git a/writerfilter/source/dmapper/CellColorHandler.cxx 
b/writerfilter/source/dmapper/CellColorHandler.cxx
index 439806e20fa8..ef4eb5dc4172 100644
--- a/writerfilter/source/dmapper/CellColorHandler.cxx
+++ b/writerfilter/source/dmapper/CellColorHandler.cxx
@@ -25,6 +25,7 @@
 #include <filter/msfilter/util.hxx>
 #include <comphelper/sequence.hxx>
 #include <tools/color.hxx>
+#include <docmodel/uno/UnoComplexColor.hxx>
 
 namespace writerfilter::dmapper {
 
@@ -124,21 +125,27 @@ void CellColorHandler::lcl_attribute(Id rName, Value & 
rVal)
             m_nColor = nIntValue;
         break;
         case NS_ooxml::LN_CT_Shd_themeFill:
+            m_eFillThemeColorType = 
TDefTableHandler::getThemeColorTypeIndex(nIntValue);
             createGrabBag("themeFill", 
uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
         break;
         case NS_ooxml::LN_CT_Shd_themeFillShade:
+            m_nFillThemeColorShade = nIntValue;
             createGrabBag("themeFillShade", 
uno::Any(OUString::number(nIntValue, 16)));
         break;
         case NS_ooxml::LN_CT_Shd_themeFillTint:
+            m_nFillThemeColorTint = nIntValue;
             createGrabBag("themeFillTint", 
uno::Any(OUString::number(nIntValue, 16)));
             break;
         case NS_ooxml::LN_CT_Shd_themeColor:
+            m_eThemeColorType = 
TDefTableHandler::getThemeColorTypeIndex(nIntValue);
             createGrabBag("themeColor", 
uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
         break;
         case NS_ooxml::LN_CT_Shd_themeShade:
+            m_nThemeColorShade = nIntValue;
             createGrabBag("themeShade", uno::Any(OUString::number(nIntValue, 
16)));
         break;
         case NS_ooxml::LN_CT_Shd_themeTint:
+            m_nThemeColorTint = nIntValue;
             createGrabBag("themeTint", uno::Any(OUString::number(nIntValue, 
16)));
             break;
         default:
@@ -281,11 +288,26 @@ TablePropertyMapPtr  CellColorHandler::getProperties()
             pPropertyMap->Insert(PROP_FILL_STYLE, 
uno::Any(drawing::FillStyle_NONE));
 
         pPropertyMap->Insert(PROP_FILL_COLOR, uno::Any(nApplyColor));
+        auto xComplexColor = 
model::color::createXComplexColor(getFillComplexColor());
+        pPropertyMap->Insert(PROP_FILL_COMPLEX_COLOR, uno::Any(xComplexColor));
     }
     else if ( nWW8BrushStyle || !m_bAutoFillColor || m_bFillSpecified )
-        pPropertyMap->Insert( m_OutputFormat == Form ? PROP_BACK_COLOR
-                            : PROP_CHAR_BACK_COLOR, uno::Any( nApplyColor ));
-
+    {
+        if (m_OutputFormat == Form)
+        {
+            pPropertyMap->Insert(PROP_BACK_COLOR, uno::Any(nApplyColor));
+        }
+        else
+        {
+            pPropertyMap->Insert(PROP_CHAR_BACK_COLOR, uno::Any(nApplyColor));
+            auto aComplexColor = getFillComplexColor();
+            if (aComplexColor.getType() != model::ColorType::Unused)
+            {
+                auto xComplexColor = 
model::color::createXComplexColor(aComplexColor);
+                pPropertyMap->Insert(PROP_CHAR_BACKGROUND_COMPLEX_COLOR, 
uno::Any(xComplexColor));
+            }
+        }
+    }
     createGrabBag("originalColor", 
uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, 
nApplyColor))));
 
     return pPropertyMap;
@@ -326,6 +348,48 @@ bool CellColorHandler::isInteropGrabBagEnabled() const
     return !(m_aInteropGrabBagName.isEmpty());
 }
 
+model::ComplexColor CellColorHandler::getComplexColor() const
+{
+    model::ComplexColor aComplexColor;
+    if (m_eThemeColorType != model::ThemeColorType::Unknown)
+    {
+        aComplexColor.setSchemeColor(m_eThemeColorType);
+
+        if (m_nThemeColorTint > 0 )
+        {
+            sal_Int16 nTint = sal_Int16((255.0 - m_nThemeColorTint) * 10000.0 
/ 255.0);
+            aComplexColor.addTransformation({model::TransformationType::Tint, 
nTint});
+        }
+        if (m_nThemeColorShade > 0)
+        {
+            sal_Int16 nShade = sal_Int16((255.0 - m_nThemeColorShade) * 10000 
/ 255.0);
+            aComplexColor.addTransformation({model::TransformationType::Shade, 
nShade});
+        }
+    }
+    return aComplexColor;
+}
+
+model::ComplexColor CellColorHandler::getFillComplexColor() const
+{
+    model::ComplexColor aComplexColor;
+    if (m_eFillThemeColorType != model::ThemeColorType::Unknown)
+    {
+        aComplexColor.setSchemeColor(m_eFillThemeColorType);
+
+        if (m_nFillThemeColorTint > 0 )
+        {
+            sal_Int16 nTint = sal_Int16((255.0 - m_nFillThemeColorTint) * 
10000.0 / 255.0);
+            aComplexColor.addTransformation({model::TransformationType::Tint, 
nTint});
+        }
+        if (m_nFillThemeColorShade > 0)
+        {
+            sal_Int16 nShade = sal_Int16((255.0 - m_nFillThemeColorShade) * 
10000.0 / 255.0);
+            aComplexColor.addTransformation({model::TransformationType::Shade, 
nShade});
+        }
+    }
+    return aComplexColor;
+}
+
 } //namespace writerfilter
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/CellColorHandler.hxx 
b/writerfilter/source/dmapper/CellColorHandler.hxx
index a011cd9fd794..418f8e1f93e4 100644
--- a/writerfilter/source/dmapper/CellColorHandler.hxx
+++ b/writerfilter/source/dmapper/CellColorHandler.hxx
@@ -21,7 +21,8 @@
 #include "LoggedResources.hxx"
 #include "PropertyMap.hxx"
 #include <vector>
-
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/color/ComplexColor.hxx>
 #include <com/sun/star/beans/PropertyValue.hpp>
 
 namespace writerfilter::dmapper
@@ -33,8 +34,17 @@ public:
     enum OutputFormat { Form, Paragraph, Character }; // for what part of the 
document
 private:
     sal_Int32 m_nShadingPattern;
+
     sal_Int32 m_nColor;
+    model::ThemeColorType m_eThemeColorType = model::ThemeColorType::Unknown;
+    sal_Int32 m_nThemeColorTint = 0;
+    sal_Int32 m_nThemeColorShade = 0;
+
     sal_Int32 m_nFillColor;
+    model::ThemeColorType m_eFillThemeColorType = 
model::ThemeColorType::Unknown;
+    sal_Int32 m_nFillThemeColorTint = 0;
+    sal_Int32 m_nFillThemeColorShade = 0;
+
     bool      m_bAutoFillColor;
     bool      m_bFillSpecified;
     OutputFormat m_OutputFormat;
@@ -60,6 +70,9 @@ public:
     css::beans::PropertyValue getInteropGrabBag();
     void disableInteropGrabBag();
     bool isInteropGrabBagEnabled() const;
+
+    model::ComplexColor getComplexColor() const;
+    model::ComplexColor getFillComplexColor() const;
 };
 }
 
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx 
b/writerfilter/source/dmapper/PropertyIds.cxx
index 64c814f79492..d294a3ad082c 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -64,6 +64,7 @@ namespace
         { PROP_CHAR_WEIGHT_ASIAN, u"CharWeightAsian"},
         { PROP_CHAR_POSTURE_ASIAN, u"CharPostureAsian"},
         { PROP_CHAR_BACK_COLOR, u"CharBackColor"},
+        { PROP_CHAR_BACKGROUND_COMPLEX_COLOR, u"CharBackgroundComplexColor"},
         { PROP_CHAR_EMPHASIS, u"CharEmphasis"},
         { PROP_CHAR_COMBINE_IS_ON, u"CharCombineIsOn"},
         { PROP_CHAR_COMBINE_PREFIX, u"CharCombinePrefix"},
@@ -172,6 +173,7 @@ namespace
         { PROP_CONTOUR_POLY_POLYGON, u"ContourPolyPolygon"},
         { PROP_PAGE_TOGGLE, u"PageToggle"},
         { PROP_BACK_COLOR, u"BackColor"},
+        { PROP_BACK_COMPLEX_COLOR, u"BackComplexColor"},
         { PROP_BACK_COLOR_TRANSPARENCY, u"BackColorTransparency"},
         { PROP_ALLOW_OVERLAP, u"AllowOverlap"},
         { PROP_ALTERNATIVE_TEXT, u"AlternativeText"},
@@ -357,6 +359,7 @@ namespace
         { PROP_FOLLOW_TEXT_FLOW, u"IsFollowingTextFlow"},
         { PROP_FILL_STYLE, u"FillStyle"},
         { PROP_FILL_COLOR, u"FillColor"},
+        { PROP_FILL_COMPLEX_COLOR, u"FillComplexColor"},
         { PROP_SNAP_TO_GRID, u"SnapToGrid"},
         { PROP_GRID_SNAP_TO_CHARS, u"GridSnapToChars"},
         { PROP_RUBY_STYLE, u"RubyCharStyleName"},
@@ -394,7 +397,9 @@ bool isCharacterProperty( const PropertyIds eId )
 
 bool isParagraphProperty( const PropertyIds eId )
 {
-    return (eId >= PROP_PARA_ADJUST && eId <= PROP_PARA_WIDOWS) || eId == 
PROP_FILL_COLOR;
+    return (eId >= PROP_PARA_ADJUST && eId <= PROP_PARA_WIDOWS)
+        || eId == PROP_FILL_COLOR
+        || eId == PROP_FILL_COMPLEX_COLOR;
 }
 
 } //namespace writerfilter
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx 
b/writerfilter/source/dmapper/PropertyIds.hxx
index d3213b7be073..6708c6dfbf35 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -41,6 +41,7 @@ enum PropertyIds
         ,PROP_ANCHOR_TYPE
         ,PROP_AUTOMATIC_DISTANCE
         ,PROP_BACK_COLOR
+        ,PROP_BACK_COMPLEX_COLOR
         ,PROP_BACK_COLOR_TRANSPARENCY
         ,PROP_BITMAP
         ,PROP_BORDER_LEFT_COMPLEX_COLOR
@@ -57,6 +58,7 @@ enum PropertyIds
         ,PROP_CHARACTER_STYLES
         ,PROP_CHAR_AUTO_KERNING
         ,PROP_CHAR_BACK_COLOR
+        ,PROP_CHAR_BACKGROUND_COMPLEX_COLOR
         ,PROP_CHAR_CASE_MAP
         ,PROP_CHAR_CHAR_KERNING
         ,PROP_CHAR_COLOR
@@ -357,6 +359,7 @@ enum PropertyIds
         ,PROP_FOLLOW_TEXT_FLOW
         ,PROP_FILL_STYLE
         ,PROP_FILL_COLOR
+        ,PROP_FILL_COMPLEX_COLOR
         ,PROP_SNAP_TO_GRID
         ,PROP_GRID_SNAP_TO_CHARS
         ,PROP_RUBY_STYLE
commit eb2af5228922779fdd993125051db4e20c703106
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Jun 21 13:38:14 2023 +0300
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Jun 22 21:03:10 2023 +0200

    tdf#155945: do not turn another style attributes to direct formatting
    
    SwUnoCursorHelper::SetPropertyValues obtains the node's item set using
    SwUnoCursorHelper::GetCursorAttr, adds new items for the property values,
    and calls SwUnoCursorHelper::SetCursorAttr to set the updated item set
    to the node. This puts all the item set data as direct formatting of the
    node (autostyle).
    
    For complex SfxPoolItem, containing several properties, it could result
    in some properties having incorrect values e.g. in this sequence:
    
    1. SwUnoCursorHelper::SetPropertyValues is called with a property sequence
       including "ParaStyleName" and "ParaTopMargin", represented by a complex
       SfxPoolItem (SvxULSpaceItem's nPropUpper). The current node uses another
       style, which has a non-default bottom margin; new style has 0 as bottom
       margin.
    2. It builds a set for the union of all WhichIds corresponding to all the
       passed properties, which includes WIDs for paragraph style and for the
       respective SvxULSpaceItem.
    3. It calls SwUnoCursorHelper::GetCursorAttr to fill the set with current
       values for these WhichIds, getting also values defined in still applied
       style, including an SvxULSpaceItem with both upper and lower spacing
       (the bottom margin value of old paragraph is stored there).
    4. It sets new value of paragraph style in this item set, and then calls
       SwUnoCursorHelper::SetCursorAttr with the item set.
    
    Now the set contains a new value for paragraph style, *and* an old value
    of the paragraphs margins. This margins value is set as the paragraph's
    direct formatting (autostyle).
    
    5. SwUnoCursorHelper::GetCursorAttr is called, updating the item set with
       new values of paragraph style and margins; the direct-formatted value
       for the latter is returned, still containing the values previously
       inherited from old style.
    6. New value of top margin is set, modifying only nPropUpper member of
       SvxULSpaceItem, and keeping nPropLower (value for bottom margin) as it
       was, i.e. keeps the value incorrectly saved from old style.
    
    This happens e.g. on DOCX import. Commit 
db115bec9254417ef7a3faf687478fe5424ab378
    (tdf#78510 sw,cui: split SvxLRSpaceItem for SwTextNode, SwTextFormatColl,
    2023-02-24) has incidentally fixed handling of left and right paragraph
    indents, making their items independent; but top/bottom margins still need
    to be fixed.
    
    This change splits the properties that cause side effects (styles) from the
    rest; so that properties with side effects are processed first, with item
    sets containing only one WID for the currently processed property. This
    both allows to avoid the problem, and simplifies the code.
    
    Change-Id: Idd451fa1e53806cdb6b9064dec31e9171d14d5d9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153384
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit b8ccf3dacb19e157d9b2c35cc2b083cb39e76da0)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153422
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf155945.docx 
b/sw/qa/extras/ooxmlexport/data/tdf155945.docx
new file mode 100644
index 000000000000..9858ac711790
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf155945.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
index 2a4e3ee83a4f..ae45bc3376ac 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
@@ -1006,6 +1006,17 @@ DECLARE_OOXMLEXPORT_TEST(testTdf131722, "tdf131722.docx")
     }
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf155945)
+{
+    createSwDoc("tdf155945.docx");
+
+    CPPUNIT_ASSERT_EQUAL(3, getParagraphs());
+    // Without a fix in place, this would fail with
+    // - Expected: 0
+    // - Actual  : 423
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(2), 
"ParaBottomMargin"));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unoobj.cxx 
b/sw/source/core/unocore/unoobj.cxx
index ccbcc536a75e..55baec88c7ea 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -1927,6 +1927,7 @@ void SwUnoCursorHelper::SetPropertyValues(
 
     // Build set of attributes we want to fetch
     WhichRangesContainer aRanges;
+    std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> 
aSideEffectsEntries;
     std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> 
aEntries;
     aEntries.reserve(aPropertyValues.size());
     for (const auto& rPropVal : aPropertyValues)
@@ -1947,39 +1948,44 @@ void SwUnoCursorHelper::SetPropertyValues(
             aPropertyVetoExMsg += "Property is read-only: '" + rPropertyName + 
"' ";
             continue;
         }
-        aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID);
-        aEntries.emplace_back(pEntry, rPropVal.Value);
+        if (propertyCausesSideEffectsInNodes(pEntry->nWID))
+        {
+            aSideEffectsEntries.emplace_back(pEntry, rPropVal.Value);
+        }
+        else
+        {
+            aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID);
+            aEntries.emplace_back(pEntry, rPropVal.Value);
+        }
+    }
+
+    // Entries with side effects first, using dedicated one-element SfxItemSet 
for each
+    for (const auto& [pEntry, rValue] : aSideEffectsEntries)
+    {
+        SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID);
+        // we need to get up-to-date item set from nodes
+        SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
+        // this can set some attributes in nodes' mpAttrSet
+        if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, 
aItemSet))
+            rPropSet.setPropertyValue(*pEntry, rValue, aItemSet);
+        SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false 
/*bTableMode*/);
     }
 
     if (!aEntries.empty())
     {
         // Fetch, overwrite, and re-set the attributes from the core
         SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aRanges));
+        // we need to get up-to-date item set from nodes
+        SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
 
-        bool bPreviousPropertyCausesSideEffectsInNodes = false;
-        for (size_t i = 0; i < aEntries.size(); ++i)
+        for (const auto& [pEntry, rValue] : aEntries)
         {
-            SfxItemPropertyMapEntry const*const pEntry = aEntries[i].first;
-            bool bPropertyCausesSideEffectsInNodes =
-                propertyCausesSideEffectsInNodes(pEntry->nWID);
-
-            // we need to get up-to-date item set from nodes
-            if (i == 0 || bPreviousPropertyCausesSideEffectsInNodes)
-            {
-                aItemSet.ClearItem();
-                SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
-            }
-
-            const uno::Any &rValue = aEntries[i].second;
             // this can set some attributes in nodes' mpAttrSet
             if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, 
rPaM, aItemSet))
                 rPropSet.setPropertyValue(*pEntry, rValue, aItemSet);
-
-            if (i + 1 == aEntries.size() || bPropertyCausesSideEffectsInNodes)
-                SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, 
false/*bTableMode*/);
-
-            bPreviousPropertyCausesSideEffectsInNodes = 
bPropertyCausesSideEffectsInNodes;
         }
+
+        SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false 
/*bTableMode*/);
     }
 
     if (!aUnknownExMsg.isEmpty())

Reply via email to