editeng/source/items/frmitems.cxx                      |    3 +
 sw/qa/extras/odfexport/odfexport.cxx                   |    2 
 sw/qa/extras/rtfexport/data/tdf129631_lostBorders3.rtf |   27 +++++++++
 sw/qa/extras/rtfexport/rtfexport4.cxx                  |   51 +++++++++++++++++
 sw/source/filter/ww8/rtfattributeoutput.cxx            |   20 ++++--
 writerfilter/source/rtftok/rtfdocumentimpl.cxx         |   15 +++++
 6 files changed, 110 insertions(+), 8 deletions(-)

New commits:
commit 221c5cfebf7c027ebb656860f2b12d60faa86b89
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Aug 10 14:04:44 2022 +0200
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Fri Aug 12 23:29:52 2022 +0200

    tdf#129631 writerfilter,sw: RTF import of invalid border...
    
    ... and export of border on paragraph that clears the border from the
    paragraph style.
    
    The import problem is that a lone \brdrcf17 without any preceding
    keyword about which border it belongs to (as required by the EBNF in the
    RTF spec) is apparently handled by Word as overriding/clearing all
    paragraph borders that may be inherited from the paragraph style.
    
    The export problem is that a null SvxBorderLine isn't exported at all,
    but there needs to be a \brdrnone to override the definition from the
    style.
    
    There was also an API problem that the null SvxBorderLine is wrongly
    converted to a table::BorderLine2 with LineStyle SOLID.
    
    Change-Id: I5fa3857de2ef843f5194e12dd0c3e57bcf1ca52b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138089
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 967a03eb8760fb498c5ea6c32d03d1eea486bbe2)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138120
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/editeng/source/items/frmitems.cxx 
b/editeng/source/items/frmitems.cxx
index c4c79dc0428b..35e1be7b094c 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -1387,7 +1387,10 @@ table::BorderLine2 SvxBoxItem::SvxLineToLine(const 
SvxBorderLine* pLine, bool bC
         aLine.LineWidth      = sal_uInt32( bConvert ? convertTwipToMm100( 
pLine->GetWidth( ) ) : pLine->GetWidth( ) );
     }
     else
+    {
         aLine.Color          = aLine.InnerLineWidth = aLine.OuterLineWidth = 
aLine.LineDistance  = 0;
+        aLine.LineStyle = table::BorderLineStyle::NONE; // 0 is SOLID!
+    }
     return aLine;
 }
 
diff --git a/sw/qa/extras/odfexport/odfexport.cxx 
b/sw/qa/extras/odfexport/odfexport.cxx
index 3fb14b220c69..73b9bcfbf6d0 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -1111,7 +1111,7 @@ DECLARE_ODFEXPORT_TEST(testCharacterBorder, 
"charborder.odt")
             table::BorderLine2(0xFF3333,0,37,0,14,37),     // Top (fine dashed 
line)
             table::BorderLine2(0x99FF66,26,26,53,11,106),  // Bottom
             table::BorderLine2(0x6666FF,9,26,9,12,71),     // Left
