sw/qa/core/draw/data/tdf107727_FrameBorder.odt |binary sw/qa/core/draw/draw.cxx | 43 ++++++++++++++++++++ sw/source/filter/ww8/rtfattributeoutput.cxx | 52 ++++++++++++++++--------- 3 files changed, 78 insertions(+), 17 deletions(-)
New commits: commit 9877a0190e43241f4a5102e5d9cc7181f91d5a6f Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Tue Feb 1 20:38:07 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Feb 2 08:38:11 2022 +0100 tdf#107727 disable border in RTF export if not drawn A border of a text frame is not drawn, if it is really disabled or if its line style is None. The patch considers both cases. Previously the first case was missing. LO can disable single border lines and single border lines can have different styles. The patch uses a border line now, that is really drawn, to get the color and width. It uses the first one in order top, bottom, left, right. In theory RTF can describe disabling single border lines by using the flags fTopLine, fBottomLine, fLeftLine or fRightLine. But Word has only the ability to enable all or none of the border lines for an old kind text box as contained in an rtf-document. The current patch uses therefore this all-or-none approach too. It enables border if at least one is actually drawn, because that keeps the style settings for that border line. Previously all four border lines need to be drawn. If it is changed to use the flags fTopLine, fBottomLine, fLeftLine and fRightLine on export, then it would be possible to recover showing only single border lines on reimport. But that is out of scope here. Change-Id: Ib78604def154c133d3c93bc75a38731eb6b02294 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129305 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/draw/data/tdf107727_FrameBorder.odt b/sw/qa/core/draw/data/tdf107727_FrameBorder.odt new file mode 100644 index 000000000000..6b7bc3a375fa Binary files /dev/null and b/sw/qa/core/draw/data/tdf107727_FrameBorder.odt differ diff --git a/sw/qa/core/draw/draw.cxx b/sw/qa/core/draw/draw.cxx index 97b6a2bb7d79..c2514808f8e4 100644 --- a/sw/qa/core/draw/draw.cxx +++ b/sw/qa/core/draw/draw.cxx @@ -10,6 +10,7 @@ #include <swmodeltestbase.hxx> #include <svx/svdpage.hxx> +#include <unotools/mediadescriptor.hxx> #include <IDocumentDrawModelAccess.hxx> #include <docsh.hxx> @@ -18,6 +19,10 @@ #include <frameformats.hxx> #include <textboxhelper.hxx> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/table/BorderLine2.hpp> +#include <com/sun/star/text/XTextFramesSupplier.hpp> + constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/draw/data/"; /// Covers sw/source/core/draw/ fixes. @@ -98,6 +103,44 @@ CPPUNIT_TEST_FIXTURE(SwCoreDrawTest, testTextboxUndoOrdNum) } } +CPPUNIT_TEST_FIXTURE(SwCoreDrawTest, testTdf107727FrameBorder) +{ + // Load a document with a textframe without border, one with only left border + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf107727_FrameBorder.odt"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", {}); + + // Export to RTF and reload + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("Rich Text Format"); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument", {}); + + // Get frame without border and inspect it. + uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xFrame0(xIndexAccess->getByIndex(0), uno::UNO_QUERY); + auto aBorder = getProperty<table::BorderLine2>(xFrame0, "LeftBorder"); + // fo:border="none" is not available via API, and aBorder.LineWidth has wrong value (why?). + sal_uInt32 nBorderWidth + = aBorder.OuterLineWidth + aBorder.InnerLineWidth + aBorder.LineDistance; + // Without patch it failed with Expected 0, Actual 26 + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), nBorderWidth); + + // Get frame with left border and inspect it. + uno::Reference<beans::XPropertySet> xFrame1(xIndexAccess->getByIndex(1), uno::UNO_QUERY); + aBorder = getProperty<table::BorderLine2>(xFrame1, "LeftBorder"); + // Without patch it failed with Expected 127, Actual 26. Default border width was used. + nBorderWidth = aBorder.OuterLineWidth + aBorder.InnerLineWidth + aBorder.LineDistance; + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(127), nBorderWidth); + // Without patch it failed with Expected Color: R:0 G:0 B:255 A:0, Actual Color: R:0 G:0 B:0 A:0. + // Default border color was used. + CPPUNIT_ASSERT_EQUAL(Color(0x0000ff), Color(ColorTransparency, aBorder.Color)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 8f9d48f05da2..657160b1ee52 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -3558,27 +3558,45 @@ void RtfAttributeOutput::FormatBox(const SvxBoxItem& rBox) const editeng::SvxBorderLine* pRight = rBox.GetLine(SvxBoxItemLine::RIGHT); const editeng::SvxBorderLine* pTop = rBox.GetLine(SvxBoxItemLine::TOP); const editeng::SvxBorderLine* pBottom = rBox.GetLine(SvxBoxItemLine::BOTTOM); - if (pLeft && pRight && pTop && pBottom && *pLeft == *pRight && *pLeft == *pTop - && *pLeft == *pBottom) + + if (!pLeft && !pRight && !pBottom && !pTop) { - const Color& rColor = pTop->GetColor(); - // We in fact need RGB to BGR, but the transformation is symmetric. - m_aFlyProperties.push_back(std::make_pair<OString, OString>( - "lineColor", OString::number(wwUtility::RGBToBGR(rColor)))); + // fLine has default 'true', so need to write it out in case of no border. + m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0")); + return; + } - if (pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE) - { - double const fConverted(editeng::ConvertBorderWidthToWord( - pTop->GetBorderLineStyle(), pTop->GetWidth())); - sal_Int32 nWidth = o3tl::convert(fConverted, o3tl::Length::twip, o3tl::Length::emu); - m_aFlyProperties.push_back( - std::make_pair<OString, OString>("lineWidth", OString::number(nWidth))); - } - else - // No border: no line. - m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0")); + // RTF has the flags fTopLine, fBottomLine, fLeftLine and fRightLine to disable single border + // lines. But Word cannot disable single border lines. So we do not use them. In case of + // single border lines it is better to draw all four borders than drawing none. So we look + // whether a border line exists, which is effectively drawn. + const editeng::SvxBorderLine* pBorder = nullptr; + if (pTop && pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE) + pBorder = pTop; + else if (pBottom && pBottom->GetBorderLineStyle() != SvxBorderLineStyle::NONE) + pBorder = pBottom; + else if (pLeft && pLeft->GetBorderLineStyle() != SvxBorderLineStyle::NONE) + pBorder = pLeft; + else if (pRight && pRight->GetBorderLineStyle() != SvxBorderLineStyle::NONE) + pBorder = pRight; + + if (!pBorder) + { + m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0")); + return; } + const Color& rColor = pBorder->GetColor(); + // We in fact need RGB to BGR, but the transformation is symmetric. + m_aFlyProperties.push_back(std::make_pair<OString, OString>( + "lineColor", OString::number(wwUtility::RGBToBGR(rColor)))); + + double const fConverted( + editeng::ConvertBorderWidthToWord(pBorder->GetBorderLineStyle(), pBorder->GetWidth())); + sal_Int32 nWidth = o3tl::convert(fConverted, o3tl::Length::twip, o3tl::Length::emu); + m_aFlyProperties.push_back( + std::make_pair<OString, OString>("lineWidth", OString::number(nWidth))); + return; }