sw/qa/core/layout/data/double-page-border.docx |binary sw/qa/core/layout/layout.cxx | 48 +++++++++++++++++++++++++ sw/source/core/layout/paintfrm.cxx | 23 +++++++++-- 3 files changed, 66 insertions(+), 5 deletions(-)
New commits: commit 60a1f07049a817d4d3d7beb6c9b9da2571e2463b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Feb 1 15:17:40 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Feb 2 09:09:48 2022 +0100 sw: fix swapped inner vs outer border for Word-style right/bottom page borders This is similar to commit cf2690ae76b4250af32be7c8980b8d83b3611591 (sw: fix swapped inner vs outer border for Word-style bottom table borders, 2022-01-13), but that was for outer table borders, this one is for page borders. The explicit mirroring is needed because Writer will automatically mirror, but Word mirrors in its document model, so we need to "mirror back" to get the matching rendering. Change-Id: I38fbf8adbc87ecd217a11b177840b0fede4cdf8c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129281 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/layout/data/double-page-border.docx b/sw/qa/core/layout/data/double-page-border.docx new file mode 100644 index 000000000000..a706b327cd05 Binary files /dev/null and b/sw/qa/core/layout/data/double-page-border.docx differ diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx index 8b8174d76941..a31646704cbd 100644 --- a/sw/qa/core/layout/layout.cxx +++ b/sw/qa/core/layout/layout.cxx @@ -694,6 +694,54 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testParaBorderInCellClip) assertXPath(pXmlDoc, "//clipregion/polygon", 2); } +CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoublePageBorder) +{ + // Given a page with a top and bottom double border, outer is thick, inner is thin: + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "double-page-border.docx"); + SwDocShell* pShell = pDoc->GetDocShell(); + + // When rendering that document: + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + + // Then make sure the top border is thick+thing and the bottom border is thin+thick (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[1], aBorderWidthVec[0]); + // Without the accompanying fix in place, this test would have failed with: + // - Expected greater than: 60 + // - Actual : 15 + // i.e. the bottom border was thick+thin, not thin+thick. + CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]); +} + 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 868817ff5147..82601c6334f6 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -5360,14 +5360,14 @@ void SwFrame::PaintSwFrameShadowAndBorder( pBottomBorder = aAccess.Get()->GetBox().GetBottom(); } - bool bWordTableCell = false; + bool bWordBorder = false; SwViewShell* pShell = getRootFrame()->GetCurrShell(); if (pShell) { const IDocumentSettingAccess& rIDSA = pShell->GetDoc()->getIDocumentSettingAccess(); - bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP); + bWordBorder = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP); } - bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() && bWordTableCell; + bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() && bWordBorder; if (bInWordTableCell) { // Compat mode: don't paint bottom border if we know the bottom of the content was cut @@ -5387,8 +5387,21 @@ void SwFrame::PaintSwFrameShadowAndBorder( aRect.Width(), aRect.Height(), aRect.Left(), aRect.Top())); const svx::frame::Style aStyleTop(pTopBorder, 1.0); - const svx::frame::Style aStyleRight(pRightBorder, 1.0); - const svx::frame::Style aStyleBottom(pBottomBorder, 1.0); + svx::frame::Style aStyleRight(pRightBorder, 1.0); + + // Right/bottom page borders are always mirrored in Word. + if (IsPageFrame() && bWordBorder) + { + aStyleRight.MirrorSelf(); + } + + svx::frame::Style aStyleBottom(pBottomBorder, 1.0); + + if (IsPageFrame() && bWordBorder) + { + aStyleBottom.MirrorSelf(); + } + const svx::frame::Style aStyleLeft(pLeftBorder, 1.0); drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;