diff --git a/Telegram/SourceFiles/ui/text/text.cpp b/Telegram/SourceFiles/ui/text/text.cpp index a13267db5e..42b9a8da12 100644 --- a/Telegram/SourceFiles/ui/text/text.cpp +++ b/Telegram/SourceFiles/ui/text/text.cpp @@ -857,15 +857,16 @@ public: _lineHeight = 0; _fontHeight = _t->_st->font->height; - QFixed last_rBearing = 0, last_rPadding = 0; + auto last_rBearing = QFixed(0); + _last_rPadding = QFixed(0); - int32 blockIndex = 0; + auto blockIndex = 0; bool longWordLine = true; - Text::TextBlocks::const_iterator e = _t->_blocks.cend(); - for (Text::TextBlocks::const_iterator i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) { - ITextBlock *b = *i; - TextBlockType _btype = b->type(); - int32 blockHeight = countBlockHeight(b, _t->_st); + auto e = _t->_blocks.cend(); + for (auto i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) { + auto b = *i; + auto _btype = b->type(); + auto blockHeight = countBlockHeight(b, _t->_st); if (_btype == TextBlockTNewline) { if (!_lineHeight) _lineHeight = blockHeight; @@ -879,7 +880,7 @@ public: _lineStartBlock = blockIndex + 1; last_rBearing = b->f_rbearing(); - last_rPadding = b->f_rpadding(); + _last_rPadding = b->f_rpadding(); _wLeft = _w - (b->f_width() - last_rBearing); if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { _wLeft -= _elideRemoveFromEnd; @@ -893,12 +894,11 @@ public: continue; } - auto b__f_lpadding = b->f_lpadding(); auto b__f_rbearing = b->f_rbearing(); - QFixed newWidthLeft = _wLeft - b__f_lpadding - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing); + auto newWidthLeft = _wLeft - last_rBearing - (_last_rPadding + b->f_width() - b__f_rbearing); if (newWidthLeft >= 0) { last_rBearing = b__f_rbearing; - last_rPadding = b->f_rpadding(); + _last_rPadding = b->f_rpadding(); _wLeft = newWidthLeft; _lineHeight = qMax(_lineHeight, blockHeight); @@ -908,9 +908,9 @@ public: } if (_btype == TextBlockTText) { - TextBlock *t = static_cast(b); + auto t = static_cast(b); if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line - last_rPadding += b__f_lpadding; + _last_rPadding += b->f_rpadding(); _lineHeight = qMax(_lineHeight, blockHeight); @@ -918,17 +918,16 @@ public: continue; } - QFixed f_wLeft = _wLeft; // vars for saving state of the last word start - int32 f_lineHeight = _lineHeight; // f points to the last word-start element of t->_words - for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) { - bool wordEndsHere = (j->f_width() >= 0); - QFixed j_width = wordEndsHere ? j->f_width() : -j->f_width(); + auto f_wLeft = _wLeft; // vars for saving state of the last word start + auto f_lineHeight = _lineHeight; // f points to the last word-start element of t->_words + for (auto j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) { + auto wordEndsHere = (j->f_width() >= 0); + auto j_width = wordEndsHere ? j->f_width() : -j->f_width(); - QFixed newWidthLeft = _wLeft - b__f_lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); - b__f_lpadding = 0; + auto newWidthLeft = _wLeft - last_rBearing - (_last_rPadding + j_width - j->f_rbearing()); if (newWidthLeft >= 0) { last_rBearing = j->f_rbearing(); - last_rPadding = j->f_rpadding(); + _last_rPadding = j->f_rpadding(); _wLeft = newWidthLeft; _lineHeight = qMax(_lineHeight, blockHeight); @@ -944,8 +943,8 @@ public: continue; } - int32 elidedLineHeight = qMax(_lineHeight, blockHeight); - bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide); + auto elidedLineHeight = qMax(_lineHeight, blockHeight); + auto elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide); if (elidedLine) { _lineHeight = elidedLineHeight; } else if (f != j && !_breakEverywhere) { @@ -964,7 +963,7 @@ public: _lineStartBlock = blockIndex; last_rBearing = j->f_rbearing(); - last_rPadding = j->f_rpadding(); + _last_rPadding = j->f_rpadding(); _wLeft = _w - (j_width - last_rBearing); if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { _wLeft -= _elideRemoveFromEnd; @@ -978,8 +977,8 @@ public: continue; } - int32 elidedLineHeight = qMax(_lineHeight, blockHeight); - bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide); + auto elidedLineHeight = qMax(_lineHeight, blockHeight); + auto elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide); if (elidedLine) { _lineHeight = elidedLineHeight; } @@ -992,7 +991,7 @@ public: _lineStartBlock = blockIndex; last_rBearing = b__f_rbearing; - last_rPadding = b->f_rpadding(); + _last_rPadding = b->f_rpadding(); _wLeft = _w - (b->f_width() - last_rBearing); if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { _wLeft -= _elideRemoveFromEnd; @@ -1133,18 +1132,19 @@ private: return true; } - uint16 trimmedLineEnd = _lineEnd; - // Disable text trimming because it causes render bugs in case of - // fully selected lines with pending spaces. - //for (; trimmedLineEnd > _lineStart; --trimmedLineEnd) { - // QChar ch = _t->_text.at(trimmedLineEnd - 1); - // if ((ch != QChar::Space || trimmedLineEnd == _lineStart + 1) && ch != QChar::LineFeed) { - // break; - // } - //} + // Trimming pending spaces, because they sometimes don't fit on the line. + // They also are not counted in the line width, they're in the right padding. + // Line width is a sum of block / word widths and paddings between them, without trailing one. + auto trimmedLineEnd = _lineEnd; + for (; trimmedLineEnd > _lineStart; --trimmedLineEnd) { + auto ch = _t->_text[trimmedLineEnd - 1]; + if (ch != QChar::Space && ch != QChar::LineFeed) { + break; + } + } - ITextBlock *_endBlock = (_endBlockIter == _end) ? nullptr : (*_endBlockIter); - bool elidedLine = _elideLast && (_y + _lineHeight >= _yToElide); + auto _endBlock = (_endBlockIter == _end) ? nullptr : (*_endBlockIter); + auto elidedLine = _elideLast && (_y + _lineHeight >= _yToElide); if (elidedLine) { // If we decided to draw the last line elided only because of the skip block // that did not fit on this line, we just draw the line till the very end. @@ -1157,23 +1157,24 @@ private: } } - int blockIndex = _lineStartBlock; - ITextBlock *currentBlock = _t->_blocks[blockIndex]; - ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + auto blockIndex = _lineStartBlock; + auto currentBlock = _t->_blocks[blockIndex]; + auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : nullptr; int32 delta = (currentBlock->from() < _lineStart ? qMin(_lineStart - currentBlock->from(), 2) : 0); _localFrom = _lineStart - delta; int32 lineEnd = (_endBlock && _endBlock->from() < trimmedLineEnd && !elidedLine) ? qMin(uint16(trimmedLineEnd + 2), _t->countBlockEnd(_endBlockIter, _end)) : trimmedLineEnd; - QString lineText = _t->_text.mid(_localFrom, lineEnd - _localFrom); - int32 lineStart = delta, lineLength = trimmedLineEnd - _lineStart; + auto lineText = _t->_text.mid(_localFrom, lineEnd - _localFrom); + auto lineStart = delta; + auto lineLength = trimmedLineEnd - _lineStart; if (elidedLine) { initParagraphBidi(); prepareElidedLine(lineText, lineStart, lineLength, _endBlock); } - QFixed x = _x; + auto x = _x; if (_align & Qt::AlignHCenter) { x += (_wLeft / 2).toInt(); } else if (((_align & Qt::AlignLeft) && _parDirection == Qt::RightToLeft) || ((_align & Qt::AlignRight) && _parDirection == Qt::LeftToRight)) { @@ -1632,10 +1633,10 @@ private: glyphsEnd = si.num_glyphs; } - for (int g = glyphsStart; g < glyphsEnd; ++g) { - QFixed adv = glyphs.effectiveAdvance(g); + for (auto g = glyphsStart; g < glyphsEnd; ++g) { + auto adv = glyphs.effectiveAdvance(g); if (_wLeft < adv) { - int pos = itemStart; + auto pos = itemStart; while (pos < itemEnd && logClusters[pos - si.position] < g) { ++pos; } @@ -2356,7 +2357,7 @@ private: // current line data QTextEngine *_e = nullptr; style::font _f; - QFixed _x, _w, _wLeft; + QFixed _x, _w, _wLeft, _last_rPadding; int32 _y, _yDelta, _lineHeight, _fontHeight; // elided hack support @@ -2473,10 +2474,10 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { int32 lineHeight = 0; int32 result = 0, lastNewlineStart = 0; QFixed _width = 0, last_rBearing = 0, last_rPadding = 0; - for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { - ITextBlock *b = *i; - TextBlockType _btype = b->type(); - int32 blockHeight = countBlockHeight(b, _st); + for (auto i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { + auto b = *i; + auto _btype = b->type(); + auto blockHeight = countBlockHeight(b, _st); if (_btype == TextBlockTNewline) { if (!lineHeight) lineHeight = blockHeight; if (initial) { @@ -2506,7 +2507,6 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { auto b__f_rbearing = b->f_rbearing(); // cache - _width += b->f_lpadding(); _width += last_rBearing + (last_rPadding + b->f_width() - b__f_rbearing); lineHeight = qMax(lineHeight, blockHeight); @@ -2720,7 +2720,7 @@ void Text::enumerateLines(int w, Callback callback) const { QFixed widthLeft = width, last_rBearing = 0, last_rPadding = 0; bool longWordLine = true; for_const (auto b, _blocks) { - TextBlockType _btype = b->type(); + auto _btype = b->type(); int blockHeight = countBlockHeight(b, _st); if (_btype == TextBlockTNewline) { @@ -2735,9 +2735,8 @@ void Text::enumerateLines(int w, Callback callback) const { longWordLine = true; continue; } - auto b__f_lpadding = b->f_lpadding(); auto b__f_rbearing = b->f_rbearing(); - QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing); + auto newWidthLeft = widthLeft - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing); if (newWidthLeft >= 0) { last_rBearing = b__f_rbearing; last_rPadding = b->f_rpadding(); @@ -2750,9 +2749,9 @@ void Text::enumerateLines(int w, Callback callback) const { } if (_btype == TextBlockTText) { - TextBlock *t = static_cast(b); + auto t = static_cast(b); if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line - last_rPadding += b__f_lpadding; + last_rPadding += b->f_rpadding(); lineHeight = qMax(lineHeight, blockHeight); @@ -2760,14 +2759,13 @@ void Text::enumerateLines(int w, Callback callback) const { continue; } - QFixed f_wLeft = widthLeft; + auto f_wLeft = widthLeft; int f_lineHeight = lineHeight; for (auto j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) { bool wordEndsHere = (j->f_width() >= 0); - QFixed j_width = wordEndsHere ? j->f_width() : -j->f_width(); + auto j_width = wordEndsHere ? j->f_width() : -j->f_width(); - QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); - b__f_lpadding = 0; + auto newWidthLeft = widthLeft - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); if (newWidthLeft >= 0) { last_rBearing = j->f_rbearing(); last_rPadding = j->f_rpadding(); diff --git a/Telegram/SourceFiles/ui/text/text_block.cpp b/Telegram/SourceFiles/ui/text/text_block.cpp index 145dc080d9..fc55db1de8 100644 --- a/Telegram/SourceFiles/ui/text/text_block.cpp +++ b/Telegram/SourceFiles/ui/text/text_block.cpp @@ -177,7 +177,6 @@ public: int end = 0; lbh.logClusters = eng->layoutData->logClustersPtr; - block->_lpadding = 0; block->_words.clear(); int wordStart = lbh.currentPosition; @@ -213,11 +212,10 @@ public: current, lbh.logClusters, lbh.glyphs); if (block->_words.isEmpty()) { - block->_lpadding = lbh.spaceData.textWidth; - } else { - block->_words.back().add_rpadding(lbh.spaceData.textWidth); - block->_width += lbh.spaceData.textWidth; + block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, -lbh.negativeRightBearing())); } + block->_words.back().add_rpadding(lbh.spaceData.textWidth); + block->_width += lbh.spaceData.textWidth; lbh.spaceData.length = 0; lbh.spaceData.textWidth = 0; @@ -271,9 +269,7 @@ public: if (lbh.currentPosition == end) newItem = item + 1; } - if (block->_words.isEmpty()) { - block->_rpadding = 0; - } else { + if (!block->_words.isEmpty()) { block->_rpadding = block->_words.back().f_rpadding(); block->_width -= block->_rpadding; block->_words.squeeze(); @@ -347,21 +343,20 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi } } -EmojiBlock::EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, uint16 lnkIndex, EmojiPtr emoji) : ITextBlock(font, str, from, length, flags, lnkIndex), emoji(emoji) { +EmojiBlock::EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, uint16 lnkIndex, EmojiPtr emoji) : ITextBlock(font, str, from, length, flags, lnkIndex) +, emoji(emoji) { _flags |= ((TextBlockTEmoji & 0x0F) << 8); _width = int(st::emojiSize + 2 * st::emojiPadding); - auto padding = 0; + _rpadding = 0; for (auto i = length; i != 0;) { auto ch = str[_from + (--i)]; if (ch.unicode() == QChar::Space) { - padding += font->spacew; + _rpadding += font->spacew; } else { - _rpadding = padding; - return; + break; } } - _lpadding = padding; } SkipBlock::SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex) : ITextBlock(font, str, from, 1, 0, lnkIndex), _height(h) { diff --git a/Telegram/SourceFiles/ui/text/text_block.h b/Telegram/SourceFiles/ui/text/text_block.h index 692cb00845..3d89956f95 100644 --- a/Telegram/SourceFiles/ui/text/text_block.h +++ b/Telegram/SourceFiles/ui/text/text_block.h @@ -50,18 +50,12 @@ public: int32 width() const { return _width.toInt(); } - int32 lpadding() const { - return _lpadding.toInt(); - } int32 rpadding() const { return _rpadding.toInt(); } QFixed f_width() const { return _width; } - QFixed f_lpadding() const { - return _lpadding; - } QFixed f_rpadding() const { return _rpadding; } @@ -88,13 +82,17 @@ public: } protected: - uint16 _from = 0; uint32 _flags = 0; // 4 bits empty, 16 bits lnkIndex, 4 bits type, 8 bits flags QFixed _width = 0; - QFixed _lpadding = 0; + + // Right padding: spaces after the last content of the block (like a word). + // This holds spaces after the end of the block, for example a text ending + // with a space before a link has started. If text block has a leading spaces + // (for example a text block after a link block) it is prepended with an empty + // word that holds those spaces as a right padding. QFixed _rpadding = 0; };