sw/qa/extras/ooxmlexport/ooxmlexport10.cxx        |    2 
 sw/qa/extras/ooxmlexport/ooxmlexport12.cxx        |    2 
 sw/source/filter/ww8/docxattributeoutput.cxx      |   59 +++++++++++++++++++---
 sw/source/filter/ww8/docxattributeoutput.hxx      |    8 ++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |    7 +-
 5 files changed, 65 insertions(+), 13 deletions(-)

New commits:
commit 02c902bde09984a87f19ac0eb63942724056c982
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Tue Apr 11 11:19:56 2023 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Fri Apr 14 03:13:23 2023 +0200

    tdf#154703 docx export framePr: merge para/frame FormatBox
    
    Now that export knows about both frame and para border spacing,
    we can remove an import hack.
    
    When exporting the paragraph properties, not only do the direct
    border settings and the paragraph styles settings apply,
    but also (uniquely for framePr) do the frame properties.
    
    The most significant property is the border spacing.
    On import only the paragraph keeps the spacing
    (with the purpose of keeping paragraph shading looking right)
    and the frames itself has no border spacing.
    [That is also good, because the frame size
     is specified as the size without border spacing,
     and LO does not expand the frame when borders spacing is added.]
    
    One exception of course is if the user adds spacing during editing.
    Another (theoretical) situation comes during an ODT->DOCX export.
    
    Fortunately, both of these situations should be handled by just
    adding the frame and paragraph properties together.
    It is emulation, but it seems to work pretty good.
    
    I modified the unit test from
    7.1 commit 49e2bd6103669ca94d4e308fc08beed57f85c7e2
    Author: Tibor Nagy on Mon Aug 10 10:51:20 2020 +0200
        tdf#131420 DOCX export: fix missing border of frame
    because we should _not_ have two pBdr entries,
    just one, non-empty entry.
    
    Table import and export are already a mess.
    See ooxmpexort5's fdo 60957-2.docx for a great example,
    and tdf104394_lostTextbox.docx is also fascinatingly complex.
    
    Change-Id: I011100ee2790de6b8573d6a8bc99b9455f65e76d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150242
    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 4ed28d57f88d..3b9e420119a5 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -520,7 +520,7 @@ DECLARE_OOXMLEXPORT_TEST(testLibreOfficeHang, 
"frame-wrap-auto.docx")
 
     sal_Int32 nFrame = getProperty<sal_Int32>(getShape(1), 
"TopBorderDistance");
     sal_Int32 nPara = getProperty<sal_Int32>(getParagraphOfText(1, xText), 
"TopBorderDistance");
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(143), nFrame + nPara);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(141), nFrame + nPara);
     // NOTE: left/right are different because of compat flag 
INVERT_BORDER_SPACING]
     nFrame = getProperty<sal_Int32>(getShape(1), "LeftBorderDistance");
     nPara = getProperty<sal_Int32>(getParagraphOfText(1, xText), 
"LeftBorderDistance");
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx
index d5ca8435b82b..d7b24692d2a7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport12.cxx
@@ -1138,7 +1138,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf131420)
 {
     loadAndSave("tdf131420.docx");
     xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
-    assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:pPr/w:pBdr[2]");
+    assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:pPr/w:pBdr/w:top");
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf80526_word_wrap, "tdf80526_word_wrap.docx")
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 1d9bde3f2ba4..0f34bc7b645b 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -575,16 +575,26 @@ OString 
DocxAttributeOutput::convertToOOXMLHoriOrientRel(sal_Int16 nOrientRel)
     }
 }
 
-void FramePrHelper::SetFrame(ww8::Frame* pFrame)
+void FramePrHelper::SetFrame(ww8::Frame* pFrame, sal_Int32 nTableDepth)
 {
     assert(!pFrame || !m_pFrame);
     m_pFrame = pFrame;
+    m_nTableDepth = nTableDepth;
     if (m_pFrame)
     {
+        m_bUseFrameBorders = true;
         m_bUseFrameBackground = true;
     }
 }
 
