From 8d43bdb0844efa4eb19350bc1a2259502dd6acb0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 6 Jul 2017 18:58:05 +0300 Subject: [PATCH] Use std::unique_ptrs for ITextBlocks. --- Telegram/SourceFiles/ui/text/text.cpp | 146 +++++++++++----------- Telegram/SourceFiles/ui/text/text.h | 6 +- Telegram/SourceFiles/ui/text/text_block.h | 44 +++---- 3 files changed, 97 insertions(+), 99 deletions(-) diff --git a/Telegram/SourceFiles/ui/text/text.cpp b/Telegram/SourceFiles/ui/text/text.cpp index 4d07d477b..9ab139403 100644 --- a/Telegram/SourceFiles/ui/text/text.cpp +++ b/Telegram/SourceFiles/ui/text/text.cpp @@ -178,13 +178,13 @@ public: } lastSkipped = false; if (emoji) { - _t->_blocks.push_back(new EmojiBlock(_t->_st->font, _t->_text, blockStart, len, flags, lnkIndex, emoji)); + _t->_blocks.push_back(std::make_unique(_t->_st->font, _t->_text, blockStart, len, flags, lnkIndex, emoji)); emoji = 0; lastSkipped = true; } else if (newline) { - _t->_blocks.push_back(new NewlineBlock(_t->_st->font, _t->_text, blockStart, len, flags, lnkIndex)); + _t->_blocks.push_back(std::make_unique(_t->_st->font, _t->_text, blockStart, len, flags, lnkIndex)); } else { - _t->_blocks.push_back(new TextBlock(_t->_st->font, _t->_text, _t->_minResizeWidth, blockStart, len, flags, lnkIndex)); + _t->_blocks.push_back(std::make_unique(_t->_st->font, _t->_text, _t->_minResizeWidth, blockStart, len, flags, lnkIndex)); } blockStart += len; blockCreated(); @@ -194,7 +194,7 @@ public: void createSkipBlock(int32 w, int32 h) { createBlock(); _t->_text.push_back('_'); - _t->_blocks.push_back(new SkipBlock(_t->_st->font, _t->_text, blockStart++, w, h, lnkIndex)); + _t->_blocks.push_back(std::make_unique(_t->_st->font, _t->_text, blockStart++, w, h, lnkIndex)); blockCreated(); } @@ -251,7 +251,7 @@ public: } else if (type == EntityInTextPre) { startFlags = TextBlockFPre; createBlock(); - if (!_t->_blocks.isEmpty() && _t->_blocks.back()->type() != TextBlockTNewline) { + if (!_t->_blocks.empty() && _t->_blocks.back()->type() != TextBlockTNewline) { createNewlineBlock(); } } else if (type == EntityInTextUrl @@ -587,7 +587,7 @@ public: _t->_links.resize(maxLnkIndex); for (auto i = _t->_blocks.cbegin(), e = _t->_blocks.cend(); i != e; ++i) { - auto b = *i; + auto b = i->get(); if (b->lnkIndex() > 0x8000) { lnkIndex = maxLnkIndex + (b->lnkIndex() - 0x8000); if (_t->_links.size() < lnkIndex) { @@ -635,7 +635,7 @@ public: } } _t->_links.squeeze(); - _t->_blocks.squeeze(); + _t->_blocks.shrink_to_fit(); _t->_text.squeeze(); } @@ -823,8 +823,8 @@ public: _wLeft = _w = w; if (_elideLast) { _yToElide = _yTo; - if (_elideRemoveFromEnd > 0 && !_t->_blocks.isEmpty()) { - int firstBlockHeight = countBlockHeight(_t->_blocks.front(), _t->_st); + if (_elideRemoveFromEnd > 0 && !_t->_blocks.empty()) { + int firstBlockHeight = countBlockHeight(_t->_blocks.front().get(), _t->_st); if (_y + firstBlockHeight >= _yToElide) { _wLeft -= _elideRemoveFromEnd; } @@ -860,7 +860,7 @@ public: bool longWordLine = true; auto e = _t->_blocks.cend(); for (auto i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) { - auto b = *i; + auto b = i->get(); auto _btype = b->type(); auto blockHeight = countBlockHeight(b, _t->_st); @@ -1139,7 +1139,7 @@ private: } } - auto _endBlock = (_endBlockIter == _end) ? nullptr : (*_endBlockIter); + auto _endBlock = (_endBlockIter == _end) ? nullptr : _endBlockIter->get(); auto elidedLine = _elideLast && (_y + _lineHeight >= _yToElide); if (elidedLine) { // If we decided to draw the last line elided only because of the skip block @@ -1154,8 +1154,8 @@ private: } auto blockIndex = _lineStartBlock; - auto currentBlock = _t->_blocks[blockIndex]; - auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : nullptr; + auto currentBlock = _t->_blocks[blockIndex].get(); + auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; int32 delta = (currentBlock->from() < _lineStart ? qMin(_lineStart - currentBlock->from(), 2) : 0); _localFrom = _lineStart - delta; @@ -1254,12 +1254,12 @@ private: QVarLengthArray visualOrder(nItems); QVarLengthArray levels(nItems); for (int i = 0; i < nItems; ++i) { - QScriptItem &si(engine.layoutData->items[firstItem + i]); + auto &si = engine.layoutData->items[firstItem + i]; while (nextBlock && nextBlock->from() <= _localFrom + si.position) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; } - TextBlockType _type = currentBlock->type(); + auto _type = currentBlock->type(); if (_type == TextBlockTSkip) { levels[i] = si.analysis.bidiLevel = 0; skipIndex = i; @@ -1282,8 +1282,8 @@ private: } blockIndex = _lineStartBlock; - currentBlock = _t->_blocks[blockIndex]; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + currentBlock = _t->_blocks[blockIndex].get(); + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; int32 textY = _y + _yDelta + _t->_st->font->ascent, emojiY = (_t->_st->font->height - st::emojiSize) / 2; @@ -1295,12 +1295,12 @@ private: while (blockIndex > _lineStartBlock + 1 && _t->_blocks[blockIndex - 1]->from() > _localFrom + si.position) { nextBlock = currentBlock; - currentBlock = _t->_blocks[--blockIndex - 1]; + currentBlock = _t->_blocks[--blockIndex - 1].get(); applyBlockProperties(currentBlock); } while (nextBlock && nextBlock->from() <= _localFrom + si.position) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; applyBlockProperties(currentBlock); } if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { @@ -1551,10 +1551,11 @@ private: } _elideSavedIndex = blockIndex; - _elideSavedBlock = _t->_blocks[blockIndex]; - const_cast(_t)->_blocks[blockIndex] = new TextBlock(_t->_st->font, _t->_text, QFIXED_MAX, elideStart, 0, _elideSavedBlock->flags(), _elideSavedBlock->lnkIndex()); + auto mutableText = const_cast(_t); + _elideSavedBlock = std::move(mutableText->_blocks[blockIndex]); + mutableText->_blocks[blockIndex] = std::make_unique(_t->_st->font, _t->_text, QFIXED_MAX, elideStart, 0, _elideSavedBlock->flags(), _elideSavedBlock->lnkIndex()); _blocksSize = blockIndex + 1; - _endBlock = (blockIndex + 1 < _t->_blocks.size() ? _t->_blocks[blockIndex + 1] : 0); + _endBlock = (blockIndex + 1 < _t->_blocks.size() ? _t->_blocks[blockIndex + 1].get() : nullptr); } void setElideBidi(int32 elideStart, int32 elideLen) { @@ -1577,9 +1578,9 @@ private: eItemize(); - int blockIndex = _lineStartBlock; - ITextBlock *currentBlock = _t->_blocks[blockIndex]; - ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + auto blockIndex = _lineStartBlock; + auto currentBlock = _t->_blocks[blockIndex].get(); + auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; QScriptLine line; line.from = lineStart; @@ -1596,7 +1597,7 @@ private: QScriptItem &si(engine.layoutData->items[firstItem + i]); while (nextBlock && nextBlock->from() <= _localFrom + si.position) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; } TextBlockType _type = currentBlock->type(); if (si.analysis.flags == QScriptAnalysis::Object) { @@ -1667,7 +1668,7 @@ private: lineLength += _Elide.size(); if (!repeat) { - for (; blockIndex < _blocksSize && _t->_blocks[blockIndex] != _endBlock && _t->_blocks[blockIndex]->from() < elideStart; ++blockIndex) { + for (; blockIndex < _blocksSize && _t->_blocks[blockIndex].get() != _endBlock && _t->_blocks[blockIndex]->from() < elideStart; ++blockIndex) { } if (blockIndex < _blocksSize) { elideSaveBlock(blockIndex, _endBlock, elideStart, elideWidth); @@ -1677,9 +1678,7 @@ private: void restoreAfterElided() { if (_elideSavedBlock) { - delete _t->_blocks[_elideSavedIndex]; - const_cast(_t)->_blocks[_elideSavedIndex] = _elideSavedBlock; - _elideSavedBlock = nullptr; + const_cast(_t)->_blocks[_elideSavedIndex] = std::move(_elideSavedBlock); } } @@ -1695,15 +1694,15 @@ private: auto end = _e->findItem(line.from + line.length - 1, item); #endif // OS_MAC_OLD - int blockIndex = _lineStartBlock; - ITextBlock *currentBlock = _t->_blocks[blockIndex]; - ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + auto blockIndex = _lineStartBlock; + auto currentBlock = _t->_blocks[blockIndex].get(); + auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; eSetFont(currentBlock); for (; item <= end; ++item) { QScriptItem &si = _e->layoutData->items[item]; while (nextBlock && nextBlock->from() <= _localFrom + si.position) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; eSetFont(currentBlock); } _e->shape(item); @@ -1773,12 +1772,12 @@ private: const ushort *string = reinterpret_cast(_e->layoutData->string.unicode()); - int blockIndex = _lineStartBlock; - ITextBlock *currentBlock = _t->_blocks[blockIndex]; - ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + auto blockIndex = _lineStartBlock; + auto currentBlock = _t->_blocks[blockIndex].get(); + auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; _e->layoutData->hasBidi = _parHasBidi; - QScriptAnalysis *analysis = _parAnalysis.data() + (_localFrom - _parStart); + auto analysis = _parAnalysis.data() + (_localFrom - _parStart); { QVarLengthArray scripts(length); @@ -1788,17 +1787,17 @@ private: } blockIndex = _lineStartBlock; - currentBlock = _t->_blocks[blockIndex]; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + currentBlock = _t->_blocks[blockIndex].get(); + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; - const ushort *start = string; - const ushort *end = start + length; + auto start = string; + auto end = start + length; while (start < end) { while (nextBlock && nextBlock->from() <= _localFrom + (start - string)) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; } - TextBlockType _type = currentBlock->type(); + auto _type = currentBlock->type(); if (_type == TextBlockTEmoji || _type == TextBlockTSkip) { analysis->script = QChar::Script_Common; analysis->flags = QScriptAnalysis::Object; @@ -1811,22 +1810,24 @@ private: } { - const QString *i_string = &_e->layoutData->string; - const QScriptAnalysis *i_analysis = _parAnalysis.data() + (_localFrom - _parStart); - QScriptItemArray *i_items = &_e->layoutData->items; + auto i_string = &_e->layoutData->string; + auto i_analysis = _parAnalysis.data() + (_localFrom - _parStart); + auto i_items = &_e->layoutData->items; blockIndex = _lineStartBlock; - currentBlock = _t->_blocks[blockIndex]; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; - ITextBlock *startBlock = currentBlock; + currentBlock = _t->_blocks[blockIndex].get(); + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; + auto startBlock = currentBlock; - if (!length) + if (!length) { return; - int start = 0, end = start + length; + } + auto start = 0; + auto end = start + length; for (int i = start + 1; i < end; ++i) { while (nextBlock && nextBlock->from() <= _localFrom + i) { currentBlock = nextBlock; - nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; + nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; } // According to the unicode spec we should be treating characters in the Common script // (punctuation, spaces, etc) as being the same script as the surrounding text for the @@ -2359,7 +2360,7 @@ private: // elided hack support int _blocksSize = 0; int _elideSavedIndex = 0; - ITextBlock *_elideSavedBlock = nullptr; + std::unique_ptr _elideSavedBlock; int _lineStart = 0; int _localFrom = 0; @@ -2406,11 +2407,11 @@ Text::Text(const Text &other) , _minHeight(other._minHeight) , _text(other._text) , _st(other._st) -, _blocks(other._blocks.size()) , _links(other._links) , _startDir(other._startDir) { - for (int32 i = 0, l = _blocks.size(); i < l; ++i) { - _blocks[i] = other._blocks.at(i)->clone(); + _blocks.reserve(other._blocks.size()); + for (auto &block : other._blocks) { + _blocks.push_back(block->clone()); } } @@ -2420,7 +2421,7 @@ Text::Text(Text &&other) , _minHeight(other._minHeight) , _text(other._text) , _st(other._st) -, _blocks(other._blocks) +, _blocks(std::move(other._blocks)) , _links(other._links) , _startDir(other._startDir) { other.clearFields(); @@ -2447,7 +2448,7 @@ Text &Text::operator=(Text &&other) { _minHeight = other._minHeight; _text = other._text; _st = other._st; - _blocks = other._blocks; + _blocks = std::move(other._blocks); _links = other._links; _startDir = other._startDir; other.clearFields(); @@ -2471,7 +2472,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { int32 result = 0, 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; + auto b = i->get(); auto _btype = b->type(); auto blockHeight = countBlockHeight(b, _st); if (_btype == TextBlockTNewline) { @@ -2530,7 +2531,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) { } } if (_width > 0) { - if (!lineHeight) lineHeight = countBlockHeight(_blocks.back(), _st); + if (!lineHeight) lineHeight = countBlockHeight(_blocks.back().get(), _st); _minHeight += lineHeight; accumulate_max(_maxWidth, _width); } @@ -2659,23 +2660,23 @@ bool Text::hasLinks() const { } bool Text::hasSkipBlock() const { - return _blocks.isEmpty() ? false : _blocks.back()->type() == TextBlockTSkip; + return _blocks.empty() ? false : _blocks.back()->type() == TextBlockTSkip; } void Text::setSkipBlock(int32 width, int32 height) { - if (!_blocks.isEmpty() && _blocks.back()->type() == TextBlockTSkip) { - SkipBlock *block = static_cast(_blocks.back()); + if (!_blocks.empty() && _blocks.back()->type() == TextBlockTSkip) { + auto block = static_cast(_blocks.back().get()); if (block->width() == width && block->height() == height) return; _text.resize(block->from()); _blocks.pop_back(); } _text.push_back('_'); - _blocks.push_back(new SkipBlock(_st->font, _text, _text.size() - 1, width, height, 0)); + _blocks.push_back(std::make_unique(_st->font, _text, _text.size() - 1, width, height, 0)); recountNaturalSize(false); } void Text::removeSkipBlock() { - if (!_blocks.isEmpty() && _blocks.back()->type() == TextBlockTSkip) { + if (!_blocks.empty() && _blocks.back()->type() == TextBlockTSkip) { _text.resize(_blocks.back()->from()); _blocks.pop_back(); recountNaturalSize(false); @@ -2721,9 +2722,9 @@ void Text::enumerateLines(int w, Callback callback) const { int lineHeight = 0; QFixed widthLeft = width, last_rBearing = 0, last_rPadding = 0; bool longWordLine = true; - for_const (auto b, _blocks) { + for (auto &b : _blocks) { auto _btype = b->type(); - int blockHeight = countBlockHeight(b, _st); + int blockHeight = countBlockHeight(b.get(), _st); if (_btype == TextBlockTNewline) { if (!lineHeight) lineHeight = blockHeight; @@ -2751,7 +2752,7 @@ void Text::enumerateLines(int w, Callback callback) const { } if (_btype == TextBlockTText) { - auto t = static_cast(b); + auto t = static_cast(b.get()); if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line last_rPadding += b->f_rpadding(); @@ -3027,9 +3028,6 @@ QString Text::originalText(TextSelection selection, ExpandLinksMode mode) const } void Text::clear() { - for (TextBlocks::iterator i = _blocks.begin(), e = _blocks.end(); i != e; ++i) { - delete *i; - } clearFields(); _text.clear(); } @@ -3041,6 +3039,8 @@ void Text::clearFields() { _startDir = Qt::LayoutDirectionAuto; } +Text::~Text() = default; + void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) { auto size = Ui::Emoji::Size(); p.drawPixmap(QPoint(x, y), App::emoji(), QRect(e->x() * size, e->y() * size, size, size)); diff --git a/Telegram/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index 4c22681fd..c5af19d19 100644 --- a/Telegram/SourceFiles/ui/text/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -199,12 +199,10 @@ public: } void clear(); - ~Text() { - clear(); - } + ~Text(); private: - using TextBlocks = QVector; + using TextBlocks = std::vector>; using TextLinks = QVector; uint16 countBlockEnd(const TextBlocks::const_iterator &i, const TextBlocks::const_iterator &e) const; diff --git a/Telegram/SourceFiles/ui/text/text_block.h b/Telegram/SourceFiles/ui/text/text_block.h index d7d3689d8..ff6f2b810 100644 --- a/Telegram/SourceFiles/ui/text/text_block.h +++ b/Telegram/SourceFiles/ui/text/text_block.h @@ -77,7 +77,7 @@ public: return (_flags & 0xFF); } - virtual ITextBlock *clone() const = 0; + virtual std::unique_ptr clone() const = 0; virtual ~ITextBlock() { } @@ -99,19 +99,19 @@ protected: class NewlineBlock : public ITextBlock { public: - Qt::LayoutDirection nextDirection() const { - return _nextDir; - } - - ITextBlock *clone() const { - return new NewlineBlock(*this); - } - -private: NewlineBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, lnkIndex), _nextDir(Qt::LayoutDirectionAuto) { _flags |= ((TextBlockTNewline & 0x0F) << 8); } + Qt::LayoutDirection nextDirection() const { + return _nextDir; + } + + std::unique_ptr clone() const override { + return std::make_unique(*this); + } + +private: Qt::LayoutDirection _nextDir; friend class Text; @@ -155,13 +155,13 @@ private: class TextBlock : public ITextBlock { public: - ITextBlock *clone() const { - return new TextBlock(*this); + TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, uint16 lnkIndex); + + std::unique_ptr clone() const override { + return std::make_unique(*this); } private: - TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, uint16 lnkIndex); - friend class ITextBlock; QFixed real_f_rbearing() const { return _words.isEmpty() ? 0 : _words.back().f_rbearing(); @@ -180,13 +180,13 @@ private: class EmojiBlock : public ITextBlock { public: - ITextBlock *clone() const { - return new EmojiBlock(*this); + EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, uint16 lnkIndex, EmojiPtr emoji); + + std::unique_ptr clone() const { + return std::make_unique(*this); } private: - EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, uint16 lnkIndex, EmojiPtr emoji); - EmojiPtr emoji = nullptr; friend class Text; @@ -198,17 +198,17 @@ private: class SkipBlock : public ITextBlock { public: + SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex); + int32 height() const { return _height; } - ITextBlock *clone() const { - return new SkipBlock(*this); + std::unique_ptr clone() const override { + return std::make_unique(*this); } private: - SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex); - int32 _height; friend class Text;