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())