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

Reply via email to