-            table::BorderLine2(0,0,0,0,0,0)                // Right
+            table::BorderLine2(0,0,0,0,table::BorderLineStyle::NONE,0) // Right
         };
 
         sal_Int32 aDistances[4] = { 400 /*Top*/, 300 /*Bottom*/, 250 /*Left*/, 
0 /*Right*/ };
diff --git a/sw/qa/extras/rtfexport/data/tdf129631_lostBorders3.rtf 
b/sw/qa/extras/rtfexport/data/tdf129631_lostBorders3.rtf
new file mode 100644
index 000000000000..dba7db7dc8e5
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf129631_lostBorders3.rtf
@@ -0,0 +1,27 @@
+{\rtf1\ansi\deff4\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New 
Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 
Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New 
Roman};}{\f4\froman\fprq0\fcharset0 Times New Roman;}{\f5\fnil\fprq2\fcharset0 
DejaVu Sans;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red6\green154\blue46;}
+{\stylesheet{\s0\snext0\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\ltrpar\hyphpar0\aspalpha\cf0\loch\f3\fs24\lang255\kerning1
 Normal;}
+{\*\cs15\snext15 CharShadow;}
+{\*\cs16\sbasedon15\snext16 CharShadow-removed;}
+{\s17\sbasedon0\snext18\dbch\af5\langfe2052\dbch\af4\afs28\alang1025\ql\widctlpar\sb240\sa120\keepn\ltrpar\cf0\loch\f4\fs28\lang255\kerning1
 Heading;}
+{\s18\sbasedon0\snext18\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\sl276\slmult1\ql\widctlpar\sb0\sa140\ltrpar\cf0\loch\f3\fs24\lang255\kerning1
 Text Body;}
+{\s19\sbasedon18\snext19\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\sl276\slmult1\ql\widctlpar\sb0\sa140\ltrpar\cf0\loch\f4\fs24\lang255\kerning1
 List;}
+{\s20\sbasedon0\snext20\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ai\ql\widctlpar\sb120\sa120\noline\ltrpar\cf0\loch\f4\fs24\lang255\i\kerning1
 Caption;}
+{\s21\sbasedon0\snext21\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\noline\ltrpar\cf0\loch\f4\fs24\lang255\kerning1
 Index;}
+{\s22\sbasedon0\snext22\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\brdrt\brdrs\brdrw50\brdrcf1\brsp0\brdrl\brdrs\brdrw50\brdrcf1\brsp0\brdrb\brdrs\brdrw50\brdrcf1\brsp20\brdrr\brdrs\brdrw50\brdrcf1\brsp20\ltrpar\cf0\loch\f3\fs48\lang255\i\b\kerning1
 Border;}
+{\s23\sbasedon0\snext23\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\sb0\sa60\noline\ltrpar\cf0\loch\f3\fs24\lang255\kerning1
 Sender;}
+}{\*\generator LibreOfficeDev/6.5.0.0.alpha0$Linux_X86_64 
LibreOffice_project/c71d886120998884fdd16a862826f59883d9a114}{\info{\creatim\yr2019\mo12\dy21\hr9\min10}{\revtim\yr2019\mo12\dy26\hr11\min50}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab709
+\viewscale140
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse451\lndscpsxn\pgwsxn8391\pghsxn5953\marglsxn1134\margrsxn1134\margtsxn992\margbsxn992\pgdscnxt0
 Default Style;}}
+\formshade{\*\pgdscno0}\landscape\paperh5953\paperw8391\margl1134\margr1134\margt992\margb992\sectd\sbknone\sectunlocked1\lndscpsxn\pgndec\pgwsxn8391\pghsxn5953\marglsxn1134\margrsxn1134\margtsxn992\margbsxn992\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc\htmautsp
+{\*\ftnsep\chftnsep}\pgndec\pard\plain 
\s0\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\ltrpar\hyphpar0\aspalpha\cf0\loch\f3\fs24\lang255\kerning1{\loch
+Paragraph border are NOT inherited from styles if partially re-defined 
directly.}
+\par \pard\plain 
\s22\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\cf0\loch\f3\fs48\lang255\i\b\kerning1\brdrcf17{\loch
+Here colored green by direct formating, but no borders defined.}
+\par \pard\plain 
\s0\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\ltrpar\hyphpar0\aspalpha\cf0\loch\f3\fs24\lang255\kerning1\loch
+
+\par \pard\plain 
\s22\dbch\af5\langfe2052\dbch\af4\afs24\alang1025\ql\widctlpar\brdrt\brdrs\brdrw50\brdrcf1\brsp0\brdrl\brdrs\brdrw50\brdrcf1\brsp0\brdrb\brdrs\brdrw50\brdrcf1\brsp20\brdrr\brdrs\brdrw50\brdrcf1\brsp20\ltrpar\cf0\loch\f3\fs48\lang255\i\b\kerning1{\loch
+End of test}
+\par }
diff --git a/sw/qa/extras/rtfexport/rtfexport4.cxx 
b/sw/qa/extras/rtfexport/rtfexport4.cxx
index 27335cf75c2f..dbcbeaee9d77 100644
--- a/sw/qa/extras/rtfexport/rtfexport4.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport4.cxx
@@ -123,6 +123,57 @@ DECLARE_RTFEXPORT_TEST(test150269, "hidden-linebreaks.rtf")
     CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xRun, "CharHidden"));
 }
 
