sw: Inline headings produce incorrect order in TOC
Inline headings are stored as flys anchored at the start of the paragraph. `SwTOXSortTabBase::sort_lt` is responsible for sorting the content of Table of Contents. Inline headings are not properly handled, which results in incorrect ordering of outline elements in TOC. Navigation panel also suffers with the same problem, where fly nodes are always assumed to render after the anchor paragraph. Handle as-char fly nodes which are positioned at the start of the anchor paragraph. Change-Id: Id3339b85fbae7731cfc5620477def1057ca15e31 Signed-off-by: Karthik <karthik.godha@collabora.com> Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2596 Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Tested-by: Caolán McNamara <caolan.mcnamara@collabora.com> (cherry picked from commit 745330e2d6f8c31193bdd10ba7e039a2aba6d6a8) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205781 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document
|
||||
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
||||
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
||||
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
||||
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
||||
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
office:version="1.4"
|
||||
office:mimetype="application/vnd.oasis.opendocument.text">
|
||||
<office:font-face-decls>
|
||||
<style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'"/>
|
||||
<style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'"/>
|
||||
</office:font-face-decls>
|
||||
<office:styles>
|
||||
<style:style style:name="Standard" style:family="paragraph" style:class="text"/>
|
||||
<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard"
|
||||
style:next-style-name="Standard" style:class="chapter">
|
||||
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm"
|
||||
style:contextual-spacing="false" fo:keep-with-next="always"/>
|
||||
<style:text-properties style:font-name="Liberation Sans" fo:font-size="14pt"/>
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph"
|
||||
style:parent-style-name="Heading" style:default-outline-level="1" style:class="chapter">
|
||||
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm"
|
||||
style:contextual-spacing="false"/>
|
||||
<style:text-properties fo:font-size="18pt" fo:font-weight="bold"/>
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph"
|
||||
style:parent-style-name="Heading" style:default-outline-level="2" style:class="chapter">
|
||||
<style:paragraph-properties fo:margin-top="0.353cm" fo:margin-bottom="0.212cm"
|
||||
style:contextual-spacing="false"/>
|
||||
<style:text-properties fo:font-size="16pt" fo:font-weight="bold"/>
|
||||
</style:style>
|
||||
<style:style style:name="Contents_20_1" style:display-name="Contents 1" style:family="paragraph"
|
||||
style:parent-style-name="Standard" style:class="index"/>
|
||||
<style:style style:name="Contents_20_2" style:display-name="Contents 2" style:family="paragraph"
|
||||
style:parent-style-name="Standard" style:class="index"/>
|
||||
<style:style style:name="Contents_20_Heading" style:display-name="Contents Heading"
|
||||
style:family="paragraph" style:parent-style-name="Heading" style:class="index">
|
||||
<style:text-properties fo:font-size="16pt" fo:font-weight="bold"/>
|
||||
</style:style>
|
||||
<style:style style:name="Index_20_Link" style:display-name="Index Link" style:family="text"/>
|
||||
<style:style style:name="Inline_20_Heading" style:display-name="Inline Heading" style:family="graphic">
|
||||
<style:graphic-properties text:anchor-type="as-char"
|
||||
svg:y="0cm" fo:margin-left="0cm" fo:margin-right="0cm"
|
||||
style:vertical-pos="middle" style:vertical-rel="text"
|
||||
fo:background-color="transparent" draw:fill="none"/>
|
||||
</style:style>
|
||||
</office:styles>
|
||||
<office:automatic-styles>
|
||||
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_1">
|
||||
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
|
||||
</style:style>
|
||||
<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Inline_20_Heading">
|
||||
<style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text"/>
|
||||
</style:style>
|
||||
<style:style style:name="Sect1" style:family="section">
|
||||
<style:section-properties>
|
||||
<style:columns fo:column-count="1" fo:column-gap="0cm"/>
|
||||
</style:section-properties>
|
||||
</style:style>
|
||||
<style:page-layout style:name="pm1">
|
||||
<style:page-layout-properties fo:page-width="21cm" fo:page-height="29.7cm"
|
||||
fo:margin-top="2cm" fo:margin-bottom="2cm"
|
||||
fo:margin-left="2cm" fo:margin-right="2cm"/>
|
||||
</style:page-layout>
|
||||
</office:automatic-styles>
|
||||
<office:master-styles>
|
||||
<style:master-page style:name="Standard" style:page-layout-name="pm1"/>
|
||||
</office:master-styles>
|
||||
<office:body>
|
||||
<office:text>
|
||||
<text:h text:style-name="Heading_20_1" text:outline-level="1">Foo</text:h>
|
||||
<text:h text:style-name="Heading_20_2" text:outline-level="2"><draw:frame draw:style-name="fr1" draw:name="Frame1" text:anchor-type="as-char" draw:z-index="0"><draw:text-box><text:h text:style-name="P1" text:outline-level="1">Bar</text:h></draw:text-box></draw:frame> boo</text:h>
|
||||
<text:table-of-content text:style-name="Sect1" text:protected="true" text:name="TOC1">
|
||||
<text:table-of-content-source text:outline-level="10">
|
||||
<text:index-title-template text:style-name="Contents_20_Heading">Table of Contents</text:index-title-template>
|
||||
<text:table-of-content-entry-template text:outline-level="1" text:style-name="Contents_20_1">
|
||||
<text:index-entry-link-start text:style-name="Index_20_Link"/>
|
||||
<text:index-entry-text/>
|
||||
<text:index-entry-link-end/>
|
||||
</text:table-of-content-entry-template>
|
||||
<text:table-of-content-entry-template text:outline-level="2" text:style-name="Contents_20_2">
|
||||
<text:index-entry-link-start text:style-name="Index_20_Link"/>
|
||||
<text:index-entry-text/>
|
||||
<text:index-entry-link-end/>
|
||||
</text:table-of-content-entry-template>
|
||||
</text:table-of-content-source>
|
||||
<text:index-body>
|
||||
<text:index-title text:style-name="Sect1" text:name="TOC1_Head">
|
||||
<text:p text:style-name="Contents_20_Heading">Table of Contents</text:p>
|
||||
</text:index-title>
|
||||
</text:index-body>
|
||||
</text:table-of-content>
|
||||
</office:text>
|
||||
</office:body>
|
||||
</office:document>
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <pam.hxx>
|
||||
#include <txttxmrk.hxx>
|
||||
#include <frmfmt.hxx>
|
||||
#include <fmtanchr.hxx>
|
||||
#include <fmtfld.hxx>
|
||||
#include <txmsrt.hxx>
|
||||
#include <ndtxt.hxx>
|
||||
@@ -139,6 +140,7 @@ SwTOXSortTabBase::SwTOXSortTabBase( TOXSortType nTyp, const SwContentNode* pNd,
|
||||
: pTOXNd( nullptr ), pTextMark( pMark ), pTOXIntl( pInter ),
|
||||
nPos( 0 ), nCntPos( 0 ), nType( o3tl::narrowing<sal_uInt16>(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<const SwTextNode*>(pNext), nCntPos,
|
||||
*static_cast<const SwTextNode*>(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<const SwTextNode*>(pNext), nCntPos,
|
||||
*static_cast<const SwTextNode*>(pFirst), nCntPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -580,10 +580,25 @@ void SwContentType::FillMemberList(bool* pbContentChanged)
|
||||
if (nLevel >= m_nOutlineLevel)
|
||||
continue;
|
||||
double nYPos = m_bAlphabeticSort ? 0 : static_cast<double>(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<SwOutlineContent>(this, aEntry, i, nLevel,
|
||||
|
||||
Reference in New Issue
Block a user