summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-02-19 18:03:59 +0100
committerMiklos Vajna <vmiklos@collabora.com>2020-02-19 20:15:29 +0100
commite6fa52c2c371c7adc9c2c2cb18c3a8cf782cfa4b (patch)
treef090c50815727c468bebe50311246ab9424d1250
parent7448b69b4aaa982940e49c5ace9842f07dd81938 (diff)
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. Change-Id: I1f682789302c88a0d326c6c0263ad3007441cb24 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89052 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--include/svx/framelink.hxx7
-rw-r--r--svx/source/dialog/framelink.cxx117
-rw-r--r--sw/qa/core/layout/data/border-collapse-compat.docxbin0 -> 12669 bytes
-rw-r--r--sw/qa/core/layout/layout.cxx20
-rw-r--r--sw/source/core/layout/paintfrm.cxx12
5 files changed, 155 insertions, 1 deletions
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index 5296ab88d56e..ec94bda63f01 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -116,6 +116,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. */
@@ -129,7 +130,8 @@ private:
mfDist(0.0),
mfSecn(0.0),
mfPatternScale(1.0),
- mnType(SvxBorderLineStyle::SOLID)
+ mnType(SvxBorderLineStyle::SOLID),
+ mbWordTableCell(false)
{}
};
@@ -187,6 +189,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 68d52462025e..286113e01dfb 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -260,6 +260,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)
@@ -283,6 +293,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)
@@ -291,6 +396,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
--- /dev/null
+++ b/sw/qa/core/layout/data/border-collapse-compat.docx
Binary files differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index cbea578be4cc..4c16a3bbcd97 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -43,6 +43,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 = dumpAndParse(aDumper, *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 d0c72f9b4f91..50cc2aaac8a7 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2744,11 +2744,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();