From 49115315ea751332d3f8f8a0770cf8427a2c9640 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 17 Jul 2021 02:31:49 +0200 Subject: [PATCH] Introduce helper template to simplify breakParagraph code This is a semi-generic iterator for iterating over a container and pretend that we add elements to it along the way. --- src/Row.h | 2 ++ src/TextMetrics.cpp | 79 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/Row.h b/src/Row.h index 4fdcee408f..72d7a860b7 100644 --- a/src/Row.h +++ b/src/Row.h @@ -150,6 +150,8 @@ public: friend std::ostream & operator<<(std::ostream & os, Element const & row); }; + /// + typedef Element value_type; /// Row() {} diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 00d65dab35..b5ba9746b9 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -995,6 +995,62 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl) return nrow; } + +/** Helper template flexible_const_iterator + * A way to iterate over a const container, but insert fake elements in it. + * In the case of a row, we will have to break some elements, which + * create new ones. This class allows to abstract this. + * Only the required parts are implemented for now. + */ +template +class flexible_const_iterator { + typedef typename T::value_type value_type; +public: + + // + flexible_const_iterator operator++() { + if (pile_.empty()) + ++cit_; + else + pile_.pop_back(); + return *this; + } + + value_type operator*() const { return pile_.empty() ? *cit_ : pile_.back(); } + + void put(value_type const & e) { pile_.push_back(e); } + +// This should be private, but declaring the friend functions is too much work +//private: + typename T::const_iterator cit_; + // A vector that is used as like a pile to store the elements to + // consider before incrementing the underlying iterator. + vector pile_; +}; + + +template +flexible_const_iterator flexible_begin(T const & t) +{ + return { t.begin(), vector() }; +} + + +template +flexible_const_iterator flexible_end(T const & t) +{ + return { t.end(), vector() }; +} + + +// Equality is only possible if respective piles are empty +template +bool operator==(flexible_const_iterator const & t1, + flexible_const_iterator const & t2) +{ + return t1.cit_ == t2.cit_ && t1.pile_.empty() && t2.pile_.empty(); +} + } @@ -1006,11 +1062,8 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const bool need_new_row = true; pos_type pos = 0; int width = 0; - Row::const_iterator cit = bigrow.begin(); - Row::const_iterator const end = bigrow.end(); - // This is a vector, but we use it like a pile putting and taking - // stuff at the back. - Row::Elements pile; + flexible_const_iterator fcit = flexible_begin(bigrow); + flexible_const_iterator const end = flexible_end(bigrow); while (true) { if (need_new_row) { if (!rows.empty()) { @@ -1029,27 +1082,25 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const // The stopping condition is here because we may need a new // empty row at the end. - if (cit == end && pile.empty()) + if (fcit == end) 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 elt = *fcit; 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(); + ++fcit; + // Add a new next element on the pile if (next_elt.isValid()) { - pile.push_back(next_elt); + // do as if we inserted this element in the original row + fcit.put(next_elt); need_new_row = true; } } -- 2.39.2