From ac018bd8db4e81c92320fe026cceff4e9f2181d2 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 15 Oct 2014 17:34:56 +0200 Subject: [PATCH] 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. --- src/Row.cpp | 73 +++++++++++++++++++++++++-------------------- src/TextMetrics.cpp | 4 ++- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/Row.cpp b/src/Row.cpp index aeede91d85..d1f589c9ff 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -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); } } diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index c99517c517..637ce1f453 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -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) { -- 2.39.5