office-gobmx/sw/source/core/text/widorp.hxx
Mike Kaganski d1c5ed30d1 tdf#162614: report the reason why a frame couldn't grow
... and use it in SwTextFrameBreak::IsBreakNow to decide if the content
needs to go to a follow or not.

The problem was, that in a specific case of the bugdoc, the follow text
line was taller than the fixed row height on that page; that resulted
in an attempt to break it again, creating an empty follow in the same
table cell; it was not moved to the next page, detecting the problem in
SwTextFrame::CalcFollow, and the formatting looped, until loop control
fired, calling SwLooping::Drastic, which validated all page's content,
including tables below, that had invalid zero client (prn) height.

It was very difficult to tell when the break is needed, and when it's
not, without the information why some frame eventually denied growing
its height by the requested amount. In the bugdoc case, I failed to
find at the SwTextFrameBreak::IsBreakNow level anything that could be
used as a reliable distinction; some heuristic conditions used there
broke layout in unit tests left and right. So eventually, I came with
this mechanism of reporting the "why I can't grow" reason back to the
caller, using the new out argument.

I believe that, beyond this use case, it might be useful in many other
cases, both to ease the decision, and to prevent needless trial-and-
error iterations, increasing stability and performance. The enum used
for the reason reporting includes 'FlowToFollow' and 'BalancedColumns',
that could be used in those other cases. However, for my needs here, I
only need the FixedSizeFrame reason, telling that it's not a case when
breaking to a next frame is possible, so preventing the break.

The choice of reported reasons in this patch is mostly best guess; it
may be wrong in some places. The crucial for the current fix is the
assignment inside the '!(GetType() & nTmpType) && HasFixSize()' check
of SwLayoutFrame::GrowFrame.

Change-Id: I9ce5dd4d2298b60e186fdf485efb85ab304308ee
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172362
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Jenkins
2024-08-25 23:40:26 +02:00

94 lines
3.2 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#pragma once
#include <swtypes.hxx>
#include "itrtxt.hxx"
class SwTextFrame;
class SwTextFrameBreak
{
private:
SwTwips m_nRstHeight;
SwTwips m_nOrigin;
protected:
SwTextFrame *m_pFrame;
bool m_bBreak;
bool m_bKeep;
public:
SwTextFrameBreak( SwTextFrame *pFrame, const SwTwips nRst = 0 );
bool IsBreakNow( SwTextMargin &rLine );
bool IsKeepAlways() const { return m_bKeep; }
void SetKeep( const bool bNew ) { m_bKeep = bNew; }
bool IsInside( SwTextMargin const &rLine ) const;
bool IsInside(SwTextMargin const& rLine, SwResizeLimitReason&) const;
// In order to be able to handle special cases with Footnote.
// SetRstHeight sets the rest height for SwTextFrameBreak. This is needed
// to call TruncLines() without IsBreakNow() returning another value.
// We assume that rLine is pointing to the last non-fitting line.
void SetRstHeight( const SwTextMargin &rLine );
};
class WidowsAndOrphans : public SwTextFrameBreak
{
private:
sal_uInt16 m_nWidLines, m_nOrphLines;
public:
WidowsAndOrphans( SwTextFrame *pFrame, const SwTwips nRst = 0,
bool bCheckKeep = true );
bool FindWidows( SwTextFrame *pFrame, SwTextMargin &rLine );
sal_uInt16 GetOrphansLines() const
{ return m_nOrphLines; }
void ClrOrphLines(){ m_nOrphLines = 0; }
bool FindBreak( SwTextFrame *pFrame, SwTextMargin &rLine, bool bHasToFit );
bool WouldFit( SwTextMargin &rLine, SwTwips &rMaxHeight, bool bTest, bool bMoveBwd );
// i#16128 - This method is named this way to avoid confusion with
// base class method <SwTextFrameBreak::IsBreakNow>, which isn't virtual.
bool IsBreakNowWidAndOrp( SwTextMargin &rLine )
{
bool isOnFirstLine = (rLine.GetLineNr() == 1 && !rLine.GetPrev());
if ( isOnFirstLine && rLine.GetCurr()->IsDummy()) {
return IsBreakNow( rLine );
}
if ( rLine.GetLineNr() > m_nOrphLines ) {
return IsBreakNow( rLine );
}
return false;
}
};
inline bool SwTextFrameBreak::IsInside(SwTextMargin const& rLine) const
{
return IsInside(rLine, o3tl::temporary(SwResizeLimitReason()));
}
namespace sw {
auto FindNonFlyPortion(SwLineLayout const& rLine) -> bool;
} // namespace sw
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */