X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=00fb217c0ad5628d8c628376288affe680c773e0;hb=6f7b39f84299660586b0485713d9672279ebe226;hp=a7dd300d2e11711393b235796ef16b3a3414dc1d;hpb=ef6dfe18c2149c6b96a806badde9548d7fd9f912;p=features.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index a7dd300d2e..00fb217c0a 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -786,15 +786,6 @@ int TextMetrics::labelFill(Row const & row) const } -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 { /** @@ -901,16 +892,12 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const 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)); @@ -920,7 +907,7 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const * 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. @@ -929,10 +916,10 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const // ⤶ 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 @@ -1042,6 +1029,7 @@ bool operator==(flexible_const_iterator const & t1, 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; @@ -1049,6 +1037,7 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) 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 @@ -1058,19 +1047,24 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) } -void cleanupRow(Row & row, pos_type pos, pos_type real_endpos, bool is_rtl) +void cleanupRow(Row & row, bool at_end) { - row.endpos(pos); + if (row.empty()) { + row.endpos(row.pos()); + return; + } + + row.endpos(row.back().endpos); // remove trailing spaces on row break - if (pos < real_endpos && !row.empty()) + if (!at_end && !row.flushed()) row.back().rtrim(); // boundary exists when there was no space at the end of row - row.right_boundary(!row.empty() && pos < real_endpos - && row.back().endpos == pos); + row.end_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) { @@ -1092,15 +1086,14 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const 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 fcit = flexible_begin(bigrow); flexible_const_iterator 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. @@ -1110,14 +1103,16 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const // 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 @@ -1128,50 +1123,30 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const // 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; @@ -1227,7 +1202,10 @@ int TextMetrics::parTopSpacing(pit_type const pit) const && 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())); @@ -1390,7 +1368,7 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x, || inset->lyxCode() == SEPARATOR_CODE)) pos = row.back().pos; else - boundary = row.right_boundary(); + boundary = row.end_boundary(); } x += xo - offset; @@ -2064,9 +2042,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // 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); }