tdf#139948: docx and rtf import: emulate border in between
Writer does not support border in between available in all MS
formats. Since this feature is missing in core it will be
better to emulate it with top borders than to ignore it
completely.
Change-Id: I4e5a99cde5908066c4bb483136cfe9a1316df53c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132429
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf139948.docx b/sw/qa/extras/ooxmlexport/data/tdf139948.docx
new file mode 100644
index 0000000..1b3f7df
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf139948.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 69591c6..f199b1f 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -397,6 +397,32 @@ DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx")
xmlXPathFreeObject(pXmlObj);
}
DECLARE_OOXMLEXPORT_TEST(testTdf139948, "tdf139948.docx")
{
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(1, "No border"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(2, "Border below"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(88),
getProperty<table::BorderLine2>(getParagraph(3, "Borders below and above"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(88),
getProperty<table::BorderLine2>(getParagraph(4, "Border above"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(5, "No border"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(1), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(2), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(3), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(4), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(5), "BottomBorder").LineWidth);
}
DECLARE_OOXMLEXPORT_TEST(testTdf144563, "tdf144563.docx")
{
uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
diff --git a/sw/qa/extras/rtfexport/data/tdf139948.rtf b/sw/qa/extras/rtfexport/data/tdf139948.rtf
new file mode 100644
index 0000000..0b601a7
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf139948.rtf
@@ -0,0 +1,8 @@
{\rtf1\ansi
No border\par
\pard\brdrbtw\brdrs\brdrw50
Border below\par
Borders below and above\par
Border above\par
\pard No border\par
}
\ No newline at end of file
diff --git a/sw/qa/extras/rtfexport/rtfexport4.cxx b/sw/qa/extras/rtfexport/rtfexport4.cxx
index 123b3b3..8f81b15 100644
--- a/sw/qa/extras/rtfexport/rtfexport4.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport4.cxx
@@ -528,6 +528,38 @@ DECLARE_RTFEXPORT_TEST(testTdf111851, "tdf111851.rtf")
CPPUNIT_ASSERT_EQUAL(COL_BLACK, getProperty<Color>(xCell6, "BackColor"));
}
DECLARE_RTFEXPORT_TEST(testTdf139948, "tdf139948.rtf")
{
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(1, "No border"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(2, "Border below"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(88),
getProperty<table::BorderLine2>(getParagraph(3, "Borders below and above"), "TopBorder")
.LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(88),
getProperty<table::BorderLine2>(getParagraph(4, "Border above"), "TopBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0),
getProperty<table::BorderLine2>(getParagraph(5, "No border"), "TopBorder").LineWidth);
// And let's ensure that there are no other horizontal borders
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0), getProperty<table::BorderLine2>(getParagraph(1), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0), getProperty<table::BorderLine2>(getParagraph(2), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0), getProperty<table::BorderLine2>(getParagraph(3), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0), getProperty<table::BorderLine2>(getParagraph(4), "BottomBorder").LineWidth);
CPPUNIT_ASSERT_EQUAL(
sal_uInt32(0), getProperty<table::BorderLine2>(getParagraph(5), "BottomBorder").LineWidth);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 22f2be9..7c2e932 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1473,7 +1473,16 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
eBorderDistId = PROP_RIGHT_BORDER_DISTANCE ;
break;
case NS_ooxml::LN_CT_PBdr_between:
//not supported
if (m_pImpl->handlePreviousParagraphBorderInBetween())
{
// If previous paragraph also had border in between property
// then it is possible to emulate this border as top border
// for current paragraph
eBorderId = PROP_TOP_BORDER;
eBorderDistId = PROP_TOP_BORDER_DISTANCE;
}
// Since there are borders in between, each paragraph will have own borders. No more joining
rContext->Insert(PROP_PARA_CONNECT_BORDERS, uno::makeAny(false));
break;
default:;
}
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index e3d6f4c..75c40de 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -8508,6 +8508,31 @@ void DomainMapper_Impl::commentProps(const OUString& sId, const CommentPropertie
m_aCommentProps[sId] = rProps;
}
bool DomainMapper_Impl::handlePreviousParagraphBorderInBetween() const
{
if (!m_xPreviousParagraph.is())
return false;
// Connected borders ("ParaIsConnectBorder") are always on by default
// and never changed by DomainMapper. Except one case when border in
// between is used. So this is not the best, but easiest way to check
// is previous paragraph has border in between.
bool bConnectBorders = true;
m_xPreviousParagraph->getPropertyValue(getPropertyName(PROP_PARA_CONNECT_BORDERS)) >>= bConnectBorders;
if (bConnectBorders)
return false;
// Previous paragraph has border in between. Current one also has (since this
// method is called). So current paragraph will get border above, but
// also need to ensure, that no unexpected bottom border are remaining in previous
// paragraph: since ParaIsConnectBorder=false it will be displayed in unexpected way.
m_xPreviousParagraph->setPropertyValue(getPropertyName(PROP_BOTTOM_BORDER), uno::makeAny(table::BorderLine2()));
return true;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index f6c3f63..9bef6fb 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -1160,6 +1160,9 @@ public:
/// start/end node.
void ClearPreviousParagraph();
/// Check if previous paragraph has borders in between and do the border magic to it if so
bool handlePreviousParagraphBorderInBetween() const;
/// Handle redline text portions in a frame, footnotes and redlines:
/// store their data, and create them after frame creation or footnote/endnote copying
bool m_bIsActualParagraphFramed;
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
index b339a83..1189bc0 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -364,6 +364,7 @@ OUString getPropertyName( PropertyIds eId )
sName = "RtlGutter";
break;
case PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF: sName = "CursorNotIgnoreTables"; break;
case PROP_PARA_CONNECT_BORDERS: sName= "ParaIsConnectBorder"; break;
}
assert(sName.getLength()>0);
return sName;
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
index b09170d..7b6fe9a 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -361,6 +361,7 @@ enum PropertyIds
,PROP_GUTTER_MARGIN
,PROP_RTL_GUTTER
,PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
,PROP_PARA_CONNECT_BORDERS
};
//Returns the UNO string equivalent to eId.
diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx b/writerfilter/source/rtftok/rtfdispatchflag.cxx
index bb611fd..463710dd 100644
--- a/writerfilter/source/rtftok/rtfdispatchflag.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx
@@ -672,6 +672,7 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
case RTFKeyword::BRDRL:
case RTFKeyword::BRDRB:
case RTFKeyword::BRDRR:
case RTFKeyword::BRDRBTW:
{
RTFSprms aAttributes;
RTFSprms aSprms;
@@ -690,6 +691,9 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
case RTFKeyword::BRDRR:
nSprm = getParagraphBorder(3);
break;
case RTFKeyword::BRDRBTW:
nSprm = getParagraphBorder(4);
break;
default:
break;
}
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
index bceea94..da53e2d 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -80,8 +80,9 @@ namespace writerfilter::rtftok
{
Id getParagraphBorder(sal_uInt32 nIndex)
{
static const Id aBorderIds[] = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left,
NS_ooxml::LN_CT_PBdr_bottom, NS_ooxml::LN_CT_PBdr_right };
static const Id aBorderIds[]
= { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
return aBorderIds[nIndex];
}