Use std::unique_ptrs for ITextBlocks.

This commit is contained in:
John Preston 2017-07-06 18:58:05 +03:00
parent 8550099110
commit 8d43bdb084
3 changed files with 97 additions and 99 deletions

View File

@ -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<EmojiBlock>(_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<NewlineBlock>(_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<TextBlock>(_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<SkipBlock>(_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<int> visualOrder(nItems);
QVarLengthArray<uchar> 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<Text*>(_t)->_blocks[blockIndex] = new TextBlock(_t->_st->font, _t->_text, QFIXED_MAX, elideStart, 0, _elideSavedBlock->flags(), _elideSavedBlock->lnkIndex());
auto mutableText = const_cast<Text*>(_t);
_elideSavedBlock = std::move(mutableText->_blocks[blockIndex]);
mutableText->_blocks[blockIndex] = std::make_unique<TextBlock>(_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<Text*>(_t)->_blocks[_elideSavedIndex] = _elideSavedBlock;
_elideSavedBlock = nullptr;
const_cast<Text*>(_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<const ushort*>(_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<uchar> 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<ITextBlock> _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<SkipBlock*>(_blocks.back());
if (!_blocks.empty() && _blocks.back()->type() == TextBlockTSkip) {
auto block = static_cast<SkipBlock*>(_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<SkipBlock>(_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<TextBlock*>(b);
auto t = static_cast<TextBlock*>(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));

View File

@ -199,12 +199,10 @@ public:
}
void clear();
~Text() {
clear();
}
~Text();
private:
using TextBlocks = QVector<ITextBlock*>;
using TextBlocks = std::vector<std::unique_ptr<ITextBlock>>;
using TextLinks = QVector<ClickHandlerPtr>;
uint16 countBlockEnd(const TextBlocks::const_iterator &i, const TextBlocks::const_iterator &e) const;

View File

@ -77,7 +77,7 @@ public:
return (_flags & 0xFF);
}
virtual ITextBlock *clone() const = 0;
virtual std::unique_ptr<ITextBlock> 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<ITextBlock> clone() const override {
return std::make_unique<NewlineBlock>(*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<ITextBlock> clone() const override {
return std::make_unique<TextBlock>(*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<ITextBlock> clone() const {
return std::make_unique<EmojiBlock>(*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<ITextBlock> clone() const override {
return std::make_unique<SkipBlock>(*this);
}
private:
SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex);
int32 _height;
friend class Text;