sw/qa/core/unocore/data/floattable-outer-nonsplit-inner.docx |binary
 sw/qa/core/unocore/unocore.cxx                               |   23 +++++++
 sw/source/core/unocore/unotext.cxx                           |   32 +++++++++--
 3 files changed, 52 insertions(+), 3 deletions(-)

New commits:
commit c374628126ad222be48d5d06857b7dc6b879f783
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jun 13 08:15:34 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Jun 13 09:01:08 2023 +0200

    sw floattable: fix anchor position of inner floating table
    
    The bugdoc has an outer, split floating table and an inner, non-split
    floating table. The anchor of the inner table was wrong: both were
    anchored in the only paragraph in the body text, while the inner
    floating table should be anchored inside the outer floating table.
    
    The reason for this is commit 9592f56323de27f9e1d890ee6259a5f4f328cbd3
    (n#695479 fix anchor handling in SwXText::convertToTextFrame(),
    2012-02-20), which was necessary to make sure that old-style frames
    after each other are all anchored to the body text, not inside each
    other.
    
    Fix the problem by leaving the behavior unchanged for empty paragraphs,
    but at least when the inner anchor is to-para, the last paragraph of a fly
    content is non-empty and the outer fly range contains the entire last
    paragraph, then consider such a fly as "inside" the outer fly content,
    rather than something that has to be moved so the anchor is still in the
    body text.
    
    CppunitTest_sw_rtfimport's testN695479, CppunitTest_sw_ooxmlexport10's
    testFloatingTablesAnchor and CppunitTest_sw_ooxmlexport13's testFlyInFly
    are all related tests and they continue to work after this change.
    
    Change-Id: I30ed1d884ec465e724b4f133640b9608845a44fe
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152950
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/unocore/data/floattable-outer-nonsplit-inner.docx 
b/sw/qa/core/unocore/data/floattable-outer-nonsplit-inner.docx
new file mode 100644
index 000000000000..dc213b1b0d26
Binary files /dev/null and 
b/sw/qa/core/unocore/data/floattable-outer-nonsplit-inner.docx differ
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 55b37c749436..605813a719b3 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -29,6 +29,7 @@
 #include <textlinebreak.hxx>
 #include <textcontentcontrol.hxx>
 #include <frmmgr.hxx>
+#include <fmtcntnt.hxx>
 
 using namespace ::com::sun::star;
 
@@ -930,6 +931,28 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testFlySplit)
     CPPUNIT_ASSERT(bIsSplitAllowed);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testConvertToTextFrame)
+{
+    // Given a document with 2 non-interesting frames, an inner frame and an 
outer frame:
+    createSwDoc("floattable-outer-nonsplit-inner.docx");
+
+    // When checking the anchor of the inner frame:
+    SwDoc* pDoc = getSwDoc();
+    const sw::FrameFormats<sw::SpzFrameFormat*>& rFrames = 
*pDoc->GetSpzFrameFormats();
+    sw::SpzFrameFormat* pFrame3 = rFrames.FindFrameFormatByName("Frame3");
+    SwNodeIndex aFrame3Anchor = pFrame3->GetAnchor().GetContentAnchor()->nNode;
+
+    // Then make sure it's anchored in the outer frame's last content node:
+    sw::SpzFrameFormat* pFrame4 = rFrames.FindFrameFormatByName("Frame4");
+    SwPaM 
aPaM(*pFrame4->GetContent().GetContentIdx()->GetNode().EndOfSectionNode());
+    aPaM.Move(fnMoveBackward, GoInContent);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: SwNodeIndex (node 27)
+    // - Actual  : SwNodeIndex (node 49)
+    // i.e. Frame3 was anchored much later, in the body text, not in Frame4.
+    CPPUNIT_ASSERT_EQUAL(aPaM.GetPoint()->nNode, aFrame3Anchor);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unotext.cxx 
b/sw/source/core/unocore/unotext.cxx
index b506b3a26183..4fede9da65b4 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -1494,6 +1494,34 @@ static bool isGraphicNode(const SwFrameFormat* 
pFrameFormat)
     return index.GetNode().IsGrfNode();
 }
 
+/// Determines if the at-para rAnchor is anchored at the start or end of 
rAnchorCheckPam.
+static bool IsAtParaMatch(const SwPaM& rAnchorCheckPam, const SwFormatAnchor& 
rAnchor)
+{
+    if (rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PARA)
+    {
+        return false;
+    }
+
+    if (rAnchorCheckPam.Start()->GetNode() == *rAnchor.GetAnchorNode())
+    {
+        return true;
+    }
+
+    if (rAnchorCheckPam.End()->GetNode() == *rAnchor.GetAnchorNode())
+    {
+        SwTextNode* pEndTextNode = 
rAnchorCheckPam.End()->GetNode().GetTextNode();
+        if (pEndTextNode && rAnchorCheckPam.End()->GetContentIndex() == 
pEndTextNode->Len())
+        {
+            // rAnchorCheckPam covers the entire last text node, rAnchor is 
at-para, consider this
+            // as "inside pam" rather than "at the end of pam".
+            return false;
+        }
+        return true;
+    }
+
+    return false;
+}
+
 // move previously appended paragraphs into a text frames
 // to support import filters
 uno::Reference< text::XTextContent > SAL_CALL
@@ -1672,9 +1700,7 @@ SwXText::convertToTextFrame(
         // and testFloatingTablesAnchor for why it excludes pre/post table
         // added nodes
         if (!isGraphicNode(pFrameFormat)
-            && (   (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()
-                    && (    oAnchorCheckPam->Start()->GetNode() == 
*rAnchor.GetAnchorNode()
-                        ||  oAnchorCheckPam->End()->GetNode() == 
*rAnchor.GetAnchorNode()))
+            && (IsAtParaMatch(*oAnchorCheckPam, rAnchor)
                 || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()
                     && (    *oAnchorCheckPam->Start() == 
*rAnchor.GetContentAnchor()
                         ||  *oAnchorCheckPam->End() == 
*rAnchor.GetContentAnchor()))))

Reply via email to