sw/qa/core/layout/data/double-border-horizontal.docx |binary
 sw/qa/core/layout/layout.cxx                         |   48 +++++++++++++++++++
 sw/source/core/layout/paintfrm.cxx                   |   36 +++++++-------
 3 files changed, 68 insertions(+), 16 deletions(-)

New commits:
commit 13f0bfc17703837bcbe28d8eeb8cc21d223722fc
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jan 13 15:57:05 2022 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Feb 11 09:22:16 2022 +0100

    sw: fix swapped inner vs outer border for Word-style bottom table borders
    
    This is similar to commit fc04a84f297b78a1049182b6d8cf745f863ffe61 (sw:
    fix swapped inner vs outer border for Word-style left table borders,
    2022-01-11), but that was for vertical borders, this is for horizontal
    ones.
    
    The other difference is that Word mirrors vertical lines, but not
    horizontal ones. This means that our horizontal line need less
    mirroring, while our vertical lines needed more mirroring.
    
    (cherry picked from commit cf2690ae76b4250af32be7c8980b8d83b3611591)
    
    Change-Id: Iff07adac5c53420673139d5c93ce52f6148fb977
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129768
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/double-border-horizontal.docx 
b/sw/qa/core/layout/data/double-border-horizontal.docx
new file mode 100644
index 000000000000..624c7aa1aa74
Binary files /dev/null and 
b/sw/qa/core/layout/data/double-border-horizontal.docx differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 0358b2f0f359..4ed97597ffcc 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -626,6 +626,54 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testDoubleBorderVertical)
     CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoubleBorderHorizontal)
+{
+    // Given a table with a top and bottom double border, outer is thin, inner 
is thick:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "double-border-horizontal.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering table borders:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure the top border is thin+thick and the bottom border is 
thick+thin (from top to
+    // bottom):
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Collect widths of horizontal lines.
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    // Vertical position -> width.
+    std::map<sal_Int32, sal_Int32> aBorderWidths;
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartY = xmlGetProp(pStart, BAD_CAST("y"));
+        xmlChar* pEndY = xmlGetProp(pEnd, BAD_CAST("y"));
+        sal_Int32 nStartY = OString(reinterpret_cast<char 
const*>(pStartY)).toInt32();
+        sal_Int32 nEndY = OString(reinterpret_cast<char 
const*>(pEndY)).toInt32();
+        if (nStartY != nEndY)
+        {
+            // Vertical border.
+            continue;
+        }
+        xmlChar* pWidth = xmlGetProp(pStart->parent, BAD_CAST("width"));
+        sal_Int32 nWidth = OString(reinterpret_cast<char 
const*>(pWidth)).toInt32();
+        aBorderWidths[nStartY] = nWidth;
+    }
+    xmlXPathFreeObject(pXmlObj);
+    std::vector<sal_Int32> aBorderWidthVec;
+    std::transform(aBorderWidths.begin(), aBorderWidths.end(), 
std::back_inserter(aBorderWidthVec),
+                   [](const std::pair<sal_Int32, sal_Int32>& rPair) { return 
rPair.second; });
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), aBorderWidthVec.size());
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[0], aBorderWidthVec[1]);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 120
+    // - Actual  : 60
+    // i.e. the bottom border was thin+thick, not thick+thin.
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[3], aBorderWidthVec[2]);
+}
+
 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 00d0000c8b81..656646420dc5 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2846,8 +2846,21 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
     svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
     aB.SetWordTableCell(bWordTableCell);
 
+    // First cell in a row.
+    bool bLeftIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() 
== &rFrame;
+    // Last cell in a row.
+    bool bRightIsOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr;
+    // First row in a table.
+    bool bTopIsOuter = rFrame.IsCellFrame() && 
rFrame.GetUpper()->GetUpper()->GetLower() == rFrame.GetUpper();
+    // Last row in a table.
+    bool bBottomIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() 
== nullptr;
+
     aR.MirrorSelf();
-    aB.MirrorSelf();
+    if (!bWordTableCell || !bBottomIsOuter)
+    {
+        // Outer horizontal lines are never mirrored in Word.
+        aB.MirrorSelf();
+    }
 
     const SwTwips nLeft   = aBorderRect.Left_();
     const SwTwips nRight  = aBorderRect.Right_();
@@ -2859,39 +2872,30 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
     aT.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
     aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
 
-    // First cell in a row.
-    bool bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() == 
&rFrame;
-
-    if (bWordTableCell && bOuter)
+    if (bWordTableCell && bLeftIsOuter)
     {
-        // First vs secondary and inner vs outer is the other way around in 
Word.
+        // Outer vertical lines are always mirrored in Word.
         aL.MirrorSelf();
     }
 
-    SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bOuter,
+    SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bLeftIsOuter,
             bVert ? aB                         : (bR2L ? aR : aL));
     if (bWordTableCell && rBoxItem.GetLeft())
     {
         aLeft.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::LEFT);
     }
 
-    // Last cell in a row.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr;
-    SwLineEntry aRight (nRight,  nTop,  nBottom, bOuter,
+    SwLineEntry aRight (nRight,  nTop,  nBottom, bRightIsOuter,
             bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
     if (bWordTableCell && rBoxItem.GetRight())
     {
         aRight.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::RIGHT);
     }
 
-    // First row in a table.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetUpper()->GetLower() 
== rFrame.GetUpper();
-    SwLineEntry aTop   (nTop,    nLeft, nRight, bOuter,
+    SwLineEntry aTop   (nTop,    nLeft, nRight, bTopIsOuter,
             bVert ? aL                         : (bBottomAsTop ? aB : aT));
 
-    // Last row in a table.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() == nullptr;
-    SwLineEntry aBottom(nBottom, nLeft, nRight, bOuter,
+    SwLineEntry aBottom(nBottom, nLeft, nRight, bBottomIsOuter,
             bVert ? aR                         : aB);
 
     Insert( aLeft, false );

Reply via email to