From 1bc07bd7d2fd60b5630a7536879604044d55053c Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 18 Jul 2021 01:09:33 +0200 Subject: [PATCH] Implement handling of row_flags for row breaking To this end, add the helper function needsRowBreak which computes the effect of two consecutive row flags. This function implements the priorities described in RowFlags.h. This function is called with the relevant flags, or NoBreak* when at boundaries and updates need_new_row. Some common code is factored in a new cleanupRow() helper. --- src/TextMetrics.cpp | 91 +++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index fa855e448e..1a6927ab98 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -980,22 +980,6 @@ 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; -} - - /** 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 @@ -1018,6 +1002,8 @@ public: value_type operator*() const { return pile_.empty() ? *cit_ : pile_.back(); } + value_type const * 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 @@ -1051,6 +1037,44 @@ 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; + 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; +} + + +void cleanupRow(Row & row, pos_type pos, pos_type real_endpos, bool is_rtl) +{ + row.endpos(pos); + row.right_boundary(!row.empty() && pos < real_endpos + && row.back().endpos == pos); + // make sure that the RTL elements are in reverse ordering + row.reverseRTL(is_rtl); +} + +// Implement the priorities described in RowFlags.h. +bool needsRowBreak(int f1, int f2) +{ + if (f1 & AlwaysBreakAfter /*|| f2 & AlwaysBreakBefore*/) + return true; + if (f1 & NoBreakAfter || f2 & NoBreakBefore) + return false; + if (f1 & BreakAfter || f2 & BreakBefore) + return true; + return false; +} + + } @@ -1058,6 +1082,7 @@ 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; bool need_new_row = true; pos_type pos = 0; @@ -1065,15 +1090,21 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const 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(); + // 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. + int const f1 = row_empty ? NoBreakAfter : rows.back().back().row_flags; + // The row flags of next element, if there is one. + // Otherwise we use NoBreakBefore (see above), unless the + // 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()) { - Row & rb = rows.back(); - rb.endpos(pos); - rb.right_boundary(!rb.empty() && rb.endpos() < bigrow.endpos() - && rb.back().endpos == rb.endpos()); - // make sure that the RTL elements are in reverse ordering - rb.reverseRTL(is_rtl); - } + if (!rows.empty()) + cleanupRow(rows.back(), pos, bigrow.endpos(), is_rtl); rows.push_back(newRow(*this, bigrow.pit(), pos, is_rtl)); // the width available for the row. width = max_width_ - rows.back().right_margin; @@ -1107,13 +1138,9 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const } if (!rows.empty()) { - Row & rb = rows.back(); + cleanupRow(rows.back(), pos, bigrow.endpos(), is_rtl); // Last row in paragraph is flushed - rb.flushed(true); - rb.endpos(bigrow.endpos()); - rb.right_boundary(false); - // make sure that the RTL elements are in reverse ordering - rb.reverseRTL(is_rtl); + rows.back().flushed(true); } return rows; @@ -1227,9 +1254,8 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const } f.fontInfo().setColor(Color_nonunique_inlinecompletion); row.addVirtual(i + 1, comp.substr(uniqueTo), f, Change()); - }//---------------------------------------------------------------^^^ + } - // FIXME: Handle when breaking the rows // Handle some situations that abruptly terminate the row // - Before an inset with BreakBefore // - After an inset with BreakAfter @@ -1254,7 +1280,6 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const ++i; ++fi; } - //--------------------------------------------------------------------vvv row.finalizeLast(); row.endpos(i); -- 2.39.5