Fix ticket #9224: text overflows through adjacent insets

The logic of Row::shortenIfNeeded is completely changed to look at the row from the start and not the end. This leads to clearer code.
This commit is contained in:
Jean-Marc Lasgouttes 2014-10-15 17:34:56 +02:00
parent 7bb472d685
commit ac018bd8db
2 changed files with 43 additions and 34 deletions

View File

@ -362,37 +362,50 @@ void Row::shortenIfNeeded(pos_type const keep, int const w)
if (empty() || width() <= w)
return;
/** First, we try to remove elements one by one from the end
* until a separator is found. cit points to the first element
* we want to remove from the row.
*/
Elements::iterator const beg = elements_.begin();
Elements::iterator const end = elements_.end();
Elements::iterator cit = end;
Elements::iterator first_below = end;
int new_end = end_;
int new_wid = dim_.wid;
// if the row ends with a separator, skip it.
if (cit != beg && boost::prior(cit)->type == SEPARATOR && new_end > keep) {
--cit;
new_end = cit->pos;
new_wid -= cit->dim.wid;
Elements::iterator last_sep = elements_.end();
double last_width = 0;
double wid = x;
Elements::iterator cit = beg;
for ( ; cit != end ; ++cit) {
if (cit->type == SEPARATOR && cit->pos >= keep) {
last_sep = cit;
last_width = wid;
}
if (wid + cit->width() > w)
break;
wid += cit->width();
}
// Search for a separator where the row can be broken.
while (cit != beg && boost::prior(cit)->type != SEPARATOR && new_end > keep) {
if (last_sep != end) {
// We have found a suitable separator. This is the
// common case.
end_ = last_sep->endpos;
dim_.wid = last_width;
elements_.erase(last_sep, end);
return;
}
if (cit == end) {
// This should not happen since the row is too long.
LYXERR0("Something is wrong cannot shorten row: " << *this);
return;
}
if (cit != beg && cit->type == VIRTUAL) {
// It is not possible to separate a virtual element from the
// previous one.
--cit;
new_end = cit->pos;
new_wid -= cit->dim.wid;
if (new_wid < w && first_below == end)
first_below = cit;
wid -= cit->width();
}
if (cit != beg) {
// We have found a suitable separator. This is the
// common case.
end_ = new_end;
dim_.wid = new_wid;
// There is no separator, but several elements (probably
// insets) have been added. We can cut at this place.
end_ = cit->pos;
dim_.wid = wid;
elements_.erase(cit, end);
return;
}
@ -402,17 +415,11 @@ void Row::shortenIfNeeded(pos_type const keep, int const w)
* something: when we have one big string, maybe with some
* other things after it.
*/
double max_w = w - x;
if (first_below->breakAt(max_w)) {
end_ = first_below->endpos;
dim_.wid = int(x + first_below->width());
if (cit->breakAt(w - x)) {
end_ = cit->endpos;
dim_.wid = int(x + cit->width());
// If there are other elements, they should be removed.
elements_.erase(boost::next(first_below), end);
} else if (first_below->pos > pos_) {
end_ = first_below->pos;
dim_.wid = new_wid;
// Remove all elements from first_below.
elements_.erase(first_below, end);
elements_.erase(boost::next(cit), end);
}
}

View File

@ -802,7 +802,9 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
int const width = max_width_ - right_margin;
pos_type const body_pos = par.beginOfBody();
row.clear();
row.dimension().wid = leftMargin(max_width_, pit, pos);
// This make get changed in computeRowMetrics depending on RTL
row.x = leftMargin(max_width_, pit, pos);
row.dimension().wid = row.x;
row.right_margin = right_margin;
if (pos >= end || row.width() > width) {