}
-int TextMetrics::labelEnd(pit_type const pit) const
-{
- // labelEnd is only needed if the layout fills a flushleft label.
- if (text_->getPar(pit).layout().margintype != MARGIN_MANUAL)
- return 0;
- // return the beginning of the body
- return leftMargin(pit);
-}
-
namespace {
/**
Dimension dim = bv_->coordCache().insets().dim(ins);
row.add(i, ins, dim, *fi, par.lookupChange(i));
} else if (c == ' ' && i + 1 == body_pos) {
- // There is a space at i, but it should not be
- // added as a separator, because it is just
- // before body_pos. Instead, insert some spacing to
- // align text
+ // This space is an \item separator. Represent it with a
+ // special space element, which dimension will be computed
+ // in breakRow.
FontMetrics const & fm = theFontMetrics(text_->labelFont(par));
- // this is needed to make sure that the row width is correct
- row.finalizeLast();
- int const add = max(fm.width(par.layout().labelsep),
- labelEnd(pit) - row.width());
- row.addSpace(i, add, *fi, par.lookupChange(i));
+ int const wid = fm.width(par.layout().labelsep);
+ row.addMarginSpace(i, wid, *fi, par.lookupChange(i));
} else if (c == '\t')
row.addSpace(i, theFontMetrics(*fi).width(from_ascii(" ")),
*fi, par.lookupChange(i));
* U+2029 PARAGRAPH SEPARATOR
* These are special unicode characters that break
- * lines/pragraphs. Not handling them lead to trouble wrt
+ * lines/pragraphs. Not handling them leads to trouble wrt
* Qt QTextLayout formatting. We add a visible character
* on screen so that the user can see that something is
* happening.
// ⤶ U+2936 ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
// ¶ U+00B6 PILCROW SIGN
char_type const screen_char = (c == 0x2028) ? 0x2936 : 0x00B6;
- row.add(i, screen_char, *fi, par.lookupChange(i), i >= body_pos);
+ row.add(i, screen_char, *fi, par.lookupChange(i));
} else
// row elements before body are unbreakable
- row.add(i, c, *fi, par.lookupChange(i), i >= body_pos);
+ row.add(i, c, *fi, par.lookupChange(i));
// add inline completion width
// draw logically behind the previous character
return t1.cit_ == t2.cit_ && t1.pile_.empty() && t2.pile_.empty();
}
+
Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl)
{
Row nrow;
nrow.pos(pos);
nrow.left_margin = tm.leftMargin(pit, pos);
nrow.right_margin = tm.rightMargin(pit);
+ nrow.setRTL(is_rtl);
if (is_rtl)
swap(nrow.left_margin, nrow.right_margin);
// Remember that the row width takes into account the left_margin
}
-void cleanupRow(Row & row, pos_type pos, pos_type real_endpos, bool is_rtl)
+void cleanupRow(Row & row, bool at_end)
{
- row.endpos(pos);
- row.right_boundary(!row.empty() && pos < real_endpos
- && row.back().endpos == pos);
+ if (row.empty()) {
+ row.endpos(row.pos());
+ return;
+ }
+
+ row.endpos(row.back().endpos);
+ // remove trailing spaces on row break
+ if (!at_end && !row.flushed())
+ row.back().rtrim();
+ // boundary exists when there was no space at the end of row
+ row.right_boundary(!at_end && row.back().endpos == row.endpos());
// make sure that the RTL elements are in reverse ordering
- row.reverseRTL(is_rtl);
+ row.reverseRTL();
}
+
// Implement the priorities described in RowFlags.h.
bool needsRowBreak(int f1, int f2)
{
RowList rows;
bool const is_rtl = text_->isRTL(bigrow.pit());
bool const end_label = text_->getEndLabel(bigrow.pit()) != END_LABEL_NO_LABEL;
+ int const next_width = max_width_ - leftMargin(bigrow.pit(), bigrow.endpos())
+ - rightMargin(bigrow.pit());
- bool need_new_row = true;
- pos_type pos = 0;
int width = 0;
flexible_const_iterator<Row> fcit = flexible_begin(bigrow);
flexible_const_iterator<Row> const end = flexible_end(bigrow);
while (true) {
- bool const has_row = !rows.empty();
- bool const row_empty = !has_row || rows.back().empty();
+ bool const row_empty = rows.empty() || rows.back().empty();
// The row flags of previous element, if there is one.
// Otherwise we use NoBreakAfter to avoid an empty row before
// e.g. a displayed equation.
// paragraph has an end label (for which an empty row is OK).
int const f2 = (fcit == end) ? (end_label ? Inline : NoBreakBefore)
: fcit->row_flags;
- need_new_row |= needsRowBreak(f1, f2);
- if (need_new_row) {
- if (!rows.empty())
- cleanupRow(rows.back(), pos, bigrow.endpos(), is_rtl);
+ if (rows.empty() || needsRowBreak(f1, f2)) {
+ if (!rows.empty()) {
+ // Flush row as requested by row flags
+ rows.back().flushed((f1 & Flush) || (f2 & FlushBefore));
+ cleanupRow(rows.back(), false);
+ }
+ pos_type pos = rows.empty() ? 0 : rows.back().endpos();
rows.push_back(newRow(*this, bigrow.pit(), pos, is_rtl));
// the width available for the row.
width = max_width_ - rows.back().right_margin;
- need_new_row = false;
}
// The stopping condition is here because we may need a new
// Next element to consider is either the top of the temporary
// pile, or the place when we were in main row
Row::Element elt = *fcit;
- Row::Element next_elt = elt.splitAt(width - rows.back().width(),
- !elt.font.language()->wordWrap());
- if (elt.dim.wid > width - rows.back().width()) {
- Row & rb = rows.back();
- rb.push_back(*fcit);
- // if the row is too large, try to cut at last separator. In case
- // of success, reset indication that the row was broken abruptly.
- int const next_width = max_width_ - leftMargin(rb.pit(), rb.endpos())
- - rightMargin(rb.pit());
-
- Row::Elements next_elts = rb.shortenIfNeeded(width, next_width);
-
- // Go to next element
- ++fcit;
-
- // Handle later the elements returned by shortenIfNeeded.
- if (!next_elts.empty()) {
- rb.flushed(false);
- fcit.put(next_elts);
- need_new_row = true;
- }
- } else {
- // a new element in the row
- rows.back().push_back(elt);
- rows.back().finalizeLast();
- pos = elt.endpos;
-
- // Go to next element
- ++fcit;
-
- // Add a new next element on the pile
- if (next_elt.isValid()) {
- // do as if we inserted this element in the original row
- if (!next_elt.str.empty())
- fcit.put(next_elt);
- need_new_row = true;
- }
+ Row::Elements tail;
+ elt.splitAt(width - rows.back().width(), next_width, false, tail);
+ Row & rb = rows.back();
+ if (elt.type == Row::MARGINSPACE)
+ elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width());
+ rb.push_back(elt);
+ rb.finalizeLast();
+ if (rb.width() > width) {
+ LATTEST(tail.empty());
+ // if the row is too large, try to cut at last separator.
+ tail = rb.shortenIfNeeded(width, next_width);
}
+
+ // Go to next element
+ ++fcit;
+
+ // Handle later the elements returned by splitAt or shortenIfNeeded.
+ fcit.put(tail);
}
if (!rows.empty()) {
- cleanupRow(rows.back(), pos, bigrow.endpos(), is_rtl);
// Last row in paragraph is flushed
rows.back().flushed(true);
+ cleanupRow(rows.back(), true);
}
return rows;
&& prevpar.getLabelWidthString() == par.getLabelWidthString()) {
layoutasc = layout.itemsep * dh;
} else if (pit != 0 && layout.topsep > 0)
- layoutasc = layout.topsep * dh;
+ // combine the separation between different layouts (with same depth)
+ layoutasc = max(0.0,
+ prevpar.getDepth() != par.getDepth() ? layout.topsep
+ : layout.topsep - prevpar.layout().bottomsep) * dh;
asc += int(layoutasc * 2 / (2 + pars[pit].getDepth()));
// already cleared because of a full repaint.
if (!pi.full_repaint && row.changed()) {
LYXERR(Debug::PAINTING, "Clear rect@("
- << max(row_x, 0) << ", " << y - row.ascent() << ")="
+ << x << ", " << y - row.ascent() << ")="
<< width() << " x " << row.height());
- pi.pain.fillRectangle(row_x, y - row.ascent(),
+ pi.pain.fillRectangle(x, y - row.ascent(),
width(), row.height(), pi.background_color);
}