[LyX/master] Break the paragraph's big row according to margins

Jean-Marc Lasgouttes lasgouttes at lyx.org
Tue Dec 7 15:47:01 UTC 2021


commit ef88e31a1fb00d16d6d56e63b671d128ef43ad12
Author: Jean-Marc Lasgouttes <lasgouttes at lyx.org>
Date:   Wed Jul 14 00:47:42 2021 +0200

    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 cc380cc..fb6574d 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 1666cd0..3ff1161 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)


More information about the lyx-cvs mailing list