From 65310f32dcc980aeca0b13253b1278a6f3ce722e Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 6 Nov 2023 11:28:27 +0400 Subject: [PATCH] Count correctly elided text dimensions. --- ui/text/text.cpp | 116 ++++++++++++++++---------------------- ui/text/text.h | 10 ++-- ui/text/text_renderer.cpp | 34 ++--------- ui/text/text_renderer.h | 2 +- 4 files changed, 61 insertions(+), 101 deletions(-) diff --git a/ui/text/text.cpp b/ui/text/text.cpp index 6e56f14..f288572 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -142,47 +142,36 @@ not_null DefaultSpoilerCache() { GeometryDescriptor SimpleGeometry( int availableWidth, - int fontHeight, - int elisionHeight, + int elisionLines, int elisionRemoveFromEnd, - bool elisionOneLine, bool elisionBreakEverywhere) { constexpr auto wrap = []( - Fn layout, + Fn layout, bool breakEverywhere = false) { return GeometryDescriptor{ std::move(layout), breakEverywhere }; }; // Try to minimize captured values (to minimize Fn allocations). - if (!elisionOneLine && !elisionHeight) { - return wrap([=](LineGeometry line) { - line.width = availableWidth; - return line; + if (!elisionLines) { + return wrap([=](int line) { + return LineGeometry{ .width = availableWidth }; }); - } else if (elisionOneLine) { - return wrap([=](LineGeometry line) { - line.elided = true; - line.width = availableWidth - elisionRemoveFromEnd; - return line; - }, elisionBreakEverywhere); } else if (!elisionRemoveFromEnd) { - return wrap([=](LineGeometry line) { - if (line.top + fontHeight * 2 > elisionHeight) { - line.elided = true; - } - line.width = availableWidth; - return line; - }); + return wrap([=](int line) { + return LineGeometry{ + .width = availableWidth, + .elided = (line + 1 >= elisionLines), + }; + }, elisionBreakEverywhere); } else { - return wrap([=](LineGeometry line) { - if (line.top + fontHeight * 2 > elisionHeight) { - line.elided = true; - line.width = availableWidth - elisionRemoveFromEnd; - } else { - line.width = availableWidth; - } - return line; - }); + return wrap([=](int line) { + const auto elided = (line + 1 >= elisionLines); + const auto removeFromEnd = (elided ? elisionRemoveFromEnd : 0); + return LineGeometry{ + .width = availableWidth - removeFromEnd, + .elided = elided, + }; + }, elisionBreakEverywhere); } }; @@ -913,7 +902,7 @@ void String::enumerateLines( return; } const auto width = std::max(w, _minResizeWidth); - auto g = SimpleGeometry(width, _st->font->height, 0, 0, false, false); + auto g = SimpleGeometry(width, 0, 0, false); g.breakEverywhere = breakEverywhere; enumerateLines(g, std::forward(callback)); } @@ -925,6 +914,13 @@ void String::enumerateLines( if (isEmpty()) { return; } + + const auto withElided = [&](bool elided) { + if (geometry.outElided) { + *geometry.outElided = elided; + } + }; + auto qindex = 0; auto quote = (QuoteDetails*)nullptr; auto qpadding = QMargins(); @@ -932,16 +928,14 @@ void String::enumerateLines( auto top = 0; auto lineLeft = 0; auto lineWidth = 0; + auto lineElided = false; auto widthLeft = QFixed(0); - auto paragraphWidthRemaining = QFixed(); + auto lineIndex = 0; const auto initNextLine = [&] { - const auto line = geometry.layout({ - .left = 0, - .top = top, - .width = paragraphWidthRemaining.ceil().toInt(), - }); + const auto line = geometry.layout(lineIndex++); lineLeft = line.left; lineWidth = line.width; + lineElided = line.elided; if (quote && quote->maxWidth < lineWidth) { const auto delta = lineWidth - quote->maxWidth; lineWidth = quote->maxWidth; @@ -951,7 +945,6 @@ void String::enumerateLines( const auto initNextParagraph = [&]( TextBlocks::const_iterator i, int16 paragraphIndex) { - paragraphWidthRemaining = 0; if (qindex != paragraphIndex) { top += qpadding.bottom(); qindex = paragraphIndex; @@ -960,23 +953,6 @@ void String::enumerateLines( top += qpadding.top(); qpadding.setTop(0); } - const auto e = _blocks.cend(); - if (i != e) { - auto last_rPadding = QFixed(0); - auto last_rBearing = QFixed(0); - for (; i != e; ++i) { - if ((*i)->type() == TextBlockType::Newline) { - break; - } - const auto rBearing = (*i)->f_rbearing(); - paragraphWidthRemaining += last_rBearing - + last_rPadding - + (*i)->f_width() - - rBearing; - last_rBearing = rBearing; - } - } - paragraphWidthRemaining += qpadding.left() + qpadding.right(); initNextLine(); }; @@ -1004,6 +980,9 @@ void String::enumerateLines( } callback(lineLeft + lineWidth - widthLeft, top += lineHeight); + if (lineElided) { + return withElided(true); + } lineHeight = 0; initNextParagraph(i + 1, index); @@ -1059,7 +1038,9 @@ void String::enumerateLines( continue; } - if (f != j && !geometry.breakEverywhere) { + if (lineElided) { + lineHeight = qMax(lineHeight, blockHeight); + } else if (f != j && !geometry.breakEverywhere) { j = f; widthLeft = f_wLeft; lineHeight = f_lineHeight; @@ -1067,10 +1048,12 @@ void String::enumerateLines( } callback(lineLeft + lineWidth - widthLeft, top += lineHeight); + if (lineElided) { + return withElided(true); + } lineHeight = qMax(0, blockHeight); - paragraphWidthRemaining -= (lineWidth - widthLeft) - last_rPadding + last_rBearing; initNextLine(); last_rBearing = j->f_rbearing(); @@ -1085,10 +1068,15 @@ void String::enumerateLines( continue; } + if (lineElided) { + lineHeight = qMax(lineHeight, blockHeight); + } callback(lineLeft + lineWidth - widthLeft, top += lineHeight); + if (lineElided) { + return withElided(true); + } lineHeight = qMax(0, blockHeight); - paragraphWidthRemaining -= (lineWidth - widthLeft) - last_rPadding + last_rBearing; initNextLine(); last_rBearing = b__f_rbearing; @@ -1103,6 +1091,7 @@ void String::enumerateLines( lineLeft + lineWidth - widthLeft, top + lineHeight + qpadding.bottom()); } + return withElided(false); } void String::draw(QPainter &p, const PaintContext &context) const { @@ -1144,11 +1133,8 @@ void String::drawElided(Painter &p, int32 left, int32 top, int32 w, int32 lines, .palette = &p.textPalette(), .paused = p.inactive(), .selection = selection, - .elisionHeight = ((!isEmpty() && lines > 1) - ? (lines * _st->font->height) - : 0), + .elisionLines = lines, .elisionRemoveFromEnd = removeFromEnd, - .elisionOneLine = (lines == 1), }); } @@ -1185,7 +1171,7 @@ StateResult String::getState(QPoint point, int width, StateRequest request) cons } return Renderer(*this).getState( point, - SimpleGeometry(width, _st->font->height, 0, 0, false, false), + SimpleGeometry(width, 0, 0, false), request); } @@ -1199,10 +1185,8 @@ StateResult String::getStateElided(QPoint point, int width, StateRequestElided r } return Renderer(*this).getState(point, SimpleGeometry( width, - _st->font->height, - (request.lines > 1) ? (request.lines * _st->font->height) : 0, + request.lines, request.removeFromEnd, - (request.lines == 1), request.flags & StateRequest::Flag::BreakEverywhere ), static_cast(request)); } diff --git a/ui/text/text.h b/ui/text/text.h index fc174d7..e6f8f42 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -146,23 +146,21 @@ struct SpecialColor { struct LineGeometry { int left = 0; - int top = 0; int width = 0; bool elided = false; }; struct GeometryDescriptor { - Fn layout; + Fn layout; bool breakEverywhere = false; + bool *outElided = nullptr; }; [[nodiscard]] not_null DefaultSpoilerCache(); [[nodiscard]] GeometryDescriptor SimpleGeometry( int availableWidth, - int fontHeight, - int elisionHeight, + int elisionLines, int elisionRemoveFromEnd, - bool elisionOneLine, bool elisionBreakEverywhere); constexpr auto kMaxQuoteOutlines = 3; @@ -230,8 +228,8 @@ struct PaintContext { HighlightInfoRequest *highlight = nullptr; int elisionHeight = 0; + int elisionLines = 0; int elisionRemoveFromEnd = 0; - bool elisionOneLine = false; bool elisionBreakEverywhere = false; }; diff --git a/ui/text/text_renderer.cpp b/ui/text/text_renderer.cpp index 42b28fb..2231fa0 100644 --- a/ui/text/text_renderer.cpp +++ b/ui/text/text_renderer.cpp @@ -189,10 +189,10 @@ void Renderer::draw(QPainter &p, const PaintContext &context) { ? context.geometry : SimpleGeometry( context.availableWidth, - _t->_st->font->height, - context.elisionHeight, + (context.elisionLines + ? context.elisionLines + : (context.elisionHeight / _t->_st->font->height)), context.elisionRemoveFromEnd, - context.elisionOneLine, context.elisionBreakEverywhere); _breakEverywhere = _geometry.breakEverywhere; _spoilerCache = context.spoiler; @@ -213,6 +213,8 @@ void Renderer::draw(QPainter &p, const PaintContext &context) { } void Renderer::enumerate() { + Expects(!_geometry.outElided); + _blocksSize = _t->_blocks.size(); _str = _t->_text.unicode(); @@ -356,7 +358,6 @@ void Renderer::enumerate() { _lineHeight = qMax(0, blockHeight); _lineStart = j->position(); _lineStartBlock = blockIndex; - _paragraphWidthRemaining -= (_lineWidth - _wLeft) - _last_rPadding + last_rBearing; initNextLine(); last_rBearing = j->f_rbearing(); @@ -385,7 +386,6 @@ void Renderer::enumerate() { _lineHeight = qMax(0, blockHeight); _lineStart = b->position(); _lineStartBlock = blockIndex; - _paragraphWidthRemaining -= (_lineWidth - _wLeft) - _last_rPadding + last_rBearing; initNextLine(); last_rBearing = b__f_rbearing; @@ -506,7 +506,6 @@ void Renderer::initNextParagraph( ? style::LayoutDirection() : direction; _paragraphStartBlock = i; - _paragraphWidthRemaining = 0; if (_quoteIndex != paragraphIndex) { _y += _quotePadding.bottom(); _quoteIndex = paragraphIndex; @@ -525,39 +524,18 @@ void Renderer::initNextParagraph( } else { _lineStart = _paragraphStart = (*i)->position(); _lineStartBlock = i - _t->_blocks.cbegin(); - - auto last_rPadding = QFixed(0); - auto last_rBearing = QFixed(0); - for (; i != e; ++i) { - if ((*i)->type() == TextBlockType::Newline) { - break; - } - const auto rBearing = (*i)->f_rbearing(); - _paragraphWidthRemaining += last_rBearing - + last_rPadding - + (*i)->f_width() - - rBearing; - last_rBearing = rBearing; - } _paragraphLength = ((i == e) ? _t->_text.size() : (*i)->position()) - _paragraphStart; } _paragraphAnalysis.resize(0); - _paragraphWidthRemaining += _quotePadding.left() + _quotePadding.right(); initNextLine(); } void Renderer::initNextLine() { - const auto line = _geometry.layout({ - .left = 0, - .top = (_y - _startTop), - .width = _paragraphWidthRemaining.ceil().toInt(), - }); - _quoteLineTop += _startTop + line.top - _y; + const auto line = _geometry.layout(_lineIndex++); _x = _startLeft + line.left + _quotePadding.left(); - _y = _startTop + line.top; _startLineWidth = line.width; _quoteShift = 0; if (_quote && _quote->maxWidth < _startLineWidth) { diff --git a/ui/text/text_renderer.h b/ui/text/text_renderer.h index a248d4d..ba9aab7 100644 --- a/ui/text/text_renderer.h +++ b/ui/text/text_renderer.h @@ -179,7 +179,6 @@ private: int _paragraphLength = 0; bool _paragraphHasBidi = false; QVarLengthArray _paragraphAnalysis; - QFixed _paragraphWidthRemaining = 0; // current quote data QuoteDetails *_quote = nullptr; @@ -203,6 +202,7 @@ private: QFixed _x, _wLeft, _last_rPadding; int _y = 0; int _yDelta = 0; + int _lineIndex = 0; int _lineHeight = 0; int _fontHeight = 0; bool _breakEverywhere = false;