sw/qa/extras/ooxmlexport/data/tdf160077_layoutInCellD.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport20.cxx | 2 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx | 79 +++++++++++-- sw/source/writerfilter/dmapper/GraphicImport.cxx | 13 ++ 4 files changed, 86 insertions(+), 8 deletions(-)
New commits: commit 31f87f369fdb40fc746d98443d75af2e9ce2452d Author: Justin Luth <jl...@mail.com> AuthorDate: Wed Aug 7 15:05:45 2024 -0400 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Aug 9 08:47:39 2024 +0200 tdf#162211 tdf#160077 tdf#91632 layoutInCell: vert page->margin, *->top Microsoft's layoutInCell is very buggy for vertical orientation. So, instead of making our own implementation just as buggy, instead, alter the document so that the settings match the implementation. That way if MSO ever decides to re-fix layoutInCell, we are in a position to easily avoid the mapping to accommodate a new compat version. make CppunitTest_sw_ooxmlexport21 \ CPPUNIT_TEST_NAME=testTdf160077_layoutInCellD Change-Id: Ic02a9b12226fd510656444ed37be470455bc4370 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171433 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins Reviewed-by: Justin Luth <jl...@mail.com> diff --git a/sw/qa/extras/ooxmlexport/data/tdf160077_layoutInCellD.docx b/sw/qa/extras/ooxmlexport/data/tdf160077_layoutInCellD.docx new file mode 100644 index 000000000000..aabbb5511244 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf160077_layoutInCellD.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx index d7fb460f8b8f..a2bbf5d200bd 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx @@ -241,7 +241,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf128646) auto xShape = getShapeByName(u"Kép 1"); CPPUNIT_ASSERT(getProperty<bool>(xShape, u"IsFollowingTextFlow"_ustr)); // the vertical offset has to be applied against the cell borders, not anchor paragraph (FRAME) - CPPUNIT_ASSERT_EQUAL(text::RelOrientation::PAGE_FRAME, + CPPUNIT_ASSERT_EQUAL(text::RelOrientation::PAGE_PRINT_AREA, getProperty<sal_Int16>(xShape, u"VertOrientRelation"_ustr)); // the shape is "from page top", which for layoutInCell is to be applied from cell top diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx index 220641845563..1dfc27e14584 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx @@ -556,7 +556,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf160077_layoutInCellB, "tdf160077_layoutInCellB.d // CPPUNIT_ASSERT_DOUBLES_EQUAL(888, nShapeTop, 50); const auto& xShape = getShapeByName(u"Group 1"); - CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_FRAME, + CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_PRINT_AREA, getProperty<sal_Int16>(xShape, u"VertOrientRelation"_ustr)); CPPUNIT_ASSERT(getProperty<bool>(xShape, u"IsFollowingTextFlow"_ustr)); @@ -569,26 +569,91 @@ DECLARE_OOXMLEXPORT_TEST(testTdf160077_layoutInCellC, "tdf160077_layoutInCellC.d // This test anchors the image on paragraph 5 - proving vertical cannot change to FRAME. xmlDocUniquePtr pDump = parseLayoutDump(); - const sal_Int32 nCellTop - = getXPath(pDump, "//row[1]/cell[2]/infos/bounds"_ostr, "top"_ostr).toInt32(); const sal_Int32 nPara1Top = getXPath(pDump, "//row[1]/cell[2]/txt[1]/infos/bounds"_ostr, "top"_ostr).toInt32(); + const sal_Int32 nPara1Bottom + = getXPath(pDump, "//row[1]/cell[2]/txt[1]/infos/bounds"_ostr, "bottom"_ostr).toInt32(); const sal_Int32 nImageTop = getXPath(pDump, "//row[1]/cell[2]/txt[5]/anchored/SwAnchoredDrawObject/bounds"_ostr, "top"_ostr) .toInt32(); // The image's top should be positioned at the start of the cell's text area (i.e. para1 top) - // Before the revert, the image was positioned at the top of para 5. - CPPUNIT_ASSERT_LESS(nPara1Top, nImageTop); // Image not lower than para 1 + // Before the fix, the image was positioned at the top of the cell. + CPPUNIT_ASSERT_LESS(nPara1Bottom, nImageTop); // Image shouldn't start lower than para 1 // The image must be limited to the top of the cell, not the page - CPPUNIT_ASSERT_GREATER(nCellTop, nImageTop); // Image is lower (greater) than top of cell + CPPUNIT_ASSERT_GREATEREQUAL(nPara1Top, nImageTop); // Image shouldn't start higher than para 1 - CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_FRAME, + CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_PRINT_AREA, getProperty<sal_Int16>(getShape(1), u"VertOrientRelation"_ustr)); // LayoutInCell must be enforced, to keep the image inside the cell boundaries CPPUNIT_ASSERT(getProperty<bool>(getShape(1), u"IsFollowingTextFlow"_ustr)); } +DECLARE_OOXMLEXPORT_TEST(testTdf160077_layoutInCellD, "tdf160077_layoutInCellD.docx") +{ + // given a table with two layoutInCell images, and cell A1 has 1/2 inch border padding (margin) + // - A1 contains an image, vertically aligned to the bottom of the page (aka cell) + // - B1 contains an image, vertically aligned to the bottom of the page margin (aka cell margin) + + // In Microsoft's layoutInCell implementation, vertical "page" is identical to "margin", + // and everything (including bottom) actually is oriented to the top of the margin. + + xmlDocUniquePtr pDump = parseLayoutDump(); + // Cell A1 + sal_Int32 nShapeTop + = getXPath(pDump, "//tab/row[1]/cell[1]/txt[1]/anchored/fly/SwAnchoredObject/bounds"_ostr, + "top"_ostr) + .toInt32(); + sal_Int32 nShapeBottom + = getXPath(pDump, "//tab/row[1]/cell[1]/txt[1]/anchored/fly/SwAnchoredObject/bounds"_ostr, + "bottom"_ostr) + .toInt32(); + // use paragraph 1 to indicate where the cell spacing/padding ends, and the text starts. + sal_Int32 nPara1Top + = getXPath(pDump, "//tab/row[1]/cell[1]/txt[1]/infos/bounds"_ostr, "top"_ostr).toInt32(); + // use paragraph 5 to prove the image is not at the bottom. + CPPUNIT_ASSERT_EQUAL(OUString("Below logo"), + getXPathContent(pDump, "//tab/row[1]/cell[1]/txt[5]"_ostr)); + sal_Int32 nPara5Top + = getXPath(pDump, "//tab/row[1]/cell[1]/txt[5]/infos/bounds"_ostr, "top"_ostr).toInt32(); + CPPUNIT_ASSERT_EQUAL(nShapeTop, nPara1Top); + CPPUNIT_ASSERT(nPara5Top > nShapeBottom); // ShapeBottom is higher than Para5Top + + // In the file it is specified as "page" (PAGE_FRAME), but implemented as if it were "margin" + // so on import we intentionally changed it to match the closest setting to the implementation. + const auto& xShape = getShapeByName(u"logo"); + CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_PRINT_AREA, + getProperty<sal_Int16>(xShape, u"VertOrientRelation"_ustr)); + + CPPUNIT_ASSERT(getProperty<bool>(xShape, u"IsFollowingTextFlow"_ustr)); + + // Cell B1 + nShapeTop + = getXPath(pDump, "//tab/row[1]/cell[2]/txt[1]/anchored/fly/SwAnchoredObject/bounds"_ostr, + "top"_ostr) + .toInt32(); + nShapeBottom + = getXPath(pDump, "//tab/row[1]/cell[2]/txt[1]/anchored/fly/SwAnchoredObject/bounds"_ostr, + "bottom"_ostr) + .toInt32(); + // use paragraph 1 to indicate where the cell spacing/padding ends, and the text starts. + nPara1Top + = getXPath(pDump, "//tab/row[1]/cell[2]/txt[1]/infos/bounds"_ostr, "top"_ostr).toInt32(); + // use paragraph 5 to prove the image is not at the bottom. + CPPUNIT_ASSERT_EQUAL(OUString("Below image"), + getXPathContent(pDump, "//tab/row[1]/cell[2]/txt[5]"_ostr)); + nPara5Top + = getXPath(pDump, "//tab[1]/row/cell[2]/txt[5]/infos/bounds"_ostr, "top"_ostr).toInt32(); + CPPUNIT_ASSERT_EQUAL(nShapeTop, nPara1Top); + CPPUNIT_ASSERT(nPara5Top > nShapeBottom); // ShapeBottom is higher than Para5Top + + const auto& xShape2 = getShapeByName(u"logoInverted"); + CPPUNIT_ASSERT_EQUAL(css::text::RelOrientation::PAGE_PRINT_AREA, + getProperty<sal_Int16>(xShape2, u"VertOrientRelation"_ustr)); + + CPPUNIT_ASSERT(getProperty<bool>(xShape2, u"IsFollowingTextFlow"_ustr)); +} + DECLARE_OOXMLEXPORT_TEST(testTdf153909_followTextFlow, "tdf153909_followTextFlow.docx") { // given a compat12 VML document with wrap-through blue rect that doesn't mention allowInCell diff --git a/sw/source/writerfilter/dmapper/GraphicImport.cxx b/sw/source/writerfilter/dmapper/GraphicImport.cxx index 12f9b0038d17..23709e8e63b1 100644 --- a/sw/source/writerfilter/dmapper/GraphicImport.cxx +++ b/sw/source/writerfilter/dmapper/GraphicImport.cxx @@ -830,6 +830,19 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue) rValue.getAny( ) >>= xShape; if ( xShape.is( ) ) { + if (m_pImpl->m_bLayoutInCell && m_pImpl->m_rDomainMapper.IsInTable()) + { + // Microsoft is buggy and inconsistent in how they handle layoutInCell. + // Map wrongly-implemented settings to the closest implemented setting + + // "page" is implemented as if it was "margin" - to cell spacing, not edge + if (m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME) + m_pImpl->m_nVertRelation = text::RelOrientation::PAGE_PRINT_AREA; + // only "from top" and "top" are appropriate. Others are implemented as Top + if (m_pImpl->m_nVertOrient != text::VertOrientation::NONE) + m_pImpl->m_nVertOrient = text::VertOrientation::TOP; + } + // Is it a graphic image bool bUseShape = true; try