Count correctly elided text dimensions.
This commit is contained in:
parent
08235c5e06
commit
65310f32dc
4 changed files with 61 additions and 101 deletions
116
ui/text/text.cpp
116
ui/text/text.cpp
|
|
@ -142,47 +142,36 @@ not_null<SpoilerMessCache*> DefaultSpoilerCache() {
|
|||
|
||||
GeometryDescriptor SimpleGeometry(
|
||||
int availableWidth,
|
||||
int fontHeight,
|
||||
int elisionHeight,
|
||||
int elisionLines,
|
||||
int elisionRemoveFromEnd,
|
||||
bool elisionOneLine,
|
||||
bool elisionBreakEverywhere) {
|
||||
constexpr auto wrap = [](
|
||||
Fn<LineGeometry(LineGeometry)> layout,
|
||||
Fn<LineGeometry(int line)> 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>(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<StateRequest>(request));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,23 +146,21 @@ struct SpecialColor {
|
|||
|
||||
struct LineGeometry {
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int width = 0;
|
||||
bool elided = false;
|
||||
};
|
||||
struct GeometryDescriptor {
|
||||
Fn<LineGeometry(LineGeometry line)> layout;
|
||||
Fn<LineGeometry(int line)> layout;
|
||||
bool breakEverywhere = false;
|
||||
bool *outElided = nullptr;
|
||||
};
|
||||
|
||||
[[nodiscard]] not_null<SpoilerMessCache*> 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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ private:
|
|||
int _paragraphLength = 0;
|
||||
bool _paragraphHasBidi = false;
|
||||
QVarLengthArray<QScriptAnalysis, 4096> _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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue