include/svx/framelink.hxx | 7 + svx/source/dialog/framelink.cxx | 117 +++++++++++++++++++++ sw/qa/core/layout/data/border-collapse-compat.docx |binary sw/qa/core/layout/layout.cxx | 21 +++ sw/source/core/layout/paintfrm.cxx | 12 ++ 5 files changed, 156 insertions(+), 1 deletion(-)
New commits: commit 37bf72bac52ba98a29c1d29f3fe9e667c4222d06 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed Feb 19 18:03:59 2020 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Feb 20 11:27:32 2020 +0100 sw table cell borders: add optional Word-compatible border collapsing We always compared border width and other aspects only after that, Word works with border weight according to their implementer notes. So extend svx::frame::Style to be able to collapse borders using weights and opt in for that from sw/ in case a compat mode (which is related to tables, off by default and is set by the DOC/DOCX import) is set. Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89052 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit e6fa52c2c371c7adc9c2c2cb18c3a8cf782cfa4b) Change-Id: I1f682789302c88a0d326c6c0263ad3007441cb24 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89078 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index fa629fc24ad2..cab0b59e371d 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -123,6 +123,7 @@ private: double mfSecn; /// Width of secondary (right or bottom) line. double mfPatternScale; /// Scale used for line pattern spacing. SvxBorderLineStyle mnType; + bool mbWordTableCell; public: /** Constructs an invisible frame style. */ @@ -136,7 +137,8 @@ private: mfDist(0.0), mfSecn(0.0), mfPatternScale(1.0), - mnType(SvxBorderLineStyle::SOLID) + mnType(SvxBorderLineStyle::SOLID), + mbWordTableCell(false) {} }; @@ -194,6 +196,9 @@ public: /** Mirrors this style (exchanges primary and secondary), if it is a double frame style. */ Style& MirrorSelf(); + /** Enables the Word-compatible Style comparison code. */ + void SetWordTableCell(bool bWordTableCell); + bool operator==( const Style& rOther) const; bool operator<( const Style& rOther) const; }; diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index b4548c6ebed9..c8696b063e0b 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -267,6 +267,16 @@ Style& Style::MirrorSelf() return *this; } +void Style::SetWordTableCell(bool bWordTableCell) +{ + if (!maImplStyle) + { + implEnsureImplStyle(); + } + + maImplStyle->mbWordTableCell = bWordTableCell; +} + bool Style::operator==( const Style& rOther) const { if(!maImplStyle && !rOther.maImplStyle) @@ -290,6 +300,101 @@ bool Style::operator==( const Style& rOther) const && Type() == rOther.Type()); } +namespace +{ +/** + * Gets the weight of rStyle, according to [MS-OI29500] v20171130, 2.1.168 Part 1 Section 17.4.66, + * tcBorders (Table Cell Borders). + */ +double GetWordTableCellBorderWeight(const Style& rStyle) +{ + double fWidth = rStyle.GetWidth(); + int nBorderNumber = 0; + + // See lcl_convertBorderStyleFromToken() in writerfilter/ and ConvertBorderStyleFromWord() in + // editeng/, this is the opposite of the combination of those functions. + switch (rStyle.Type()) + { + case SvxBorderLineStyle::NONE: + return 0.0; + case SvxBorderLineStyle::DOTTED: + case SvxBorderLineStyle::DASHED: + return 1.0; + case SvxBorderLineStyle::SOLID: + // single = 1 + // thick = 2 + // wave = 20 + nBorderNumber = 1; + break; + case SvxBorderLineStyle::DOUBLE: + case SvxBorderLineStyle::DOUBLE_THIN: + // double = 3 + // triple = 10 + // doubleWave = 21 + // dashDotStroked = 23 + nBorderNumber = 3; + break; + case SvxBorderLineStyle::DASH_DOT: + // dotDash = 8 + nBorderNumber = 8; + break; + case SvxBorderLineStyle::DASH_DOT_DOT: + // dotDotDash = 9 + nBorderNumber = 9; + break; + case SvxBorderLineStyle::THINTHICK_SMALLGAP: + // thinThickSmallGap = 11 + nBorderNumber = 11; + break; + case SvxBorderLineStyle::THICKTHIN_SMALLGAP: + // thickThinSmallGap = 12 + // thinThickThinSmallGap = 13 + nBorderNumber = 12; + break; + case SvxBorderLineStyle::THINTHICK_MEDIUMGAP: + // thinThickMediumGap = 14 + nBorderNumber = 14; + break; + case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP: + // thickThinMediumGap = 15 + // thinThickThinMediumGap = 16 + nBorderNumber = 15; + break; + case SvxBorderLineStyle::THINTHICK_LARGEGAP: + // thinThickLargeGap = 17 + nBorderNumber = 17; + break; + case SvxBorderLineStyle::THICKTHIN_LARGEGAP: + // thickThinLargeGap = 18 + // thinThickThinLargeGap = 19 + nBorderNumber = 18; + break; + case SvxBorderLineStyle::FINE_DASHED: + // dashSmallGap = 22 + nBorderNumber = 22; + break; + case SvxBorderLineStyle::EMBOSSED: + // threeDEmboss = 24 + nBorderNumber = 24; + break; + case SvxBorderLineStyle::ENGRAVED: + // threeDEngrave = 25 + nBorderNumber = 25; + break; + case SvxBorderLineStyle::OUTSET: + // outset = 26 + nBorderNumber = 25; + break; + case SvxBorderLineStyle::INSET: + // inset = 27 + nBorderNumber = 27; + break; + } + + return nBorderNumber * fWidth; +} +} + bool Style::operator<( const Style& rOther) const { if(!maImplStyle && !rOther.maImplStyle) @@ -298,6 +403,18 @@ bool Style::operator<( const Style& rOther) const return false; } + if (maImplStyle && maImplStyle->mbWordTableCell) + { + // The below code would first compare based on the border width, Word compares based on its + // calculated weight, do that in the compat case. + double fLW = GetWordTableCellBorderWeight(*this); + double fRW = GetWordTableCellBorderWeight(rOther); + if (!rtl::math::approxEqual(fLW, fRW)) + { + return fLW < fRW; + } + } + // different total widths -> this<rOther, if this is thinner double nLW = GetWidth(); double nRW = rOther.GetWidth(); diff --git a/sw/qa/core/layout/data/border-collapse-compat.docx b/sw/qa/core/layout/data/border-collapse-compat.docx new file mode 100644 index 000000000000..a3f29cbe8d1c Binary files /dev/null and b/sw/qa/core/layout/data/border-collapse-compat.docx differ diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx index cbea578be4cc..9c19cbbfd2f9 100644 --- a/sw/qa/core/layout/layout.cxx +++ b/sw/qa/core/layout/layout.cxx @@ -13,6 +13,7 @@ #include <comphelper/classids.hxx> #include <tools/globname.hxx> #include <svtools/embedhlp.hxx> +#include <test/mtfxmldump.hxx> #include <wrtsh.hxx> #include <fmtanchr.hxx> @@ -43,6 +44,26 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testTableFlyOverlap) CPPUNIT_ASSERT_GREATEREQUAL(nFlyBottom, nTableTop); } +CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testBorderCollapseCompat) +{ + // Load a document with a border conflict: top cell has a dotted bottom border, bottom cell has + // a solid upper border. + load(DATA_DIRECTORY, "border-collapse-compat.docx"); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwDocShell* pShell = pTextDoc->GetDocShell(); + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + MetafileXmlDump aDumper; + xmlDocPtr pXmlDoc = aDumper.dumpAndParse(*xMetaFile); + + // Make sure the solid border has priority. + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 48 + // i.e. there was no single cell border with width=20, rather there were 48 border parts + // (forming a dotted border), all with width=40. + assertXPath(pXmlDoc, "//polyline[@style='solid']", "width", "20"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 480cf8ea8613..b149802db1ba 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -2709,11 +2709,23 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem bool const bVert = mrTabFrame.IsVertical(); bool const bR2L = mrTabFrame.IsRightToLeft(); + bool bWordTableCell = false; + SwViewShell* pShell = rFrame.getRootFrame()->GetCurrShell(); + if (pShell) + { + const IDocumentSettingAccess& rIDSA = pShell->GetDoc()->getIDocumentSettingAccess(); + bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP); + } + // no scaling needed, it's all in the primitives and the target device svx::frame::Style aL(rBoxItem.GetLeft(), 1.0); + aL.SetWordTableCell(bWordTableCell); svx::frame::Style aR(rBoxItem.GetRight(), 1.0); + aR.SetWordTableCell(bWordTableCell); svx::frame::Style aT(rBoxItem.GetTop(), 1.0); + aT.SetWordTableCell(bWordTableCell); svx::frame::Style aB(rBoxItem.GetBottom(), 1.0); + aB.SetWordTableCell(bWordTableCell); aR.MirrorSelf(); aB.MirrorSelf(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits