sw/qa/extras/ooxmlexport/data/tdf162551_notLayoutInCell_charLeft_fromTop.docx 
|binary
 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx                                    
|   21 ++++++++++
 sw/qa/extras/ww8export/ww8export4.cxx                                         
|   21 +++++-----
 sw/source/filter/ww8/wrtw8esh.cxx                                             
|    4 +
 sw/source/filter/ww8/ww8graf.cxx                                              
|   21 ++++++++--
 sw/source/writerfilter/dmapper/GraphicImport.cxx                              
|   15 +++++++
 6 files changed, 70 insertions(+), 12 deletions(-)

New commits:
commit 0640a0f673635f861a28d14d21e40599e7a54553
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Thu Aug 22 16:46:18 2024 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Sat Aug 24 14:34:59 2024 +0200

    tdf#162551 mso formats: line(vert) or char(hori) forces layoutInCell
    
    Already DOCX compat15 always forces layoutInCell,
    but even earlier than 2013, if the shape is oriented
    vertically to the line, or horizontally to the character
    then everything is treated as if it was layoutInCell.
    
    So let's make it explicit while we import.
    That seems to make the most sense.
    
    make CppunitTest_sw_ooxmlexport21 CPPUNIT_TEST_NAME=testTdf162551
    make CppunitTest_sw_ww8export4 CPPUNIT_TEST_NAME=testTdf162542
    
    No existing unit tests found.
    
    Change-Id: Ibdb4933e248c86ab595df68f81fad1f23345c2a2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172296
    Reviewed-by: Justin Luth <jl...@mail.com>
    Tested-by: Jenkins

diff --git 
a/sw/qa/extras/ooxmlexport/data/tdf162551_notLayoutInCell_charLeft_fromTop.docx 
b/sw/qa/extras/ooxmlexport/data/tdf162551_notLayoutInCell_charLeft_fromTop.docx
new file mode 100644
index 000000000000..20609bf733b6
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf162551_notLayoutInCell_charLeft_fromTop.docx 
differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
index a3a60c2973cf..a7c46b536f95 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
@@ -676,6 +676,27 @@ DECLARE_OOXMLEXPORT_TEST(testTdf153909_followTextFlow, 
"tdf153909_followTextFlow
     CPPUNIT_ASSERT(nTableLeft > nRectLeft);
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf162551, 
"tdf162551_notLayoutInCell_charLeft_fromTop.docx")
+{
+    // given cell B2 with a para-fromTop, char-left image that is NOT 
layoutInCell
+    // (but Microsoft sees the CHAR orientation and triggers a layoutInCell 
anyway)
+    xmlDocUniquePtr pDump = parseLayoutDump();
+    sal_Int32 nShapeTop
+        = getXPath(pDump, 
"//tab/row[2]/cell[2]/txt/anchored/fly/SwAnchoredObject/bounds"_ostr,
+                   "top"_ostr)
+              .toInt32();
+    // sal_Int32 nPara1Top
+    //     = getXPath(pDump, "//tab/row[2]/cell[2]/txt/infos/bounds"_ostr, 
"top"_ostr).toInt32();
+    sal_Int32 nCellTop
+        = getXPath(pDump, "//tab/row[2]/cell[2]/infos/bounds"_ostr, 
"top"_ostr).toInt32();
+    // The image is limited by the cell boundaries (should be limited to cell 
margin actually)
+    CPPUNIT_ASSERT(nCellTop <= nShapeTop);
+    // CPPUNIT_ASSERT_EQUAL(nPara1Top, nShapeTop); // tdf#162539
+
+    // since in fact layoutInCell is supposed to be applied, we mark (and 
export) as layoutInCell
+    CPPUNIT_ASSERT(getProperty<bool>(getShape(1), 
u"IsFollowingTextFlow"_ustr));
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf159207_footerFramePrBorder)
 {
     loadFromFile(u"tdf159207_footerFramePrBorder.docx"); // re-imports as 
editeng Frame/Shape
diff --git a/sw/qa/extras/ww8export/ww8export4.cxx 
b/sw/qa/extras/ww8export/ww8export4.cxx
index 1266a2a06977..3e881a5114c2 100644
--- a/sw/qa/extras/ww8export/ww8export4.cxx
+++ b/sw/qa/extras/ww8export/ww8export4.cxx
@@ -203,15 +203,18 @@ DECLARE_WW8EXPORT_TEST(testTdf162542, 
"tdf162542_notLayoutInCell_charLeft_wrapTh
         = getXPath(pDump, "//tab/row[2]/cell[2]/txt[6]/infos/bounds"_ostr, 
"left"_ostr).toInt32();
     CPPUNIT_ASSERT(nShapeLeft > nPara6Left); // nShapeLeft starts after the 
word "anchor"
 
-    // sal_Int32 nShapeTop
-    //     = getXPath(pDump, 
"//tab/row[2]/cell[2]/txt[6]/anchored/fly/SwAnchoredObject/bounds"_ostr,
-    //                "top"_ostr)
-    //           .toInt32();
-    // sal_Int32 nPara1Top
-    //     = getXPath(pDump, "//tab/row[2]/cell[2]/txt[1]/infos/bounds"_ostr, 
"top"_ostr).toInt32();
-    // CPPUNIT_ASSERT_EQUAL(nPara1Top, nShapeTop); // nShapeTop starts at the 
cell margin"
-
-    CPPUNIT_ASSERT(!getProperty<bool>(getShape(1), 
u"IsFollowingTextFlow"_ustr));
+    // tdf#162551: The top is oriented to the top of the page - but MSO treats 
it as layoutInCell
+    sal_Int32 nShapeTop
+        = getXPath(pDump, 
"//tab/row[2]/cell[2]/txt[6]/anchored/fly/SwAnchoredObject/bounds"_ostr,
+                   "top"_ostr)
+              .toInt32();
+    sal_Int32 nPara1Top
+        = getXPath(pDump, "//tab/row[2]/cell[2]/txt[1]/infos/bounds"_ostr, 
"top"_ostr).toInt32();
+    // layoutInCell uses the cell margin as the top-most point, not the cell 
edge
+    CPPUNIT_ASSERT_EQUAL(nPara1Top, nShapeTop); // nShapeTop starts at the 
cell margin"
+
+    // since in fact layoutInCell is supposed to be applied, we mark (and 
export) as layoutInCell
+    CPPUNIT_ASSERT(getProperty<bool>(getShape(1), 
u"IsFollowingTextFlow"_ustr)); // tdf#162551
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testEndnotesAtSectEndDOC)
diff --git a/sw/source/filter/ww8/wrtw8esh.cxx 
b/sw/source/filter/ww8/wrtw8esh.cxx
index 9513c42d4d01..c1066d355569 100644
--- a/sw/source/filter/ww8/wrtw8esh.cxx
+++ b/sw/source/filter/ww8/wrtw8esh.cxx
@@ -2707,6 +2707,10 @@ void WinwordAnchoring::SetAnchoring(const SwFrameFormat& 
rFormat)
     // so do nothing unless "Follow text flow" is disabled (which is the 
default in native LO).
     bool bLayoutInCell = rFormat.GetFollowTextFlow().GetValue();
 
+    // Microsoft will treat any orientation to CHAR or TEXT_LINE as if it had 
to layoutInCell
+    if (!bLayoutInCell)
+        bLayoutInCell = mnYRelTo == 3 || mnXRelTo == 3;
+
     // If this is already MSO format, then we need to round-trip a false 
