sw/qa/extras/ooxmlexport/ooxmlexport10.cxx | 3 ++ sw/source/filter/ww8/docxattributeoutput.cxx | 21 ++++++++++++++ writerfilter/source/dmapper/DomainMapper_Impl.cxx | 31 ++++++++++++++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-)
New commits: commit 1d12d12598927ef8a74dd648632112ceb16bdf78 Author: Justin Luth <justin.l...@collabora.com> AuthorDate: Thu Apr 13 10:59:29 2023 -0400 Commit: Justin Luth <jl...@mail.com> CommitDate: Sun Apr 16 03:50:57 2023 +0200 tdf#154703 DOCX {im,ex}port framePr: adjust framesize by para spacing The specified frame size does not seem to account for left and right paragraph border spacing. At first I assumed it was just RTF, but DOCX needed it as well. This is all VERY nasty. In practice, the paragraph border spacing normally matches the frame's border spacing, but not necessarily. Plus, the user might have interferred. MS Word must know that this is a special kind of frame. LO doesn't. To handle this properly, LO frame UI would need to adjust ALL of the paragraphs' border properties when any changes are made to the frame. For the present, we have to import the frame properly, and export as well as possible. RTF export is losing paragraph borders already, so it has been excluded from consideration. No other unit tests were found that had a significant border spacing. make CppunitTest_sw_ooxmlexport10 CPPUNIT_TEST_NAME=testLibreOfficeHang Change-Id: I03d801ff0ec3c2b93a77761da8ad1f43aeaacf42 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150357 Tested-by: Jenkins Reviewed-by: Justin Luth <jl...@mail.com> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx index 3b9e420119a5..5a886f6907ee 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx @@ -526,6 +526,9 @@ DECLARE_OOXMLEXPORT_TEST(testLibreOfficeHang, "frame-wrap-auto.docx") nPara = getProperty<sal_Int32>(getParagraphOfText(1, xText), "LeftBorderDistance"); CPPUNIT_ASSERT_EQUAL(nFrame, nPara); CPPUNIT_ASSERT(nPara); + + // Additionally, the width of the frame needs to grow by the size of the left/right spacing + CPPUNIT_ASSERT_EQUAL(sal_Int32(7064), getProperty<sal_Int32>(getShape(1), "Width")); } DECLARE_OOXMLEXPORT_TEST(testI124106, "i124106.docx") diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index d83cc1cdcc63..093ace109ddb 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -908,7 +908,26 @@ void DocxAttributeOutput::PopulateFrameProperties(const SwFrameFormat* pFrameFor const SwFormatVertOrient& rVertOrient = pFrameFormat->GetVertOrient(); awt::Point aPos(rHoriOrient.GetPos(), rVertOrient.GetPos()); - attrList->add( FSNS( XML_w, XML_w), OString::number(rSize.Width())); + // A few assumptions need to be made here, because framePr is a confused mixture + // of (multiple) paragraph's border properties being transferred to/from a frame. + // The frame size describes the size BEFORE the PARAGRAPH border spacing is applied. + // However, we can't actually look at all the paragraphs' borders because they might be + // different, and all MUST specify the same frame width in order to belong to the same frame. + // In order for them all to be consistent, the only choice is to use the frame's border spacing. + // During import, the frame was assigned border spacing based on the contained paragraphs. + // So now at export time we have to assume that none of this has been changed by the user. + + // 620 (31pt) is the maximum paragraph border spacing allowed in MS Formats, + // so if the value is greater than that, avoid adjusting the size - the user has interferred. + const sal_uInt32 nLeftBorderSpacing = pFrameFormat->GetBox().GetDistance(SvxBoxItemLine::LEFT); + const sal_uInt32 nRighttBorderSpacing = pFrameFormat->GetBox().GetDistance(SvxBoxItemLine::RIGHT); + sal_uInt32 nAdjustedWidth = rSize.Width(); + if (nLeftBorderSpacing < 621 && nRighttBorderSpacing < 621 + && nAdjustedWidth > nLeftBorderSpacing + nRighttBorderSpacing) + { + nAdjustedWidth -= nLeftBorderSpacing + nRighttBorderSpacing; + } + attrList->add( FSNS( XML_w, XML_w), OString::number(nAdjustedWidth)); attrList->add( FSNS( XML_w, XML_h), OString::number(rSize.Height())); attrList->add( FSNS( XML_w, XML_x), OString::number(aPos.X)); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 068347f52347..3bca3186ca82 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -1554,6 +1554,21 @@ static void lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& r PROP_BOTTOM_BORDER_DISTANCE }; + // The frame width specified does not include border spacing, + // so the frame needs to be increased by the left/right para border spacing amount + sal_Int32 nWidth = 0; + sal_Int32 nIndexOfWidthProperty = -1; + sal_Int16 nType = text::SizeType::FIX; + for (size_t i = 0; nType == text::SizeType::FIX && i < rFrameProperties.size(); ++i) + { + if (rFrameProperties[i].Name == "WidthType") + rFrameProperties[i].Value >>= nType; + else if (rFrameProperties[i].Name == "Width") + nIndexOfWidthProperty = i; + } + if (nIndexOfWidthProperty > -1 && nType == text::SizeType::FIX) + rFrameProperties[nIndexOfWidthProperty].Value >>= nWidth; + for( size_t nProperty = 0; nProperty < SAL_N_ELEMENTS( aBorderProperties ); ++nProperty) { OUString sPropertyName = getPropertyName(aBorderProperties[nProperty]); @@ -1562,11 +1577,23 @@ static void lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& r aValue.Value = xTextRangeProperties->getPropertyValue(sPropertyName); if( nProperty < 4 ) xTextRangeProperties->setPropertyValue( sPropertyName, uno::Any(table::BorderLine2())); - else if (nProperty > 5 || bIsRTFImport) + else // border spacing { + sal_Int32 nDistance = 0; + aValue.Value >>= nDistance; + // left4/right5 need to be duplicated because of INVERT_BORDER_SPACING (DOCX only) // Do not duplicate the top6/bottom7 border spacing. - aValue.Value <<= sal_Int32(0); + if (nProperty > 5 || bIsRTFImport) + aValue.Value <<= sal_Int32(0); + + // frames need to be increased by the left/right para border spacing amount + // This is needed for RTF as well, but that requires other export/import fixes. + if (!bIsRTFImport && nProperty < 6 && nWidth && nDistance) + { + nWidth += nDistance; + rFrameProperties[nIndexOfWidthProperty].Value <<= nWidth; + } } if (aValue.Value.hasValue()) rFrameProperties.push_back(aValue);