From 708fc0c2d5c9cf7163b41519b71026d806c4f047 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 14 Jul 2021 00:47:42 +0200 Subject: [PATCH] Break the paragraph's big row according to margins Still many features missing: - handle insets that break rows (display math, newline, ...) - handle rows that are too long by replacing the single call to breakAt with a call to a reworked Row::shortenIfNeeded. - some easy things at the end of breakRow (bidi text, etc.). --- src/TextMetrics.cpp | 91 ++++++++++++++++++++++++++++++++++++++++----- src/TextMetrics.h | 2 + 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index cc380cc193..fb6574d72e 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -990,6 +990,79 @@ Row TextMetrics::tokenizeParagraph(pit_type const pit) const } +namespace { + +Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) +{ + Row nrow; + nrow.pit(pit); + nrow.pos(pos); + nrow.left_margin = tm.leftMargin(pit, pos); + nrow.right_margin = tm.rightMargin(pit); + if (is_rtl) + swap(nrow.left_margin, nrow.right_margin); + // Remember that the row width takes into account the left_margin + // but not the right_margin. + nrow.dim().wid = nrow.left_margin; + return nrow; +} + +} + + +RowList TextMetrics::breakParagraph(Row const & row) const +{ + RowList rows; + bool const is_rtl = text_->isRTL(row.pit()); + + bool need_new_row = true; + pos_type pos = 0; + int width = 0; + Row::const_iterator cit = row.begin(); + Row::const_iterator const end = row.end(); + // This is a vector, but we use it like a pile putting and taking + // stuff at the back. + Row::Elements pile; + while (true) { + if (need_new_row) { + if (!rows.empty()) + rows.back().endpos(pos); + rows.push_back(newRow(*this, row.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 + // empty row at the end. + if (cit == end && pile.empty()) + break; + + // Next element to consider is either the top of the temporary + // pile, or the place when we were in main row + Row::Element elt = pile.empty() ? *cit : pile.back(); + //LYXERR0("elt=" << elt); + Row::Element next_elt = elt.splitAt(width - rows.back().width(), + !elt.font.language()->wordWrap()); + //LYXERR0("next_elt=" << next_elt); + // a new element in the row + rows.back().push_back(elt); + pos = elt.endpos; + // Go to next element + if (pile.empty()) + ++cit; + else + pile.pop_back(); + // Add a new next element on the pile + if (next_elt.isValid()) { + pile.push_back(next_elt); + need_new_row = true; + } + } + + return rows; +} + /** This is the function where the hard work is done. The code here is * very sensitive to small changes :) Note that part of the * intelligence is also in Row::shortenIfNeeded. @@ -1003,20 +1076,20 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const theSession().bookmarks().bookmarksInPar(buf.fileName(), par.id());// pos_type const end = par.size();// - pos_type const pos = row.pos(); + pos_type const pos = row.pos();// pos_type const body_pos = par.beginOfBody();// - bool const is_rtl = text_->isRTL(row.pit()); - bool need_new_row = false; + bool const is_rtl = text_->isRTL(row.pit());// + bool need_new_row = false;// - row.left_margin = leftMargin(row.pit(), pos); - row.right_margin = right_margin; - if (is_rtl) - swap(row.left_margin, row.right_margin); + row.left_margin = leftMargin(row.pit(), pos);// + row.right_margin = right_margin;// + if (is_rtl)// + swap(row.left_margin, row.right_margin);// // Remember that the row width takes into account the left_margin // but not the right_margin. - row.dim().wid = row.left_margin; + row.dim().wid = row.left_margin;// // the width available for the row. - int const width = max_width_ - row.right_margin; + int const width = max_width_ - row.right_margin;// // check for possible inline completion DocIterator const & ic_it = bv_->inlineCompletionPos();// diff --git a/src/TextMetrics.h b/src/TextMetrics.h index 1666cd014b..3ff11617da 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -153,6 +153,8 @@ private: Row tokenizeParagraph(pit_type pit) const; + RowList breakParagraph(Row const & row) const; + /// sets row.end to the pos value *after* which a row should break. /// for example, the pos after which isNewLine(pos) == true /// \return true when another row is required (after a newline) -- 2.39.5