FollowingTextFlow value
     const bool bIsMSOLayout = rFormat.getIDocumentSettingAccess().get(
         DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
diff --git a/sw/source/filter/ww8/ww8graf.cxx b/sw/source/filter/ww8/ww8graf.cxx
index bdce9d5e340c..222685102019 100644
--- a/sw/source/filter/ww8/ww8graf.cxx
+++ b/sw/source/filter/ww8/ww8graf.cxx
@@ -2312,6 +2312,8 @@ RndStdIds 
SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec& rRecord, WW8_FS
                                               SfxItemSet &rFlySet)
 {
     bool bCurSectionVertical = m_aSectionManager.CurrentSectionIsVertical();
+    bool bIsObjectLayoutInTableCell
+        = m_nInTable && 
IsObjectLayoutInTableCell(rRecord.nGroupShapeBooleanProperties);
 
     if (!rRecord.nXRelTo)
     {
@@ -2417,6 +2419,20 @@ RndStdIds 
SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec& rRecord, WW8_FS
         text::RelOrientation::TEXT_LINE   // 3 is relative to line
     };
 
+    if (!bIsObjectLayoutInTableCell && m_nInTable && eAnchor == 
RndStdIds::FLY_AT_CHAR)
+    {
+        // Microsoft apparently forces layoutInCell behaviour
+        // if either horizontal orientation is based on character
+        // or vertical orientation is based on line
+        // so make it explicit instead of trying to hack in tons of 
adjustments.
+        if (aVertRelOriTab[nYRelTo] == text::RelOrientation::TEXT_LINE
+            || aHoriRelOriTab[nXRelTo] == text::RelOrientation::CHAR)
+        {
+            bIsObjectLayoutInTableCell = true;
+            rFlySet.Put(SwFormatFollowTextFlow(true));
+        }
+    }
+
     // If the image is inline, then the relative orientation means nothing,
     // so set it up so that if the user changes it into an anchor, it 
positions usefully.
     sal_Int16 eHoriOri
@@ -2468,9 +2484,6 @@ RndStdIds 
SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec& rRecord, WW8_FS
     // if the object is anchored inside a table cell, is horizontal aligned
     // at frame and has wrap through, but its attribute
     // 'layout in table cell' isn't set, convert its horizontal alignment to 
page text area.
-    // #i84783# - use new method <IsObjectLayoutInTableCell()>
-    const bool bIsObjectLayoutInTableCell
-        = m_nInTable && 
IsObjectLayoutInTableCell(rRecord.nGroupShapeBooleanProperties);
     if (!bIsObjectLayoutInTableCell && m_nInTable &&
             (eHoriRel == text::RelOrientation::FRAME) &&
             rFSPA.nwr == 3)
@@ -2536,6 +2549,8 @@ RndStdIds 
SwWW8ImplReader::ProcessEscherAlign(SvxMSDffImportRec& rRecord, WW8_FS
 }
 
 // #i84783#
+// Return whether the fly specifies layoutInCell.
+// (NOTE: there are circumstances where layoutInCell is implemented even when 
set to false)
 bool SwWW8ImplReader::IsObjectLayoutInTableCell(const sal_uInt32 
nGroupShapeBooleanProperties) const
 {
     bool bIsObjectLayoutInTableCell = false;
diff --git a/sw/source/writerfilter/dmapper/GraphicImport.cxx 
b/sw/source/writerfilter/dmapper/GraphicImport.cxx
index ff08d87b0428..e7332d1245a8 100644
--- a/sw/source/writerfilter/dmapper/GraphicImport.cxx
+++ b/sw/source/writerfilter/dmapper/GraphicImport.cxx
@@ -830,6 +830,21 @@ void GraphicImport::lcl_attribute(Id nName, const Value& 
rValue)
                 rValue.getAny( ) >>= xShape;
                 if ( xShape.is( ) )
                 {
+                    if (!m_pImpl->m_bLayoutInCell && 
m_pImpl->m_rDomainMapper.IsInTable()
+                        && m_pImpl->m_rGraphicImportType == 
IMPORT_AS_DETECTED_ANCHOR)
+                    {
+                        // Microsoft apparently forces layoutInCell behaviour
+                        // if either horizontal orientation is based on 
character
+                        // or vertical orientation is based on line
+                        // so make it explicit instead of trying to hack in 
tons of adjustments.
+                        if (m_pImpl->m_nVertRelation == 
text::RelOrientation::TEXT_LINE
+                            || m_pImpl->m_nHoriRelation == 
text::RelOrientation::CHAR)
+                        {
+                            m_pImpl->m_bLayoutInCell = true;
+                            m_pImpl->m_bCompatForcedLayoutInCell = true;
+                        }
+                    }
+
                     if (m_pImpl->m_bLayoutInCell && 
m_pImpl->m_rDomainMapper.IsInTable())
                     {
                         // Microsoft is buggy and inconsistent in how they 
handle layoutInCell.

Reply via email to