cool#16071 sw: do not lose footnote lines cut away to fit
RearrangeFootnotes may cause SetRstHeight to set the rest height to 0 for footnote lines no more fitting the footnote area; but 0 was used as a special value in IsInside, meaning "no rest height was set", which then incorrectly measured the upper instead - still as tall as the lines the frame had before the truncation. Then the frame was considered as having enough space, marked valid, and the lines cut away from it got no follow to move to, so they never appeared anywhere. Give the rest height its own "not given" state instead of spelling that as a number, and honour a height of zero for what it says. A magic negative would not do: SwContentFrame::WouldFit_ passes a negative height when the frames before it overfill the new upper, and that has to keep meaning that no line fits. The footnote computation in the constructor still falls back to the upper when it ends up at or below zero, so only the SetRstHeight path changes behaviour. Signed-off-by: Mike Kaganski <mike.kaganski@collabora.com> Change-Id: If692577f3ee692ad5c0dbe87f9a11a2670f8cf16 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/8906 Tested-by: Jenkins CPCI <releng@collaboraoffice.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 77634c741bb538853a757c2a41e4c9b919f22815) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209271 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org> Tested-by: Jenkins
This commit is contained in:
committed by
Xisco Fauli
parent
50ce488d18
commit
44c92622d2
@@ -0,0 +1,60 @@
|
||||
<?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:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" 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-family-generic="roman"/>
|
||||
</office:font-face-decls>
|
||||
<office:automatic-styles>
|
||||
<style:style style:name="Tbl" style:family="table">
|
||||
<style:table-properties style:width="8cm" table:align="left" style:may-break-between-rows="true"/>
|
||||
</style:style>
|
||||
<style:style style:name="TblCol" style:family="table-column">
|
||||
<style:table-column-properties style:column-width="8cm"/>
|
||||
</style:style>
|
||||
<style:style style:name="Row1" style:family="table-row">
|
||||
<style:table-row-properties style:row-height="5.8cm"/>
|
||||
</style:style>
|
||||
<style:style style:name="Row2" style:family="table-row">
|
||||
<style:table-row-properties style:row-height="2cm"/>
|
||||
</style:style>
|
||||
<style:style style:name="Row3" style:family="table-row">
|
||||
<style:table-row-properties style:row-height="3cm"/>
|
||||
</style:style>
|
||||
<style:style style:name="Row4" style:family="table-row">
|
||||
<style:table-row-properties style:row-height="2cm"/>
|
||||
</style:style>
|
||||
<style:style style:name="PFtn" style:family="paragraph" style:parent-style-name="Footnote">
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-size="10pt"/>
|
||||
</style:style>
|
||||
<style:style style:name="Cell" style:family="table-cell">
|
||||
<style:table-cell-properties fo:padding="0cm" fo:border="0.5pt solid #000000"/>
|
||||
</style:style>
|
||||
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-size="12pt"/>
|
||||
</style:style>
|
||||
<style:page-layout style:name="PM1">
|
||||
<style:page-layout-properties fo:page-width="10cm" fo:page-height="8cm" style:print-orientation="portrait" fo:margin-top="1cm" fo:margin-bottom="1cm" fo:margin-left="1cm" fo:margin-right="1cm"/>
|
||||
</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>
|
||||
<table:table table:name="T1" table:style-name="Tbl">
|
||||
<table:table-column table:style-name="TblCol"/>
|
||||
<table:table-row table:style-name="Row1">
|
||||
<table:table-cell table:style-name="Cell" office:value-type="string"><text:p text:style-name="P1">Row 1<text:note text:id="ftn1" text:note-class="footnote"><text:note-citation>1</text:note-citation><text:note-body><text:p text:style-name="PFtn">alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango uniform victor whiskey xray yankee zulu alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango uniform victor whiskey xray yankee zulu alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango uniform victor whiskey xray yankee zulu alpha bravo charlie delta echo foxtrot golf hotel india juliet filler</text:p></text:note-body></text:note></text:p></table:table-cell>
|
||||
</table:table-row>
|
||||
<table:table-row table:style-name="Row2">
|
||||
<table:table-cell table:style-name="Cell" office:value-type="string"><text:p text:style-name="P1">Row 2</text:p></table:table-cell>
|
||||
</table:table-row>
|
||||
<table:table-row table:style-name="Row3">
|
||||
<table:table-cell table:style-name="Cell" office:value-type="string"><text:p text:style-name="P1">Row 3</text:p></table:table-cell>
|
||||
</table:table-row>
|
||||
<table:table-row table:style-name="Row4">
|
||||
<table:table-cell table:style-name="Cell" office:value-type="string"><text:p text:style-name="P1">Row 4<text:note text:id="ftn2" text:note-class="footnote"><text:note-citation>2</text:note-citation><text:note-body><text:p text:style-name="PFtn">alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra TAILMARK</text:p></text:note-body></text:note></text:p></table:table-cell>
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
</office:text>
|
||||
</office:body>
|
||||
</office:document>
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <com/sun/star/text/WrapTextMode.hpp>
|
||||
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
|
||||
#include <vcl/event.hxx>
|
||||
#include <vcl/pdf/PDFPageObjectType.hxx>
|
||||
#include <vcl/scheduler.hxx>
|
||||
#include <editeng/fontitem.hxx>
|
||||
#include <editeng/fhgtitem.hxx>
|
||||
@@ -1610,6 +1611,38 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testCool16067_footnoteSpaceFreedBySplit)
|
||||
assertXPath(pXmlDoc, "//page[4]/body/tab/row", 1);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testCool16071_footnoteTailKeptWhenTruncated)
|
||||
{
|
||||
// The first row's footnote fills the footnote area of the page it ends up on, and the last
|
||||
// row travels between pages carrying a footnote of three lines. That leaves the lines after
|
||||
// the first formatted against a footnote area with no room for them.
|
||||
createSwDoc("Cool16071_footnoteTailKeptWhenTruncated.fodt");
|
||||
// A layout dump would format what it reads, and that alone repairs the frame: measure the
|
||||
// export instead.
|
||||
save(TestFilter::PDF_WRITER);
|
||||
std::unique_ptr<vcl::pdf::PDFiumDocument> pPdf = parsePDFExport();
|
||||
if (!pPdf)
|
||||
return;
|
||||
|
||||
// the last word of the last footnote, on its third line
|
||||
bool bTailExported = false;
|
||||
for (int nPage = 0; nPage < pPdf->getPageCount() && !bTailExported; ++nPage)
|
||||
{
|
||||
std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdf->openPage(nPage);
|
||||
std::unique_ptr<vcl::pdf::PDFiumTextPage> pTextPage = pPage->getTextPage();
|
||||
for (int i = 0; i < pPage->getObjectCount() && !bTailExported; ++i)
|
||||
{
|
||||
std::unique_ptr<vcl::pdf::PDFiumPageObject> pObject = pPage->getObject(i);
|
||||
if (pObject->getType() == vcl::pdf::PDFPageObjectType::Text)
|
||||
bTailExported = pObject->getText(pTextPage).indexOf("TAILMARK") >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Without the fix the footnote kept its first line only: the two lines cut away from it had
|
||||
// nowhere to go, so their text was missing from the document altogether.
|
||||
CPPUNIT_ASSERT(bTailExported);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testHiddenParagraphFollowFrame)
|
||||
{
|
||||
createSwDoc("hidden-para-follow-frame.fodt");
|
||||
|
||||
@@ -1849,7 +1849,7 @@ void SwTextFrame::Format_( SwTextFormatter &rLine, SwTextFormatInfo &rInf,
|
||||
rRepaint.Top( rLine.Y() );
|
||||
if( 0 >= rRepaint.Width() )
|
||||
rRepaint.Width(1);
|
||||
WidowsAndOrphans aFrameBreak( this, rInf.IsTest() ? 1 : 0 );
|
||||
WidowsAndOrphans aFrameBreak(this, rInf.IsTest() ? std::optional<SwTwips>(0) : std::nullopt);
|
||||
|
||||
// rLine is now set to the first line which needs formatting.
|
||||
// The bFirst flag makes sure that Next() is not called.
|
||||
|
||||
@@ -59,8 +59,9 @@ bool IsNastyFollow( const SwTextFrame *pFrame )
|
||||
|
||||
}
|
||||
|
||||
SwTextFrameBreak::SwTextFrameBreak( SwTextFrame *pNewFrame, const SwTwips nRst )
|
||||
: m_nRstHeight(nRst), m_pFrame(pNewFrame)
|
||||
SwTextFrameBreak::SwTextFrameBreak(SwTextFrame* pNewFrame, const std::optional<SwTwips>& oRst)
|
||||
: m_oRstHeight(oRst)
|
||||
, m_pFrame(pNewFrame)
|
||||
{
|
||||
SwSwapIfSwapped swap(m_pFrame);
|
||||
SwRectFnSet aRectFnSet(*m_pFrame);
|
||||
@@ -84,13 +85,13 @@ SwTextFrameBreak::SwTextFrameBreak( SwTextFrame *pNewFrame, const SwTwips nRst )
|
||||
|
||||
m_bBreak = false;
|
||||
|
||||
if( !m_nRstHeight && !m_pFrame->IsFollow() && m_pFrame->IsInFootnote() && m_pFrame->HasPara() )
|
||||
if (!m_oRstHeight && !m_pFrame->IsFollow() && m_pFrame->IsInFootnote() && m_pFrame->HasPara())
|
||||
{
|
||||
m_nRstHeight = m_pFrame->GetFootnoteFrameHeight();
|
||||
m_nRstHeight += aRectFnSet.GetHeight(m_pFrame->getFramePrintArea()) -
|
||||
aRectFnSet.GetHeight(m_pFrame->getFrameArea());
|
||||
if( m_nRstHeight < 0 )
|
||||
m_nRstHeight = 0;
|
||||
m_oRstHeight = m_pFrame->GetFootnoteFrameHeight()
|
||||
+ aRectFnSet.GetHeight(m_pFrame->getFramePrintArea())
|
||||
- aRectFnSet.GetHeight(m_pFrame->getFrameArea());
|
||||
if (*m_oRstHeight <= 0)
|
||||
m_oRstHeight.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +145,8 @@ bool SwTextFrameBreak::IsInside(SwTextMargin const& rLine, SwResizeLimitReason&
|
||||
&& rLine.GetEnd() >= TextFrameIndex(m_pFrame->GetText().getLength()))
|
||||
nLineHeight += m_pFrame->CalcAddLowerSpaceAsLastInTableCell();
|
||||
|
||||
if( m_nRstHeight )
|
||||
bFit = m_nRstHeight >= nLineHeight;
|
||||
if (m_oRstHeight)
|
||||
bFit = *m_oRstHeight >= nLineHeight;
|
||||
else
|
||||
{
|
||||
// The Frame has a height to fit on the page.
|
||||
@@ -297,22 +298,25 @@ void SwTextFrameBreak::SetRstHeight( const SwTextMargin &rLine )
|
||||
// Consider bottom margin
|
||||
SwRectFnSet aRectFnSet(*m_pFrame);
|
||||
|
||||
m_nRstHeight = aRectFnSet.GetBottomMargin(*m_pFrame);
|
||||
m_oRstHeight = aRectFnSet.GetBottomMargin(*m_pFrame);
|
||||
|
||||
if ( aRectFnSet.IsVert() )
|
||||
{
|
||||
if ( m_pFrame->IsVertLR() )
|
||||
m_nRstHeight = aRectFnSet.YDiff( m_pFrame->SwitchHorizontalToVertical( rLine.Y() ) , m_nOrigin );
|
||||
m_oRstHeight
|
||||
= aRectFnSet.YDiff(m_pFrame->SwitchHorizontalToVertical(rLine.Y()), m_nOrigin);
|
||||
else
|
||||
m_nRstHeight += m_nOrigin - m_pFrame->SwitchHorizontalToVertical( rLine.Y() );
|
||||
*m_oRstHeight += m_nOrigin - m_pFrame->SwitchHorizontalToVertical(rLine.Y());
|
||||
}
|
||||
else
|
||||
m_nRstHeight += rLine.Y() - m_nOrigin;
|
||||
*m_oRstHeight += rLine.Y() - m_nOrigin;
|
||||
}
|
||||
|
||||
WidowsAndOrphans::WidowsAndOrphans( SwTextFrame *pNewFrame, const SwTwips nRst,
|
||||
bool bChkKeep )
|
||||
: SwTextFrameBreak( pNewFrame, nRst ), m_nWidLines( 0 ), m_nOrphLines( 0 )
|
||||
WidowsAndOrphans::WidowsAndOrphans(SwTextFrame* pNewFrame, const std::optional<SwTwips>& oRst,
|
||||
bool bChkKeep)
|
||||
: SwTextFrameBreak(pNewFrame, oRst)
|
||||
, m_nWidLines(0)
|
||||
, m_nOrphLines(0)
|
||||
{
|
||||
SwSwapIfSwapped swap(m_pFrame);
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <swtypes.hxx>
|
||||
#include "itrtxt.hxx"
|
||||
|
||||
@@ -26,14 +28,16 @@ class SwTextFrame;
|
||||
class SwTextFrameBreak
|
||||
{
|
||||
private:
|
||||
SwTwips m_nRstHeight;
|
||||
// The height the frame has to fit into. Zero and negative values are considered valid. If not
|
||||
// set, the whole upper is measured instead.
|
||||
std::optional<SwTwips> m_oRstHeight;
|
||||
SwTwips m_nOrigin;
|
||||
protected:
|
||||
SwTextFrame *m_pFrame;
|
||||
bool m_bBreak;
|
||||
bool m_bKeep;
|
||||
public:
|
||||
SwTextFrameBreak( SwTextFrame *pFrame, const SwTwips nRst = 0 );
|
||||
SwTextFrameBreak(SwTextFrame* pFrame, const std::optional<SwTwips>& oRst = std::nullopt);
|
||||
bool IsBreakNow( SwTextMargin &rLine );
|
||||
bool IsKeepAlways() const { return m_bKeep; }
|
||||
|
||||
@@ -56,8 +60,8 @@ private:
|
||||
sal_uInt16 m_nWidLines, m_nOrphLines;
|
||||
|
||||
public:
|
||||
WidowsAndOrphans( SwTextFrame *pFrame, const SwTwips nRst = 0,
|
||||
bool bCheckKeep = true );
|
||||
WidowsAndOrphans(SwTextFrame* pFrame, const std::optional<SwTwips>& oRst = std::nullopt,
|
||||
bool bCheckKeep = true);
|
||||
bool FindWidows( SwTextFrame *pFrame, SwTextMargin &rLine );
|
||||
sal_uInt16 GetOrphansLines() const
|
||||
{ return m_nOrphLines; }
|
||||
|
||||
Reference in New Issue
Block a user