diff --git a/sw/qa/extras/layout/data/toc-inline-heading-order.fodt b/sw/qa/extras/layout/data/toc-inline-heading-order.fodt
new file mode 100644
index 000000000000..d5fa5a9dbacf
--- /dev/null
+++ b/sw/qa/extras/layout/data/toc-inline-heading-order.fodt
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Foo
+ Bar boo
+
+
+ Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Table of Contents
+
+
+
+
+
+
diff --git a/sw/qa/extras/layout/layout6.cxx b/sw/qa/extras/layout/layout6.cxx
index adb0e855ee43..a5c2249a0723 100644
--- a/sw/qa/extras/layout/layout6.cxx
+++ b/sw/qa/extras/layout/layout6.cxx
@@ -2236,6 +2236,22 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170846_2)
assertXPath(pXmlDoc, "//page[2]//tab", 3); // Three tables on page 2
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTocInlineHeadingOrder)
+{
+ createSwDoc("toc-inline-heading-order.fodt");
+ dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // The TOC is the second section in the body. The body section's three
+ // txt children carry the entries in document order.
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout",
+ "portion", u"Foo");
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout",
+ "portion", u"Bar");
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout",
+ "portion", u" boo");
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testInlineTableShiftDown)
{
createSwDoc("floattable-center-shift-down.docx");
diff --git a/sw/source/core/inc/txmsrt.hxx b/sw/source/core/inc/txmsrt.hxx
index 324f88a90f23..bd0734d01aa9 100644
--- a/sw/source/core/inc/txmsrt.hxx
+++ b/sw/source/core/inc/txmsrt.hxx
@@ -162,6 +162,7 @@ struct SwTOXSortTabBase
private:
bool m_bValidText;
+ bool m_bAnchoredAsChar; // used by SwTOXSortTabBase::sort_lt to break ties
TextAndReading m_aSort;
virtual TextAndReading GetText_Impl(SwRootFrame const* pLayout) const = 0;
diff --git a/sw/source/core/tox/txmsrt.cxx b/sw/source/core/tox/txmsrt.cxx
index 58e8a5230d57..bd4b41449cc0 100644
--- a/sw/source/core/tox/txmsrt.cxx
+++ b/sw/source/core/tox/txmsrt.cxx
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -139,6 +140,7 @@ SwTOXSortTabBase::SwTOXSortTabBase( TOXSortType nTyp, const SwContentNode* pNd,
: pTOXNd( nullptr ), pTextMark( pMark ), pTOXIntl( pInter ),
nPos( 0 ), nCntPos( 0 ), nType( o3tl::narrowing(nTyp) )
, m_bValidText( false )
+ , m_bAnchoredAsChar( false )
{
if ( pLocale )
aLocale = *pLocale;
@@ -177,6 +179,10 @@ SwTOXSortTabBase::SwTOXSortTabBase( TOXSortType nTyp, const SwContentNode* pNd,
OSL_ENSURE(bResult, "where is the text node");
nPos = aPos.GetNodeIndex();
nCntPos = aPos.GetContentIndex();
+
+ const SwFrameFormat* pFlyFormat = pNd->GetFlyFormat();
+ if (pFlyFormat && pFlyFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+ m_bAnchoredAsChar = true;
}
}
else
@@ -291,8 +297,16 @@ bool SwTOXSortTabBase::sort_lt(const SwTOXSortTabBase& rCmp)
}
else if( pFirst && pFirst->IsTextNode() &&
pNext && pNext->IsTextNode() )
- return ::IsFrameBehind( *static_cast(pNext), nCntPos,
- *static_cast(pFirst), nCntPos );
+ {
+ // An inline (as-char) anchored fly's content is rendered
+ // at its anchor character position. If the character offset is same
+ // then the inline fly is rendered before the paragraph.
+ if (m_bAnchoredAsChar != rCmp.m_bAnchoredAsChar)
+ return m_bAnchoredAsChar;
+
+ return ::IsFrameBehind(*static_cast(pNext), nCntPos,
+ *static_cast(pFirst), nCntPos);
+ }
}
}
return false;
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index 544447d7e0a9..0aa15988c7fa 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -580,10 +580,25 @@ void SwContentType::FillMemberList(bool* pbContentChanged)
if (nLevel >= m_nOutlineLevel)
continue;
double nYPos = m_bAlphabeticSort ? 0 : static_cast(getYPos(*pNode));
- if (nEndOfExtrasIndex >= pNode->GetIndex() && pNode->GetFlyFormat())
+ const SwFrameFormat* pFlyFormat = pNode->GetFlyFormat();
+ if (nEndOfExtrasIndex >= pNode->GetIndex() && pFlyFormat)
{
- nYPos += nOutlinesInFramesIndexAdjustment;
- nOutlinesInFramesIndexAdjustment += 0.00001;
+ // For fly nodes getYPos() returns their anchor node's nYPos
+ const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
+ const SwPosition* pAnchorPos = rAnchor.GetContentAnchor();
+ if (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR && pAnchorPos
+ && pAnchorPos->GetContentIndex() == 0)
+ {
+ // An inline (as-char) fly anchored at the start of its
+ // anchor paragraph renders before the paragraph's own
+ // text. Place its outline entry before the anchor's nYPos.
+ nYPos -= 0.0001;
+ }
+ else
+ {
+ nYPos += nOutlinesInFramesIndexAdjustment;
+ nOutlinesInFramesIndexAdjustment += 0.00001;
+ }
}
auto pCnt(std::make_unique(this, aEntry, i, nLevel,