sw/source/core/unocore/unotext.cxx | 24 +++ writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx | 24 +++ writerfilter/qa/cppunittests/dmapper/data/table-style-para-border-spacing.docx |binary writerfilter/source/dmapper/DomainMapper.cxx | 67 +++++++--- writerfilter/source/dmapper/DomainMapperTableHandler.cxx | 48 ++++++- writerfilter/source/dmapper/PropertyIds.cxx | 27 ++-- writerfilter/source/dmapper/PropertyIds.hxx | 12 + 7 files changed, 171 insertions(+), 31 deletions(-)
New commits: commit 86a5e47b07d5b8140434d24f74230eacaac16bd4 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jun 11 10:49:29 2024 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Thu Jun 13 10:57:22 2024 +0200 tdf#161443 DOCX import, table style: handle para border in table cell paras Open the bugdoc, the in-table paragraphs have some top and bottom paragraph borders in Word, not in Writer -- because the cell and paragraph UNO object both have a property named TopBorder as mentioned in commit 39c54c0ef837e0e23a676a4d1fa5da667e18939c (tdf#161443 DOCX import, table style: fix para border leaking into cell border, 2024-06-07). The previous fix avoided the problem that the unwanted border affects, the cell, but re-routing the property to affect the in-table paragraph were not done. Fix the problem by adding 3 new meta-properties with a "Para" prefix for all 4 border locations (top/left/bottom/right), this way the paragraph borders defined in a table style can affect the in-table paragraphs, but not the table cells. Apart from the border itself, this also affected the border spacing, which means that the position of all text inside and below the table is now also correct. Unfortunately this also means we need to move away from the constexpr frozen container that is only suitable for a limited number of items: sw/source/writerfilter/dmapper/PropertyIds.cxx:394:6: error: ‘constexpr’ evaluation operation count exceeds limit of 33554432 (use ‘-fconstexpr-ops-limit=’ to increase the limit) Returning to std::unordered_map is good enough for our needs. (cherry picked from commit 013300c751d7a9ede12c1bf1c784254d1c6c5433) Change-Id: I478f274800a1d0b200f10226438ab4cfd4957b74 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168696 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> (cherry picked from commit dded9c034bd1be2fdac41923ec0724e52505d40b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168711 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx index 3f720e452f15..30b89a06e0c4 100644 --- a/sw/source/core/unocore/unotext.cxx +++ b/sw/source/core/unocore/unotext.cxx @@ -2113,6 +2113,18 @@ lcl_ApplyCellProperties( { static const std::initializer_list<std::u16string_view> vDenylist = { u"LeftMargin", + u"ParaTopBorder", + u"ParaTopBorderDistance", + u"ParaTopBorderComplexColor", + u"ParaLeftBorder", + u"ParaLeftBorderDistance", + u"ParaLeftBorderComplexColor", + u"ParaBottomBorder", + u"ParaBottomBorderDistance", + u"ParaBottomBorderComplexColor", + u"ParaRightBorder", + u"ParaRightBorderDistance", + u"ParaRightBorderComplexColor", }; if (std::find(vDenylist.begin(), vDenylist.end(), rName) == vDenylist.end()) { @@ -2251,6 +2263,18 @@ SwXText::convertToTable( u"RightBorder", u"TopBorder", u"VerticalBorder", + u"ParaTopBorder", + u"ParaTopBorderDistance", + u"ParaTopBorderComplexColor", + u"ParaLeftBorder", + u"ParaLeftBorderDistance", + u"ParaLeftBorderComplexColor", + u"ParaBottomBorder", + u"ParaBottomBorderDistance", + u"ParaBottomBorderComplexColor", + u"ParaRightBorder", + u"ParaRightBorderDistance", + u"ParaRightBorderComplexColor", }; if (std::find(vDenylist.begin(), vDenylist.end(), rTableProperty.Name) == vDenylist.end()) { diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx index 5924fb90bc2a..7f7cfd9b008b 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx @@ -229,6 +229,30 @@ CPPUNIT_TEST_FIXTURE(Test, testDOCXFloatingTableHeaderBodyOverlap) // Fly bottom was 3063, body text top was 7148. CPPUNIT_ASSERT_LESS(nBodyTextTop, nFlyBottom); } + +CPPUNIT_TEST_FIXTURE(Test, testTableStyleParaBorderSpacing) +{ + // Given a document with a table style, table style defines top and bottom border for + // paragraphs: + // When loading that document: + loadFromFile(u"table-style-para-border-spacing.docx"); + + // Then make sure the in-table paragraph gets its top border: + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xText(xTextDocument->getText(), uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParaEnum = xText->createEnumeration(); + uno::Reference<text::XTextTable> xPara(xParaEnum->nextElement(), uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xCell(xPara->getCellByName("A1"), uno::UNO_QUERY); + xParaEnum = xCell->createEnumeration(); + uno::Reference<beans::XPropertySet> xParaProps(xParaEnum->nextElement(), uno::UNO_QUERY); + sal_Int32 nTopBorderDistance{}; + xParaProps->getPropertyValue("TopBorderDistance") >>= nTopBorderDistance; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 35 + // - Actual : 0 + // i.e. the top and bottom border and its 1pt spacing was not set on the in-table paragraph. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(35), nTopBorderDistance); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/qa/cppunittests/dmapper/data/table-style-para-border-spacing.docx b/writerfilter/qa/cppunittests/dmapper/data/table-style-para-border-spacing.docx new file mode 100644 index 000000000000..b8382000b2b5 Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/table-style-para-border-spacing.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 0c2cb13a3185..36fb00408ddb 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1610,34 +1610,65 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) PropertyIds eBorderDistId = PropertyIds::INVALID; const StyleSheetEntryPtr& pEntry = GetStyleSheetTable()->GetCurrentEntry(); - if (pEntry && pEntry->m_nStyleTypeCode == STYLE_TYPE_TABLE) - { - // This would map para borders in table style to cell borders, avoid that till we - // have separate property names for these. - break; - } + bool bInTableStyle = pEntry && pEntry->m_nStyleTypeCode == STYLE_TYPE_TABLE; switch( nSprmId ) { case NS_ooxml::LN_CT_PBdr_top: - eBorderId = PROP_TOP_BORDER; - eBorderComplexColorId = PROP_BORDER_TOP_COMPLEX_COLOR; - eBorderDistId = PROP_TOP_BORDER_DISTANCE; + if (bInTableStyle) + { + eBorderId = PROP_PARA_TOP_BORDER; + eBorderComplexColorId = PROP_PARA_BORDER_TOP_COMPLEX_COLOR; + eBorderDistId = PROP_PARA_TOP_BORDER_DISTANCE; + } + else + { + eBorderId = PROP_TOP_BORDER; + eBorderComplexColorId = PROP_BORDER_TOP_COMPLEX_COLOR; + eBorderDistId = PROP_TOP_BORDER_DISTANCE; + } break; case NS_ooxml::LN_CT_PBdr_left: - eBorderId = PROP_LEFT_BORDER; - eBorderComplexColorId = PROP_BORDER_LEFT_COMPLEX_COLOR; - eBorderDistId = PROP_LEFT_BORDER_DISTANCE; + if (bInTableStyle) + { + eBorderId = PROP_PARA_LEFT_BORDER; + eBorderComplexColorId = PROP_PARA_BORDER_LEFT_COMPLEX_COLOR; + eBorderDistId = PROP_PARA_LEFT_BORDER_DISTANCE; + } + else + { + eBorderId = PROP_LEFT_BORDER; + eBorderComplexColorId = PROP_BORDER_LEFT_COMPLEX_COLOR; + eBorderDistId = PROP_LEFT_BORDER_DISTANCE; + } break; case NS_ooxml::LN_CT_PBdr_bottom: - eBorderId = PROP_BOTTOM_BORDER; - eBorderComplexColorId = PROP_BORDER_BOTTOM_COMPLEX_COLOR; - eBorderDistId = PROP_BOTTOM_BORDER_DISTANCE; + if (bInTableStyle) + { + eBorderId = PROP_PARA_BOTTOM_BORDER; + eBorderComplexColorId = PROP_PARA_BORDER_BOTTOM_COMPLEX_COLOR; + eBorderDistId = PROP_PARA_BOTTOM_BORDER_DISTANCE; + } + else + { + eBorderId = PROP_BOTTOM_BORDER; + eBorderComplexColorId = PROP_BORDER_BOTTOM_COMPLEX_COLOR; + eBorderDistId = PROP_BOTTOM_BORDER_DISTANCE; + } break; case NS_ooxml::LN_CT_PBdr_right: - eBorderId = PROP_RIGHT_BORDER; - eBorderComplexColorId = PROP_BORDER_RIGHT_COMPLEX_COLOR; - eBorderDistId = PROP_RIGHT_BORDER_DISTANCE; + if (bInTableStyle) + { + eBorderId = PROP_PARA_RIGHT_BORDER; + eBorderComplexColorId = PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR; + eBorderDistId = PROP_PARA_RIGHT_BORDER_DISTANCE; + } + else + { + eBorderId = PROP_RIGHT_BORDER; + eBorderComplexColorId = PROP_BORDER_RIGHT_COMPLEX_COLOR; + eBorderDistId = PROP_RIGHT_BORDER_DISTANCE; + } break; case NS_ooxml::LN_CT_PBdr_between: if (m_pImpl->handlePreviousParagraphBorderInBetween()) diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx index 0ecc6701551a..1a25f2c856aa 100644 --- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -1091,7 +1091,7 @@ void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParag std::vector<beans::PropertyValue> aProps; std::optional<OUString> oParagraphText; - for( auto const& eId : aAllTableParaProperties ) + for( auto eId : aAllTableParaProperties ) { // apply paragraph and character properties of the table style on table paragraphs // if there is no direct paragraph formatting @@ -1105,7 +1105,51 @@ void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParag continue; } + PropertyIds eMappedId = eId; + switch (eId) + { + case PROP_PARA_TOP_BORDER: + eMappedId = PROP_TOP_BORDER; + break; + case PROP_PARA_TOP_BORDER_DISTANCE: + eMappedId = PROP_TOP_BORDER_DISTANCE; + break; + case PROP_PARA_BORDER_TOP_COMPLEX_COLOR: + eMappedId = PROP_BORDER_TOP_COMPLEX_COLOR; + break; + case PROP_PARA_LEFT_BORDER: + eMappedId = PROP_LEFT_BORDER; + break; + case PROP_PARA_LEFT_BORDER_DISTANCE: + eMappedId = PROP_LEFT_BORDER_DISTANCE; + break; + case PROP_PARA_BORDER_LEFT_COMPLEX_COLOR: + eMappedId = PROP_BORDER_LEFT_COMPLEX_COLOR; + break; + case PROP_PARA_BOTTOM_BORDER: + eMappedId = PROP_BOTTOM_BORDER; + break; + case PROP_PARA_BOTTOM_BORDER_DISTANCE: + eMappedId = PROP_BOTTOM_BORDER_DISTANCE; + break; + case PROP_PARA_BORDER_BOTTOM_COMPLEX_COLOR: + eMappedId = PROP_BORDER_BOTTOM_COMPLEX_COLOR; + break; + case PROP_PARA_RIGHT_BORDER: + eMappedId = PROP_RIGHT_BORDER; + break; + case PROP_PARA_RIGHT_BORDER_DISTANCE: + eMappedId = PROP_RIGHT_BORDER_DISTANCE; + break; + case PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR: + eMappedId = PROP_BORDER_RIGHT_COMPLEX_COLOR; + break; + default: + break; + } + OUString sPropertyName = getPropertyName(eId); + OUString sMappedPropertyName = getPropertyName(eMappedId); auto pCellProp = std::find_if(rCellProperties.begin(), rCellProperties.end(), [&](const beans::PropertyValue& rProp) { return rProp.Name == sPropertyName; }); @@ -1168,7 +1212,7 @@ void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParag if (!aParaStyle.hasValue() || bDocDefault || bCompatOverride) try { // apply style setting when the paragraph doesn't modify it - aProps.push_back(comphelper::makePropertyValue(sPropertyName, pCellProp->Value)); + aProps.push_back(comphelper::makePropertyValue(sMappedPropertyName, pCellProp->Value)); if (eId == PROP_FILL_COLOR) { // we need this for complete import of table-style based paragraph background color diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx index b8b4efc06222..0b599a0a4a28 100644 --- a/writerfilter/source/dmapper/PropertyIds.cxx +++ b/writerfilter/source/dmapper/PropertyIds.cxx @@ -18,16 +18,13 @@ */ #include <rtl/ustring.hxx> #include "PropertyIds.hxx" -#include <frozen/bits/defines.h> -#include <frozen/bits/elsa_std.h> -#include <frozen/unordered_map.h> +#include <unordered_map> namespace writerfilter::dmapper{ -namespace +OUString getPropertyName( PropertyIds eId ) { - constexpr auto constPropertyMap = frozen::make_unordered_map<PropertyIds, std::u16string_view>( - { + static const std::unordered_map<PropertyIds, std::u16string_view> constPropertyMap { { PROP_CHAR_WEIGHT, u"CharWeight"}, { PROP_CHAR_POSTURE, u"CharPosture"}, { PROP_CHAR_STRIKEOUT, u"CharStrikeout"}, @@ -106,6 +103,18 @@ namespace { PROP_PARA_IS_HANGING_PUNCTUATION, u"ParaIsHangingPunctuation"}, { PROP_PARA_LINE_SPACING, u"ParaLineSpacing"}, { PROP_PARA_TAB_STOPS, u"ParaTabStops"}, + { PROP_PARA_TOP_BORDER, u"ParaTopBorder"}, + { PROP_PARA_TOP_BORDER_DISTANCE, u"ParaTopBorderDistance"}, + { PROP_PARA_BORDER_TOP_COMPLEX_COLOR, u"ParaTopBorderComplexColor"}, + { PROP_PARA_LEFT_BORDER, u"ParaLeftBorder"}, + { PROP_PARA_LEFT_BORDER_DISTANCE, u"ParaLeftBorderDistance"}, + { PROP_PARA_BORDER_LEFT_COMPLEX_COLOR, u"ParaLeftBorderComplexColor"}, + { PROP_PARA_BOTTOM_BORDER, u"ParaBottomBorder"}, + { PROP_PARA_BOTTOM_BORDER_DISTANCE, u"ParaBottomBorderDistance"}, + { PROP_PARA_BORDER_BOTTOM_COMPLEX_COLOR, u"ParaBottomBorderComplexColor"}, + { PROP_PARA_RIGHT_BORDER, u"ParaRightBorder"}, + { PROP_PARA_RIGHT_BORDER_DISTANCE, u"ParaRightBorderDistance"}, + { PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR, u"ParaRightBorderComplexColor"}, { PROP_PARA_WIDOWS, u"ParaWidows"}, { PROP_PARA_ORPHANS, u"ParaOrphans"}, { PROP_PARA_LINE_NUMBER_START_VALUE, u"ParaLineNumberStartValue"}, @@ -384,11 +393,7 @@ namespace { PROP_PARA_CONNECT_BORDERS, u"ParaIsConnectBorder"}, { PROP_DECORATIVE, u"Decorative"}, { PROP_PAPER_TRAY, u"PrinterPaperTray"}, - }); -} // end anonymous ns - -OUString getPropertyName( PropertyIds eId ) -{ + }; auto iterator = constPropertyMap.find(eId); if (iterator != constPropertyMap.end()) return OUString(iterator->second); diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx index b39fcd24fa49..ba62c34000ed 100644 --- a/writerfilter/source/dmapper/PropertyIds.hxx +++ b/writerfilter/source/dmapper/PropertyIds.hxx @@ -261,6 +261,18 @@ enum PropertyIds ,PROP_PARA_TAB_STOPS ,PROP_PARA_TOP_MARGIN ,PROP_PARA_VERT_ALIGNMENT + ,PROP_PARA_TOP_BORDER + ,PROP_PARA_TOP_BORDER_DISTANCE + ,PROP_PARA_BORDER_TOP_COMPLEX_COLOR + ,PROP_PARA_LEFT_BORDER + ,PROP_PARA_LEFT_BORDER_DISTANCE + ,PROP_PARA_BORDER_LEFT_COMPLEX_COLOR + ,PROP_PARA_BOTTOM_BORDER + ,PROP_PARA_BOTTOM_BORDER_DISTANCE + ,PROP_PARA_BORDER_BOTTOM_COMPLEX_COLOR + ,PROP_PARA_RIGHT_BORDER + ,PROP_PARA_RIGHT_BORDER_DISTANCE + ,PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR ,PROP_PARA_WIDOWS ,PROP_PAPER_TRAY ,PROP_PARENT_NUMBERING