sw/inc/IDocumentSettingAccess.hxx | 2 + sw/qa/core/layout/flycnt.cxx | 6 +-- sw/qa/extras/layout/data/tdf155229_row_height_at_least.docx |binary sw/qa/extras/layout/layout3.cxx | 13 +++++++ sw/qa/extras/ooxmlexport/data/lost-footer-style.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport5.cxx | 15 ++++++++ sw/source/core/doc/DocumentSettingManager.cxx | 13 ++++++- sw/source/core/inc/DocumentSettingManager.hxx | 1 sw/source/core/layout/tabfrm.cxx | 10 +++++ sw/source/filter/ww8/wrtw8sty.cxx | 22 ++++++++---- sw/source/filter/ww8/ww8par.cxx | 3 + sw/source/uibase/uno/SwXDocumentSettings.cxx | 18 +++++++++ sw/source/writerfilter/dmapper/DomainMapper.cxx | 2 + 13 files changed, 93 insertions(+), 12 deletions(-)
New commits: commit 32b667acd665ce9e66ec6db952e1effb7b4c1031 Author: Miklos Vajna <[email protected]> AuthorDate: Fri Aug 30 12:18:32 2024 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Aug 30 15:47:53 2024 +0200 tdf#162707 DOCX export: fix lost paragraph styles with many numberings Open the bugdoc, style of the only para of the only footer is Footer, save as DOCX, reopen, style changes from Footer to Default. What seems to happen is that the document has too many numberings, and each numbering has 9 levels, so if we have a char style for each level, that easily runs into the MSWORD_MAX_STYLES_LIMIT limit, after which we silently start dropping styles during export. Fix the problem by tweaking the fix done in commit 7376a47680b65cbdfd747a736f288e06f51f7f2d (tdf#92335 DOCX: fix multiplying of "ListLabel" styles, 2019-05-28): if we don't just avoid writing those ListLabel styles (where the real info is written as a non-style in numbering.xml, so no formatting is list) but we filter them out earlier, then MSWordStyles::BuildStylesTable() will count styles correctly and we'll still have space for the lost Footer style. Regression from commit f9c8d97d82a85b897520a2fe897352ee5ad879d9 (tdf#95213 DOCX import: don't reuse list label styles, 2016-01-07). Change-Id: I7a6b0b7b5a7b3c813a844c5fd185cf2f419e1a5c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172647 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins diff --git a/sw/qa/extras/ooxmlexport/data/lost-footer-style.docx b/sw/qa/extras/ooxmlexport/data/lost-footer-style.docx new file mode 100644 index 000000000000..ed9db77a7121 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/lost-footer-style.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx index 6b91c7814321..019331df8a93 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -700,6 +700,21 @@ CPPUNIT_TEST_FIXTURE(Test, testfdo79968_sldx) u"PowerPoint.Slide.12"_ustr); } +CPPUNIT_TEST_FIXTURE(Test, testLostFooterStyle) +{ + // Given a document with many numberings and a Footer para style: + loadAndSave("lost-footer-style.docx"); + + // When saving that to DOCX and checking the Footer style: + xmlDocUniquePtr pXmlDoc = parseExport(u"word/styles.xml"_ustr); + // Without the accompanying fix in place, this test would have failed, the Footer style was + // lost on export due to the many ListLabel char styles. + OUString aType = getXPath(pXmlDoc, "/w:styles/w:style[@w:styleId='Footer']"_ostr, "type"_ostr); + + // Then make sure we have a Footer para style: + CPPUNIT_ASSERT_EQUAL(u"paragraph"_ustr, aType); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index 6cbc2702e02d..39ab72c1fbc3 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -320,7 +320,22 @@ void MSWordStyles::BuildStylesTable() const SwCharFormats& rArr = *m_rExport.m_rDoc.GetCharFormats(); // first CharFormat // the default character style ( 0 ) will not be outputted ! for (size_t n = 1; n < rArr.size() && m_aStyles.size() < MSWORD_MAX_STYLES_LIMIT; ++n) + { + if (m_rExport.GetExportFormat() == MSWordExportBase::DOCX + && rArr[n]->GetName().startsWith("ListLabel")) + { + // tdf#92335 don't export redundant DOCX import style "ListLabel" + continue; + } + m_aStyles.emplace_back(rArr[n]); + } + + if (m_aStyles.size() == MSWORD_MAX_STYLES_LIMIT) + { + SAL_WARN("sw.ww8", "MSWordStyles::BuildStylesTable: too many styles, have " + << rArr.size() << " char styles"); + } const SwTextFormatColls& rArr2 = *m_rExport.m_rDoc.GetTextFormatColls(); // then TextFormatColls // the default paragraph style ( 0 ) will not be outputted ! @@ -700,13 +715,6 @@ void MSWordStyles::OutputStyle(sal_uInt16 nSlot) GetStyleData(entry.format, bFormatColl, nBase, nWwNext, nWwLink); - if (!bFormatColl && m_rExport.GetExportFormat() == MSWordExportBase::DOCX && - entry.style_id.startsWith("ListLabel")) - { - // tdf#92335 don't export redundant DOCX import style "ListLabel" - return; - } - m_rExport.AttrOutput().StartStyle(entry.ww_name, (bFormatColl ? STYLE_TYPE_PARA : STYLE_TYPE_CHAR), nBase, nWwNext, nWwLink, m_aStyles[nSlot].ww_id, nSlot, entry.format->IsAutoUpdateOnDirectFormat() ); commit 4f5b896d004af023f210f235aeafa9abc50068d2 Author: Oliver Specht <[email protected]> AuthorDate: Thu Jun 27 08:57:43 2024 +0200 Commit: Gabor Kelemen <[email protected]> CommitDate: Fri Aug 30 15:47:49 2024 +0200 tdf#155229 Calculate row height incl. border if 'atLeast' is set Word includes the width of horizontal borders when calculating row height in case the row height is set as "atLeast" This is now handled via a compat flag for doc/rtf/docx formats. The default for ODF is unspecified, which (sanely) continues to treat the row size of "atLeast" and "fixed" as measuring the same thing. Change-Id: I37778e5cdc6e083e94a17f50bd0b75a291ededcd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169611 Tested-by: Gabor Kelemen <[email protected]> Tested-by: Jenkins Reviewed-by: Gabor Kelemen <[email protected]> diff --git a/sw/inc/IDocumentSettingAccess.hxx b/sw/inc/IDocumentSettingAccess.hxx index 39bcd7efcbeb..133fd12811b7 100644 --- a/sw/inc/IDocumentSettingAccess.hxx +++ b/sw/inc/IDocumentSettingAccess.hxx @@ -135,6 +135,8 @@ enum class DocumentSettingId USE_VARIABLE_WIDTH_NBSP, // overlap background shapes if anchored in body PAINT_HELL_OVER_HEADER_FOOTER, + // tdf#155229 calculate minimum row height including horizontal border width + MIN_ROW_HEIGHT_INCL_BORDER, }; /** Provides access to settings of a document diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 397a67eb135b..3e9fcb981125 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -450,10 +450,10 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWidow) SwFrame* pTab2 = pPage2Fly->GetLower(); SwFrame* pRow2 = pTab2->GetLower(); // Without the accompanying fix in place, this test would have failed with: - // - Expected: 1014 + // - Expected: 1029 // - Actual : 553 - // i.e. <w:trHeight w:val="1014"> from the file was ignored. - CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(1014), pRow2->getFrameArea().Height()); + // i.e. <w:trHeight w:val="1029"> from the file was ignored + CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(1029), pRow2->getFrameArea().Height()); SwFrame* pCell2 = pRow2->GetLower(); auto pText2 = dynamic_cast<SwTextFrame*>(pCell2->GetLower()); // And then similarly this was 1, not 2. diff --git a/sw/qa/extras/layout/data/tdf155229_row_height_at_least.docx b/sw/qa/extras/layout/data/tdf155229_row_height_at_least.docx new file mode 100644 index 000000000000..a42031a41f5b Binary files /dev/null and b/sw/qa/extras/layout/data/tdf155229_row_height_at_least.docx differ diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx index 2ebac8b4ea17..df1d734debc3 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -3196,6 +3196,19 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf146081) CPPUNIT_ASSERT_EQUAL(nTotalHeight, nHeight1 * 4); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf155229RowAtLeast) +{ + createSwDoc("tdf155229_row_height_at_least.docx"); + + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + sal_Int32 nTableHeight + = getXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[11]/infos/bounds"_ostr, "bottom"_ostr) + .toInt32(); + + // Without the fix, this was Actual : 14174 + CPPUNIT_ASSERT_EQUAL(sal_Int32(15494), nTableHeight); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf157829LTR) { // Verify that line breaking inside a bidi portion triggers underflow to previous bidi portions diff --git a/sw/source/core/doc/DocumentSettingManager.cxx b/sw/source/core/doc/DocumentSettingManager.cxx index 52d609be2e78..adcbc033970b 100644 --- a/sw/source/core/doc/DocumentSettingManager.cxx +++ b/sw/source/core/doc/DocumentSettingManager.cxx @@ -108,7 +108,8 @@ sw::DocumentSettingManager::DocumentSettingManager(SwDoc &rDoc) mbNoNumberingShowFollowBy(false), mbDropCapPunctuation(true), mbUseVariableWidthNBSP(false), - mbPaintHellOverHeaderFooter(false) + mbPaintHellOverHeaderFooter(false), + mbMinRowHeightInclBorder(false) // COMPATIBILITY FLAGS END { @@ -268,6 +269,7 @@ bool sw::DocumentSettingManager::get(/*[in]*/ DocumentSettingId id) const case DocumentSettingId::DROP_CAP_PUNCTUATION: return mbDropCapPunctuation; case DocumentSettingId::USE_VARIABLE_WIDTH_NBSP: return mbUseVariableWidthNBSP; case DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER: return mbPaintHellOverHeaderFooter; + case DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER: return mbMinRowHeightInclBorder; default: OSL_FAIL("Invalid setting id"); } @@ -489,6 +491,10 @@ void sw::DocumentSettingManager::set(/*[in]*/ DocumentSettingId id, /*[in]*/ boo mbPaintHellOverHeaderFooter = value; break; + case DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER: + mbMinRowHeightInclBorder = value; + break; + // COMPATIBILITY FLAGS END case DocumentSettingId::BROWSE_MODE: //can be used temporary (load/save) when no SwViewShell is available @@ -1069,6 +1075,11 @@ void sw::DocumentSettingManager::dumpAsXml(xmlTextWriterPtr pWriter) const BAD_CAST(OString::boolean(mbPaintHellOverHeaderFooter).getStr())); (void)xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbMinRowHeightInclBorder")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), + BAD_CAST(OString::boolean(mbMinRowHeightInclBorder).getStr())); + (void)xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbContinuousEndnotes")); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(mbContinuousEndnotes).getStr())); diff --git a/sw/source/core/inc/DocumentSettingManager.hxx b/sw/source/core/inc/DocumentSettingManager.hxx index 4006fa51dbbe..fd40e8acf22c 100644 --- a/sw/source/core/inc/DocumentSettingManager.hxx +++ b/sw/source/core/inc/DocumentSettingManager.hxx @@ -185,6 +185,7 @@ class DocumentSettingManager final : bool mbDropCapPunctuation; // tdf#150200, tdf#150438 bool mbUseVariableWidthNBSP : 1; // tdf#41652 bool mbPaintHellOverHeaderFooter : 1; // tdf#160198 + bool mbMinRowHeightInclBorder : 1; // tdf#155229 public: diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index f88993f39d79..413fe460cb9e 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -196,6 +196,8 @@ static bool lcl_InnerCalcLayout( SwFrame *pFrame, // cell height. static SwTwips lcl_CalcMinRowHeight( const SwRowFrame *pRow, const bool _bConsiderObjs ); +static sal_uInt16 lcl_GetTopSpace( const SwRowFrame& rRow ); + static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrame&, const SwBorderAttrs& ); static SwTwips lcl_calcHeightOfRowBeforeThisFrame(const SwRowFrame& rRow); @@ -4806,6 +4808,9 @@ static SwTwips lcl_CalcMinCellHeight( const SwLayoutFrame *_pCell, static SwTwips lcl_CalcMinRowHeight( const SwRowFrame* _pRow, const bool _bConsiderObjs ) { + //calc min height including width of horizontal border + const bool bMinRowHeightInclBorder = + _pRow->GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER); SwTwips nHeight = 0; if ( !_pRow->IsRowSpanLine() ) { @@ -4847,6 +4852,11 @@ static SwTwips lcl_CalcMinRowHeight( const SwRowFrame* _pRow, { nHeight = rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*_pRow); } + if (bMinRowHeightInclBorder) + { + //get horizontal border(s) + nHeight += lcl_GetTopSpace(*_pRow); + } } } diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx index c3abc3d1b0e3..cf15871c8abc 100644 --- a/sw/source/filter/ww8/ww8par.cxx +++ b/sw/source/filter/ww8/ww8par.cxx @@ -1874,6 +1874,9 @@ void SwWW8ImplReader::ImportDop() DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND, true); m_rDoc.getIDocumentSettingAccess().set( DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, false); + // tdf#155229 calculate minimum row height including horizontal border width + m_rDoc.getIDocumentSettingAccess().set( + DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER, true); // Import Default Tabs tools::Long nDefTabSiz = m_xWDop->dxaTab; diff --git a/sw/source/uibase/uno/SwXDocumentSettings.cxx b/sw/source/uibase/uno/SwXDocumentSettings.cxx index 6ccf8849482b..99338f8894f3 100644 --- a/sw/source/uibase/uno/SwXDocumentSettings.cxx +++ b/sw/source/uibase/uno/SwXDocumentSettings.cxx @@ -161,7 +161,8 @@ enum SwDocumentSettingsPropertyHandles HANDLE_USE_VARIABLE_WIDTH_NBSP, HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, HANDLE_DO_NOT_MIRROR_RTL_DRAW_OBJS, - HANDLE_PAINT_HELL_OVER_HEADER_FOOTER + HANDLE_PAINT_HELL_OVER_HEADER_FOOTER, + HANDLE_MIN_ROW_HEIGHT_INCL_BORDER }; } @@ -270,6 +271,7 @@ static rtl::Reference<MasterPropertySetInfo> lcl_createSettingsInfo() { u"ApplyTextAttrToEmptyLineAtEndOfParagraph"_ustr, HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, cppu::UnoType<bool>::get(), 0 }, { u"DoNotMirrorRtlDrawObjs"_ustr, HANDLE_DO_NOT_MIRROR_RTL_DRAW_OBJS, cppu::UnoType<bool>::get(), 0 }, { u"PaintHellOverHeaderFooter"_ustr, HANDLE_PAINT_HELL_OVER_HEADER_FOOTER, cppu::UnoType<bool>::get(), 0 }, + { u"MinRowHeightInclBorder"_ustr, HANDLE_MIN_ROW_HEIGHT_INCL_BORDER, cppu::UnoType<bool>::get(), 0 }, /* * As OS said, we don't have a view when we need to set this, so I have to @@ -1162,6 +1164,14 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER, bTmp); } break; + case HANDLE_MIN_ROW_HEIGHT_INCL_BORDER: + { + bool bTmp; + if (rValue >>= bTmp) + mpDoc->getIDocumentSettingAccess().set( + DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER, bTmp); + } + break; default: throw UnknownPropertyException(OUString::number(rInfo.mnHandle)); } @@ -1744,6 +1754,12 @@ void SwXDocumentSettings::_getSingleValue( const comphelper::PropertyInfo & rInf DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER); } break; + case HANDLE_MIN_ROW_HEIGHT_INCL_BORDER: + { + rValue <<= mpDoc->getIDocumentSettingAccess().get( + DocumentSettingId::MIN_ROW_HEIGHT_INCL_BORDER); + } + break; default: throw UnknownPropertyException(OUString::number(rInfo.mnHandle)); } diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx b/sw/source/writerfilter/dmapper/DomainMapper.cxx index 304519470097..4dbf34fa32d4 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx @@ -152,6 +152,8 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon m_pImpl->SetDocumentSettingsProperty(u"PaintHellOverHeaderFooter"_ustr,uno::Any(true)); m_pImpl->SetDocumentSettingsProperty(u"EmptyDbFieldHidesPara"_ustr,uno::Any(false)); m_pImpl->SetDocumentSettingsProperty(u"IgnoreTabsAndBlanksForLineCalculation"_ustr,uno::Any(true)); + // calculate table row height with 'atLeast' including horizontal border width + m_pImpl->SetDocumentSettingsProperty(u"MinRowHeightInclBorder"_ustr,uno::Any(true)); } // Initialize RDF metadata, to be able to add statements during the import.