+DECLARE_RTFEXPORT_TEST(test129758, "tdf129631_lostBorders3.rtf")
+{
+    uno::Reference<container::XNameAccess> 
xStyles(getStyles("ParagraphStyles"));
+    uno::Reference<beans::XPropertySet> xStyle(xStyles->getByName("Border"), 
uno::UNO_QUERY);
+    // style has borders
+    table::BorderLine2 border;
+    border = getProperty<table::BorderLine2>(xStyle, "RightBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xStyle, "LeftBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xStyle, "TopBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xStyle, "BottomBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    // style applied
+    uno::Reference<beans::XPropertySet> xPara2(getParagraph(2), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString("Border"), getProperty<OUString>(xPara2, 
"ParaStyleName"));
+    // but no borders
+    border = getProperty<table::BorderLine2>(xPara2, "RightBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::NONE, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara2, "LeftBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::NONE, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara2, "TopBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::NONE, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara2, "BottomBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::NONE, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), border.LineWidth);
+    // last paragraph: style applied, no override
+    uno::Reference<beans::XPropertySet> xPara4(getParagraph(4), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString("Border"), getProperty<OUString>(xPara4, 
"ParaStyleName"));
+    border = getProperty<table::BorderLine2>(xPara4, "RightBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara4, "LeftBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara4, "TopBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+    border = getProperty<table::BorderLine2>(xPara4, "BottomBorder");
+    CPPUNIT_ASSERT_EQUAL(table::BorderLineStyle::SOLID, border.LineStyle);
+    CPPUNIT_ASSERT_EQUAL(sal_uInt32(88), border.LineWidth);
+}
+
 DECLARE_RTFEXPORT_TEST(testAnchoredAtSamePosition, "anchor.fodt")
 {
     SwXTextDocument* const pTextDoc = 
dynamic_cast<SwXTextDocument*>(mxComponent.get());
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 9d634e73af7a..6fa088f5f82a 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -188,6 +188,11 @@ static OString OutTBLBorderLine(RtfExport const& rExport, 
const editeng::SvxBord
         aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRCF);
         
aRet.append(static_cast<sal_Int32>(rExport.GetColor(pLine->GetColor())));
     }
+    else // tdf#129758 "no border" may be needed to override style
+    {
+        aRet.append(pStr);
+        aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRNONE);
+    }
     return aRet.makeStringAndClear();
 }
 
@@ -197,8 +202,11 @@ static OString OutBorderLine(RtfExport const& rExport, 
const editeng::SvxBorderL
 {
     OStringBuffer aRet;
     aRet.append(OutTBLBorderLine(rExport, pLine, pStr));
-    aRet.append(OOO_STRING_SVTOOLS_RTF_BRSP);
-    aRet.append(static_cast<sal_Int32>(nDist));
+    if (pLine)
+    {
+        aRet.append(OOO_STRING_SVTOOLS_RTF_BRSP);
+        aRet.append(static_cast<sal_Int32>(nDist));
+    }
     if (eShadowLocation == SvxShadowLocation::BottomRight)
         aRet.append(LO_STRING_SVTOOLS_RTF_BRDRSH);
     return aRet.makeStringAndClear();
@@ -3644,11 +3652,9 @@ void RtfAttributeOutput::FormatBox(const SvxBoxItem& 
rBox)
         const char** pBrdNms = aBorderNames;
         for (int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms)
         {
-            if (const editeng::SvxBorderLine* pLn = rBox.GetLine(*pBrd))
-            {
-                m_aSectionBreaks.append(OutBorderLine(m_rExport, pLn, *pBrdNms,
-                                                      rBox.GetDistance(*pBrd), 
eShadowLocation));
-            }
+            editeng::SvxBorderLine const* const pLn = rBox.GetLine(*pBrd);
+            m_aSectionBreaks.append(
+                OutBorderLine(m_rExport, pLn, *pBrdNms, 
rBox.GetDistance(*pBrd), eShadowLocation));
         }
     }
 
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx 
b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index cbe36e5c277c..076bd5efa845 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -186,6 +186,21 @@ void putBorderProperty(RTFStack& aStates, Id nId, const 
RTFValue::Pointer_t& pVa
     else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
         pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
                                          
NS_ooxml::LN_EG_SectPrContents_pgBorders);
+    else if (aStates.top().getBorderState() == RTFBorderState::NONE)
+    {
+        // this is invalid, but Word apparently clears or overrides all 
paragraph borders now
+        for (int i = 0; i < 4; ++i)
+        {
+            auto const nBorder = getParagraphBorder(i);
+            RTFSprms aAttributes;
+            RTFSprms aSprms;
+            aAttributes.set(NS_ooxml::LN_CT_Border_val,
+                            new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+            putNestedSprm(aStates.top().getParagraphSprms(), 
NS_ooxml::LN_CT_PrBase_pBdr, nBorder,
+                          new RTFValue(aAttributes, aSprms), 
RTFOverwrite::YES);
+        }
+    }
+
     if (pAttributes)
         pAttributes->set(nId, pValue);
 }

Reply via email to