sw/qa/core/layout/data/para-border-in-cell-clip.docx |binary
 sw/qa/core/layout/layout.cxx                         |   20 +++++++++
 sw/source/core/layout/paintfrm.cxx                   |   40 +++++++++++++++++--
 vcl/source/gdi/mtfxmldump.cxx                        |   24 +++++++++++
 4 files changed, 81 insertions(+), 3 deletions(-)

New commits:
commit f168cfc7a3a374fba2175eb8682a69b924928ccb
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 18 17:04:14 2022 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Jan 19 16:32:08 2022 +0100

    sw: fix unexpected paragraph border inside table cells
    
    The bug document has a table cell, which contains a paragraph with
    borders. Its left/right/bottom borders are rendered in Writer, but not
    in Word.
    
    The reason for the left/right border is that it's outside the
    paragraph's frame area, which is not rendered in Word. Fix this by
    clipping the rendered borders so they don't go outside the paragraph's
    frame area. (Normally the frame area is the larger rectangle, and then
    margins may cause a smaller "print area", but in this case we have a
    negative right margin, so clipping the print area to fit into the frame
    area actually does something.)
    
    This is quite similar to what commit
    1e21902106cbe57658bed03ed24d4d0863685cfd (tdf#117884: intersect border
    with paint area of upper frame., 2018-05-26) did for table borders.
    
    The bottom border is a different problem: the cell has a fixed height
    and enough content so the paragraph is cut off vertically. This means
    that technically the bottom border would be inside the frame area, but
    Word cuts it off, because they apply clipping on the not-yet-cut-off
    rectangle. Fix this by dropping the bottom margin when the frame is cut
    off.
    
    (cherry picked from commit 4a7281fa206c0a82cfc2ba23f25c31ae775d8777)
    
    Conflicts:
            sw/qa/core/layout/layout.cxx
            sw/source/core/layout/paintfrm.cxx
    
    Change-Id: I7f65b68997330b247db65839db8a484e74f78c64
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128611
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/para-border-in-cell-clip.docx 
b/sw/qa/core/layout/data/para-border-in-cell-clip.docx
new file mode 100644
index 000000000000..7c516853648c
Binary files /dev/null and 
b/sw/qa/core/layout/data/para-border-in-cell-clip.docx differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 1a83a17332c7..d982cae6fb01 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -356,6 +356,26 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testGutterMirrorMargin)
     CPPUNIT_ASSERT_EQUAL(nGutterTwips, nOldRight - nNewRight);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testParaBorderInCellClip)
+{
+    // Given a document which has outside-cell borders defined, which should 
not be visible:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "para-border-in-cell-clip.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering those borders:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure that we have clipping setup for both paragraphs inside 
the table cell:
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 0
+    // - XPath '//clipregion/polygon' number of nodes is incorrect
+    // i.e. there was no clipping applied, leading to unexpected left/right 
borders.
+    assertXPath(pXmlDoc, "//clipregion/polygon", 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 82d1d4fbcbb7..c1f924a34845 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -116,6 +116,7 @@
 
 #include <vcl/BitmapTools.hxx>
 #include <comphelper/lok.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
 
 #define COL_NOTES_SIDEPANE                  Color(230,230,230)
 #define COL_NOTES_SIDEPANE_BORDER           Color(200,200,200)
@@ -5227,6 +5228,25 @@ void SwFrame::PaintSwFrameShadowAndBorder(
             pBottomBorder = aAccess.Get()->GetBox().GetBottom();
         }
 
+        bool bWordTableCell = false;
+        SwViewShell* pShell = getRootFrame()->GetCurrShell();
+        if (pShell)
+        {
+            const IDocumentSettingAccess& rIDSA = 
pShell->GetDoc()->getIDocumentSettingAccess();
+            bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
+        }
+        bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() 
&& bWordTableCell;
+        if (bInWordTableCell)
+        {
+            // Compat mode: don't paint bottom border if we know the bottom of 
the content was cut
+            // off.
+            auto pContentFrame = static_cast<const SwContentFrame*>(this);
+            if (pContentFrame->IsUndersized())
+            {
+                pBottomBorder = nullptr;
+            }
+        }
+
         if(nullptr != pLeftBorder || nullptr != pRightBorder || nullptr != 
pTopBorder || nullptr != pBottomBorder)
         {
             // now we have all SvxBorderLine(s) sorted out, create geometry
@@ -5240,14 +5260,28 @@ void SwFrame::PaintSwFrameShadowAndBorder(
             const svx::frame::Style aStyleLeft(pLeftBorder, 1.0);
             drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
 
-            aBorderLineTarget.append(
-                drawinglayer::primitive2d::Primitive2DReference(
+            drawinglayer::primitive2d::Primitive2DReference aRetval(
                     new 
drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
                         aBorderTransform,
                         aStyleTop,
                         aStyleRight,
                         aStyleBottom,
-                        aStyleLeft)));
+                        aStyleLeft));
+
+            if (bInWordTableCell)
+            {
+                // Compat mode: cut off the borders which are outside of our 
own area.
+                const SwRect& rClip = getFrameArea();
+                basegfx::B2DRectangle aClip(rClip.Left(), rClip.Top(), 
rClip.Right(),
+                                            rClip.Bottom());
+                const basegfx::B2DPolyPolygon aPolyPolygon(
+                    basegfx::utils::createPolygonFromRect(aClip));
+                const drawinglayer::primitive2d::Primitive2DReference xClipped(
+                    new 
drawinglayer::primitive2d::MaskPrimitive2D(aPolyPolygon, { aRetval }));
+                aRetval = xClipped;
+            }
+
+            aBorderLineTarget.append(aRetval);
             gProp.pBLines->AddBorderLines(aBorderLineTarget);
         }
     }
diff --git a/vcl/source/gdi/mtfxmldump.cxx b/vcl/source/gdi/mtfxmldump.cxx
index 5e80e3f229f5..33eae5a38263 100644
--- a/vcl/source/gdi/mtfxmldump.cxx
+++ b/vcl/source/gdi/mtfxmldump.cxx
@@ -1032,6 +1032,30 @@ void MetafileXmlDump::writeXml(const GDIMetaFile& 
rMetaFile, tools::XmlWriter& r
                 // dumping the real polypolygon in the future
                 tools::Rectangle aRectangle = 
pMetaClipRegionAction->GetRegion().GetBoundRect();
                 writeRectangle(rWriter, aRectangle);
+
+                vcl::Region aRegion = pMetaClipRegionAction->GetRegion();
+
+                if (aRegion.HasPolyPolygonOrB2DPolyPolygon())
+                {
+                    tools::PolyPolygon aPolyPolygon = 
aRegion.GetAsPolyPolygon();
+
+                    for (sal_uInt16 j = 0; j < aPolyPolygon.Count(); ++j)
+                    {
+                        rWriter.startElement("polygon");
+                        tools::Polygon const& rPolygon = aPolyPolygon[j];
+                        bool bFlags = rPolygon.HasFlags();
+                        for (sal_uInt16 i = 0; i < rPolygon.GetSize(); ++i)
+                        {
+                            rWriter.startElement("point");
+                            writePoint(rWriter, rPolygon[i]);
+                            if (bFlags)
+                                rWriter.attribute("flags", 
convertPolygonFlags(rPolygon.GetFlags(i)));
+                            rWriter.endElement();
+                        }
+                        rWriter.endElement();
+                    }
+                }
+
                 rWriter.endElement();
             }
             break;

Reply via email to