+bool FramePrHelper::UseFrameBorders(sal_Int32 nTableDepth)
+{
+    if (!m_pFrame || m_nTableDepth < nTableDepth)
+        return false;
+
+    return m_bUseFrameBorders;
+}
+
 bool FramePrHelper::UseFrameBackground()
 {
     if (!m_pFrame)
@@ -1117,7 +1127,7 @@ void DocxAttributeOutput::EndParagraph( 
ww8::WW8TableNodeInfoInner::Pointer_t pT
     for ( const auto & pFrame : aFramePrTextbox )
     {
         DocxTableExportContext aTableExportContext(*this);
-        m_aFramePr.SetFrame(pFrame.get());
+        m_aFramePr.SetFrame(pFrame.get(), !m_xTableWrt ? -1 : 
m_tableReference.m_nTableDepth);
         m_rExport.SdrExporter().writeOnlyTextOfFrame(pFrame.get());
         m_aFramePr.SetFrame(nullptr);
     }
@@ -1503,7 +1513,10 @@ void DocxAttributeOutput::EndParagraphProperties(const 
SfxItemSet& rParagraphMar
 
         const Size aSize = m_aFramePr.Frame()->GetSize();
         PopulateFrameProperties(&rFrameFormat, aSize);
-        FormatBox(rFrameFormat.GetBox());
+
+        // if the paragraph itself never called FormatBox, do so now
+        if (m_aFramePr.UseFrameBorders(!m_xTableWrt ? -1 : 
m_tableReference.m_nTableDepth))
+            FormatBox(rFrameFormat.GetBox());
 
         if (m_aFramePr.UseFrameBackground())
         {
@@ -1522,7 +1535,9 @@ void DocxAttributeOutput::EndParagraphProperties(const 
SfxItemSet& rParagraphMar
                 }
             }
         }
+
         // reset to true in preparation for the next paragraph in the frame
+        m_aFramePr.SetUseFrameBorders(true);
         m_aFramePr.SetUseFrameBackground(true);
     }
 
@@ -4163,7 +4178,8 @@ static void impl_borders( FSHelperPtr const & pSerializer,
                           const SvxBoxItem& rBox,
                           const OutputBorderOptions& rOptions,
                           std::map<SvxBoxItemLine,
-                          css::table::BorderLine2> &rTableStyleConf )
+                          css::table::BorderLine2> &rTableStyleConf,
+                          ww8::Frame* pFramePr = nullptr)
 {
     static const SvxBoxItemLine aBorders[] =
     {
@@ -4243,6 +4259,34 @@ static void impl_borders( FSHelperPtr const & 
pSerializer,
             }
         }
 
+        if (pFramePr)
+        {
+            assert(rOptions.bWriteDistance && !rOptions.pDistances);
+
+            // In addition to direct properties, and paragraph styles,
+            // for framePr-floated paragraphs the frame borders also affect 
the exported values.
+
+            // For border spacing, there is a special situation to consider
+            // because a compat setting ignores left/right paragraph spacing 
on layout.
+            const SwFrameFormat& rFormat = pFramePr->GetFrameFormat();
+            const SvxBoxItem& rFramePrBox = rFormat.GetBox();
+            const IDocumentSettingAccess& rIDSA = 
rFormat.GetDoc()->getIDocumentSettingAccess();
+            if (rIDSA.get(DocumentSettingId::INVERT_BORDER_SPACING)
+                && (*pBrd == SvxBoxItemLine::LEFT || *pBrd == 
SvxBoxItemLine::RIGHT))
+            {
+                // only the frame's border spacing affects layout - so use 
that value instead.
+                nDist = rFramePrBox.GetDistance(*pBrd);
+            }
+            else
+            {
+                nDist += rFramePrBox.GetDistance(*pBrd);
+            }
+
+            // Unless the user added a paragraph border, the border normally 
comes from the frame.
+            if (!pLn)
+                pLn = rFramePrBox.GetLine(*pBrd);
+        }
+
         impl_borderLine( pSerializer, aXmlElements[i], pLn, nDist, 
bWriteShadow, aStyleProps );
     }
     if (tagWritten && rOptions.bWriteTag) {
@@ -9518,11 +9562,14 @@ void DocxAttributeOutput::FormatBox( const SvxBoxItem& 
rBox )
         aStyleBorders[ SvxBoxItemLine::LEFT ] = 
SvxBoxItem::SvxLineToLine(pInherited->GetLeft(), false);
         aStyleBorders[ SvxBoxItemLine::RIGHT ] = 
SvxBoxItem::SvxLineToLine(pInherited->GetRight(), false);
     }
-
-    impl_borders( m_pSerializer, rBox, aOutputBorderOptions, aStyleBorders );
+    bool bUseFrame = m_aFramePr.UseFrameBorders(!m_xTableWrt ? -1 : 
m_tableReference.m_nTableDepth);
+    impl_borders(m_pSerializer, rBox, aOutputBorderOptions, aStyleBorders,
+                 bUseFrame ? m_aFramePr.Frame() : nullptr);
 
     // Close the paragraph's borders tag
     m_pSerializer->endElementNS( XML_w, XML_pBdr );
+
+    m_aFramePr.SetUseFrameBorders(false);
 }
 
 void DocxAttributeOutput::FormatColumns_Impl( sal_uInt16 nCols, const 
SwFormatCol& rCol, bool bEven, SwTwips nPageSize )
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index 1e536bd11965..bf2af19a410e 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -130,16 +130,22 @@ struct TableReference
 class FramePrHelper
 {
     ww8::Frame* m_pFrame;
+    sal_Int32 m_nTableDepth;
+    bool m_bUseFrameBorders;
     bool m_bUseFrameBackground;
 
 public:
     FramePrHelper()
         : m_pFrame(nullptr)
+        , m_nTableDepth(0)
+        , m_bUseFrameBorders(true)
         , m_bUseFrameBackground(true)
     {}
 
     ww8::Frame* Frame() { return m_pFrame; }
-    void SetFrame(ww8::Frame* pSet);
+    void SetFrame(ww8::Frame* pSet, sal_Int32 nTableDepth = -1);
+    bool UseFrameBorders(sal_Int32 nTableDepth);
+    void SetUseFrameBorders(bool bSet) { m_bUseFrameBorders = bSet; }
     bool UseFrameBackground();
     void SetUseFrameBackground(bool bSet) { m_bUseFrameBackground = bSet; }
 };
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index f76ca11b01a1..07a475485eca 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1563,10 +1563,9 @@ static void 
lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& r
                 xTextRangeProperties->setPropertyValue( sPropertyName, 
uno::Any(table::BorderLine2()));
             else if (nProperty > 5)
             {
-                // Do not duplicate the top/bottom border spacing.
-                // [NOTE: left/right need to be duplicated because of 
INVERT_BORDER_SPACING]
-                // Hack: a minimal distance is given so left/right shading 
extends to the edge.
-                xTextRangeProperties->setPropertyValue( sPropertyName, 
uno::Any(sal_Int32(1)));
+                // Do not duplicate the top6/bottom7 border spacing.
+                // left4/right5 need to be duplicated because of 
INVERT_BORDER_SPACING
+                aValue.Value <<= sal_Int32(0);
             }
             if (aValue.Value.hasValue())
                 rFrameProperties.push_back(aValue);

Reply via email to