mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 10:58:52 +00:00
Avoid row breaking at inconvenient places.
When it turns out that breaking a STRING row element was not sufficient in Row::shortenIfNeeded, we still remember the shortest width that one can obtain. Later, when we try to split a previous element of the row, we have a better idea of how much of the row remains after it. To this end, change the signature of Element::splitAt to use an enum: FIT (was: force=false), FORCE (was: force= true) and BEST_EFFORT (split at max_width, but do not return an error if the string is too large). Fixes bug #12660.
This commit is contained in:
parent
1ca43e1938
commit
71d9f6e90d
25
src/Row.cpp
25
src/Row.cpp
@ -123,7 +123,7 @@ pos_type Row::Element::x2pos(int &x) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Row::Element::splitAt(int const width, int next_width, bool force,
|
bool Row::Element::splitAt(int const width, int next_width, SplitType split_type,
|
||||||
Row::Elements & tail)
|
Row::Elements & tail)
|
||||||
{
|
{
|
||||||
// Not a string or already OK.
|
// Not a string or already OK.
|
||||||
@ -142,13 +142,13 @@ bool Row::Element::splitAt(int const width, int next_width, bool force,
|
|||||||
|
|
||||||
bool const wrap_any = !font.language()->wordWrap();
|
bool const wrap_any = !font.language()->wordWrap();
|
||||||
FontMetrics::Breaks breaks = fm.breakString(str, width, next_width,
|
FontMetrics::Breaks breaks = fm.breakString(str, width, next_width,
|
||||||
isRTL(), wrap_any | force);
|
isRTL(), wrap_any || split_type == FORCE);
|
||||||
|
|
||||||
/** if breaking did not really work, give up
|
/** if breaking did not really work, give up
|
||||||
* case 1: we do not force break and the first element is longer than the limit;
|
* case 1: split type is FIT and the first element is longer than the limit;
|
||||||
* case 2: the first break occurs at the front of the string
|
* case 2: the first break occurs at the front of the string
|
||||||
*/
|
*/
|
||||||
if ((!force && breaks.front().nspc_wid > width)
|
if ((split_type == FIT && breaks.front().nspc_wid > width)
|
||||||
|| (breaks.size() > 1 && breaks.front().len == 0)) {
|
|| (breaks.size() > 1 && breaks.front().len == 0)) {
|
||||||
if (dim.wid == 0)
|
if (dim.wid == 0)
|
||||||
dim.wid = fm.width(str);
|
dim.wid = fm.width(str);
|
||||||
@ -548,6 +548,8 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
|||||||
Elements::iterator const beg = elements_.begin();
|
Elements::iterator const beg = elements_.begin();
|
||||||
Elements::iterator const end = elements_.end();
|
Elements::iterator const end = elements_.end();
|
||||||
int wid = left_margin;
|
int wid = left_margin;
|
||||||
|
// the smallest row width we know we can achieve by breaking a string.
|
||||||
|
int min_row_wid = dim_.wid;
|
||||||
|
|
||||||
// Search for the first element that goes beyond right margin
|
// Search for the first element that goes beyond right margin
|
||||||
Elements::iterator cit = beg;
|
Elements::iterator cit = beg;
|
||||||
@ -600,14 +602,23 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
|||||||
* - shorter than the natural width of the element, in order to enforce
|
* - shorter than the natural width of the element, in order to enforce
|
||||||
* break-up.
|
* break-up.
|
||||||
*/
|
*/
|
||||||
if (brk.splitAt(min(max_width - wid_brk, brk.dim.wid - 2), next_width, false, tail)) {
|
int const split_width = min(max_width - wid_brk, brk.dim.wid - 2);
|
||||||
|
if (brk.splitAt(split_width, next_width, BEST_EFFORT, tail)) {
|
||||||
|
// if we did not manage to fit a part of the element into
|
||||||
|
// the split_width limit, at least remember that we can
|
||||||
|
// shorten the row if needed.
|
||||||
|
if (brk.dim.wid > split_width) {
|
||||||
|
min_row_wid = wid_brk + brk.dim.wid;
|
||||||
|
tail.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* if this element originally did not cause a row overflow
|
/* if this element originally did not cause a row overflow
|
||||||
* in itself, and the remainder of the row would still be
|
* in itself, and the remainder of the row would still be
|
||||||
* too large after breaking, then we will have issues in
|
* too large after breaking, then we will have issues in
|
||||||
* next row. Thus breaking does not help.
|
* next row. Thus breaking does not help.
|
||||||
*/
|
*/
|
||||||
if (wid_brk + cit_brk->dim.wid < max_width
|
if (wid_brk + cit_brk->dim.wid < max_width
|
||||||
&& dim_.wid - (wid_brk + brk.dim.wid) >= next_width) {
|
&& min_row_wid - (wid_brk + brk.dim.wid) >= next_width) {
|
||||||
tail.clear();
|
tail.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -641,7 +652,7 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
|||||||
* shorten the row. Let's try to break it again, but force
|
* shorten the row. Let's try to break it again, but force
|
||||||
* splitting this time.
|
* splitting this time.
|
||||||
*/
|
*/
|
||||||
if (cit->splitAt(max_width - wid, next_width, true, tail)) {
|
if (cit->splitAt(max_width - wid, next_width, FORCE, tail)) {
|
||||||
end_ = cit->endpos;
|
end_ = cit->endpos;
|
||||||
dim_.wid = wid + cit->dim.wid;
|
dim_.wid = wid + cit->dim.wid;
|
||||||
// If there are other elements, they should be removed.
|
// If there are other elements, they should be removed.
|
||||||
|
14
src/Row.h
14
src/Row.h
@ -55,6 +55,14 @@ public:
|
|||||||
// by the initial width
|
// by the initial width
|
||||||
MARGINSPACE
|
MARGINSPACE
|
||||||
};
|
};
|
||||||
|
enum SplitType {
|
||||||
|
// split string to fit requested width, fail if string remains too long
|
||||||
|
FIT,
|
||||||
|
// if the requested width is too small, accept the first possible break
|
||||||
|
BEST_EFFORT,
|
||||||
|
// cut string at any place, even for languages that wrap at word delimiters
|
||||||
|
FORCE
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One element of a Row. It has a set of attributes that can be used
|
* One element of a Row. It has a set of attributes that can be used
|
||||||
@ -94,14 +102,12 @@ public:
|
|||||||
* not needed or not possible.
|
* not needed or not possible.
|
||||||
* \param width: maximum width of the row.
|
* \param width: maximum width of the row.
|
||||||
* \param next_width: available width on next rows.
|
* \param next_width: available width on next rows.
|
||||||
* \param force: if true, cut string at any place, even for
|
* \param split_type: indicate how the string should be split.
|
||||||
* languages that wrap at word delimiters; if false, do not
|
|
||||||
* break at all if first element would larger than \c width.
|
|
||||||
* \param tail: a vector of elements where the remainder of
|
* \param tail: a vector of elements where the remainder of
|
||||||
* the text will be appended (empty if nothing happened).
|
* the text will be appended (empty if nothing happened).
|
||||||
*/
|
*/
|
||||||
// FIXME: ideally last parameter should be Elements&, but it is not possible.
|
// FIXME: ideally last parameter should be Elements&, but it is not possible.
|
||||||
bool splitAt(int width, int next_width, bool force, std::vector<Element> & tail);
|
bool splitAt(int width, int next_width, SplitType split_type, std::vector<Element> & tail);
|
||||||
// remove trailing spaces (useful for end of row)
|
// remove trailing spaces (useful for end of row)
|
||||||
void rtrim();
|
void rtrim();
|
||||||
|
|
||||||
|
@ -1150,7 +1150,7 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
|
|||||||
// pile, or the place when we were in main row
|
// pile, or the place when we were in main row
|
||||||
Row::Element elt = *fcit;
|
Row::Element elt = *fcit;
|
||||||
Row::Elements tail;
|
Row::Elements tail;
|
||||||
elt.splitAt(width - rows.back().width(), next_width, false, tail);
|
elt.splitAt(width - rows.back().width(), next_width, Row::FIT, tail);
|
||||||
Row & rb = rows.back();
|
Row & rb = rows.back();
|
||||||
if (elt.type == Row::MARGINSPACE)
|
if (elt.type == Row::MARGINSPACE)
|
||||||
elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width());
|
elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width());
|
||||||
|
Loading…
Reference in New Issue
Block a user