diff --git a/ui/text/text.cpp b/ui/text/text.cpp index b8e4911..60a8a52 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -2755,7 +2755,7 @@ void String::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { _maxWidth = _minHeight = 0; int32 lineHeight = 0; - int32 result = 0, lastNewlineStart = 0; + int32 lastNewlineStart = 0; QFixed _width = 0, last_rBearing = 0, last_rPadding = 0; for (auto i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { auto b = i->get(); @@ -2823,6 +2823,63 @@ void String::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { } } +int String::countMaxMonospaceWidth() const { + NewlineBlock *lastNewline = 0; + + auto result = QFixed(); + auto paragraphWidth = QFixed(); + auto lastNewlineStart = 0; + auto fullMonospace = true; + QFixed _width = 0, last_rBearing = 0, last_rPadding = 0; + for (auto i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { + auto b = i->get(); + auto _btype = b->type(); + if (_btype == TextBlockTNewline) { + lastNewlineStart = b->from(); + lastNewline = static_cast(b); + + last_rBearing = b->f_rbearing(); + last_rPadding = b->f_rpadding(); + + if (fullMonospace) { + accumulate_max(paragraphWidth, _width); + accumulate_max(result, paragraphWidth); + paragraphWidth = 0; + } else { + fullMonospace = true; + } + _width = (b->f_width() - last_rBearing); + continue; + } + if (!(b->flags() & (TextBlockFPre | TextBlockFCode)) + && (b->type() != TextBlockTSkip)) { + fullMonospace = false; + } + auto b__f_rbearing = b->f_rbearing(); // cache + + // We need to accumulate max width after each block, because + // some blocks have width less than -1 * previous right bearing. + // In that cases the _width gets _smaller_ after moving to the next block. + // + // But when we layout block and we're sure that _maxWidth is enough + // for all the blocks to fit on their line we check each block, even the + // intermediate one with a large negative right bearing. + if (fullMonospace) { + accumulate_max(paragraphWidth, _width); + } + _width += last_rBearing + (last_rPadding + b->f_width() - b__f_rbearing); + + last_rBearing = b__f_rbearing; + last_rPadding = b->f_rpadding(); + continue; + } + if (_width > 0 && fullMonospace) { + accumulate_max(paragraphWidth, _width); + accumulate_max(result, paragraphWidth); + } + return result.ceil().toInt(); +} + void String::setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options) { _st = &st; clear(); diff --git a/ui/text/text.h b/ui/text/text.h index dd7614e..709f22a 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -128,12 +128,13 @@ public: bool updateSkipBlock(int width, int height); bool removeSkipBlock(); - int32 maxWidth() const { + int maxWidth() const { return _maxWidth.ceil().toInt(); } - int32 minHeight() const { + int minHeight() const { return _minHeight; } + int countMaxMonospaceWidth() const; void draw(Painter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }, bool fullWidthSelection = true) const; void drawElided(Painter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const;