diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index 5cb96d971..a6816c6c3 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -1522,10 +1522,7 @@ ImagePtr HistoryDocument::replyPreview() { HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent) , _data(document) -, _thumbw(1) -, _thumbh(1) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) -, _gif(nullptr) { +, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { setDocumentLinks(_data, true); setStatusSize(FileStatusSizeReady); @@ -1541,8 +1538,7 @@ HistoryGif::HistoryGif(HistoryItem *parent, const HistoryGif &other) : HistoryFi , _data(other._data) , _thumbw(other._thumbw) , _thumbh(other._thumbh) -, _caption(other._caption) -, _gif(nullptr) { +, _caption(other._caption) { setDocumentLinks(_data, true); setStatusSize(other._statusSize); @@ -1555,16 +1551,15 @@ void HistoryGif::initDimensions() { bool bubble = _parent->hasBubble(); int32 tw = 0, th = 0; - if (gif() && _gif->state() == Media::Clip::State::Error) { + if (_gif && _gif->state() == Media::Clip::State::Error) { if (!_gif->autoplay()) { Ui::showLayer(new InformBox(lang(lng_gif_error))); } - App::unregGifItem(_gif); - delete _gif; - _gif = Media::Clip::BadReader; + App::unregGifItem(_gif.get()); + _gif.setBad(); } - if (gif() && _gif->ready()) { + if (_gif && _gif->ready()) { tw = convertScale(_gif->width()); th = convertScale(_gif->height()); } else { @@ -1590,7 +1585,7 @@ void HistoryGif::initDimensions() { _maxw = qMax(tw, int32(st::minPhotoSize)); _minh = qMax(th, int32(st::minPhotoSize)); _maxw = qMax(_maxw, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - if (!gif() || !_gif->ready()) { + if (!_gif || !_gif->ready()) { _maxw = qMax(_maxw, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); } if (bubble) { @@ -1610,7 +1605,7 @@ int HistoryGif::resizeGetHeight(int width) { bool bubble = _parent->hasBubble(); int tw = 0, th = 0; - if (gif() && _gif->ready()) { + if (_gif && _gif->ready()) { tw = convertScale(_gif->width()); th = convertScale(_gif->height()); } else { @@ -1645,7 +1640,7 @@ int HistoryGif::resizeGetHeight(int width) { _width = qMax(tw, int32(st::minPhotoSize)); _height = qMax(th, int32(st::minPhotoSize)); _width = qMax(_width, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - if (gif() && _gif->ready()) { + if (_gif && _gif->ready()) { if (!_gif->started()) { auto inWebPage = (_parent->getMedia() != this); auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; @@ -1676,7 +1671,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6 bool loaded = _data->loaded(), displayLoading = (_parent->id < 0) || _data->displayLoading(); bool selected = (selection == FullSelection); - if (loaded && !gif() && _gif != Media::Clip::BadReader && cAutoPlayGif()) { + if (loaded && !_gif && !_gif.isBad() && cAutoPlayGif()) { Ui::autoplayMediaInlineAsync(_parent->fullId()); } @@ -1686,7 +1681,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6 int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); - bool animating = (gif() && _gif->started()); + bool animating = (_gif && _gif->started()); if (!animating || _parent->id < 0) { if (displayLoading) { @@ -1730,7 +1725,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6 App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners); } - if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == Media::Clip::BadReader)) { + if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) { float64 radialOpacity = (radial && loaded && _parent->id > 0) ? _animation->radial.opacity() : 1; QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); @@ -1818,7 +1813,7 @@ HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request) if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (_data->uploading()) { result.link = _cancell; - } else if (!gif() || !cAutoPlayGif()) { + } else if (!_gif || !cAutoPlayGif()) { result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); } if (_parent->getMedia() == this) { @@ -1891,36 +1886,34 @@ ImagePtr HistoryGif::replyPreview() { } bool HistoryGif::playInline(bool autoplay) { - if (gif()) { + if (_gif) { stopInline(); } else if (_data->loaded(DocumentData::FilePathResolveChecked)) { if (!cAutoPlayGif()) { App::stopGifItems(); } - _gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) { + _gif = Media::Clip::MakeReader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) { _parent->clipCallback(notification); }); - App::regGifItem(_gif, _parent); - if (gif()) _gif->setAutoplay(); + App::regGifItem(_gif.get(), _parent); + if (_gif) _gif->setAutoplay(); } return true; } void HistoryGif::stopInline() { - if (gif()) { - App::unregGifItem(_gif); - delete _gif; - _gif = 0; + if (_gif) { + App::unregGifItem(_gif.get()); } + _gif.reset(); _parent->setPendingInitDimensions(); Notify::historyItemLayoutChanged(_parent); } HistoryGif::~HistoryGif() { - if (gif()) { - App::unregGifItem(_gif); - deleteAndMark(_gif); + if (_gif) { + App::unregGifItem(_gif.get()); } } @@ -3071,7 +3064,7 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint p.fillRect(bar, barfg); if (_titleLines) { - p.setPen(st::black); + p.setPen(semibold); int32 endskip = 0; if (_title.hasSkipBlock()) { endskip = _parent->skipBlockWidth(); diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index fe62bcb08..1dec2c746 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -446,7 +446,7 @@ public: return _data; } Media::Clip::Reader *getClipReader() override { - return gif(); + return _gif.get(); } bool playInline(bool autoplay) override; @@ -491,16 +491,11 @@ protected: private: DocumentData *_data; - int32 _thumbw, _thumbh; + int32 _thumbw = 1; + int32 _thumbh = 1; Text _caption; - Media::Clip::Reader *_gif; - Media::Clip::Reader *gif() { - return (_gif == Media::Clip::BadReader) ? nullptr : _gif; - } - const Media::Clip::Reader *gif() const { - return (_gif == Media::Clip::BadReader) ? nullptr : _gif; - } + Media::Clip::ReaderPointer _gif; void setStatusSize(int32 newSize) const; void updateStatusText() const; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index fac4a6cff..f3ed03cf1 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -112,8 +112,7 @@ void Gif::initDimensions() { void Gif::setPosition(int32 position) { ItemBase::setPosition(position); if (_position < 0) { - if (gif()) delete _gif; - _gif = 0; + _gif.reset(); } } @@ -133,15 +132,15 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons document->automaticLoad(nullptr); bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); - if (loaded && !gif() && _gif != Media::Clip::BadReader) { + if (loaded && !_gif && !_gif.isBad()) { auto that = const_cast(this); - that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(document->location(), document->data(), [that](Media::Clip::Notification notification) { that->clipCallback(notification); }); - if (gif()) _gif->setAutoplay(); + if (_gif) _gif->setAutoplay(); } - bool animating = (gif() && _gif->started()); + bool animating = (_gif && _gif->started()); if (displayLoading) { ensureAnimation(); if (!_animation->radial.animating()) { @@ -166,7 +165,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons } } - if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) { + if (radial || _gif.isBad() || (!_gif && !loaded && !loading)) { auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.; if (_animation && _animation->_a_over.animating(context->ms)) { auto over = _animation->_a_over.current(); @@ -248,7 +247,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { } QSize Gif::countFrameSize() const { - bool animating = (gif() && _gif->ready()); + bool animating = (_gif && _gif->ready()); int32 framew = animating ? _gif->width() : content_width(), frameh = animating ? _gif->height() : content_height(), height = st::inlineMediaHeight; if (framew * height > frameh * _width) { if (framew < st::maxStickerSize || frameh > height) { @@ -274,10 +273,6 @@ QSize Gif::countFrameSize() const { return QSize(framew, frameh); } -Gif::~Gif() { - if (gif()) deleteAndMark(_gif); -} - void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const { if (DocumentData *document = getShownDocument()) { if (!document->thumb->isNull()) { @@ -332,18 +327,16 @@ void Gif::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { case NotificationReinit: { - if (gif()) { + if (_gif) { if (_gif->state() == State::Error) { - delete _gif; - _gif = BadReader; + _gif.setBad(); getShownDocument()->forget(); } else if (_gif->ready() && !_gif->started()) { int32 height = st::inlineMediaHeight; QSize frame = countFrameSize(); _gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None); } else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) { - delete _gif; - _gif = nullptr; + _gif.reset(); getShownDocument()->forget(); } } @@ -352,7 +345,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) { } break; case NotificationRepaint: { - if (gif() && !_gif->currentDisplayed()) { + if (_gif && !_gif->currentDisplayed()) { update(); } } break; @@ -1193,8 +1186,7 @@ void Game::initDimensions() { void Game::setPosition(int32 position) { ItemBase::setPosition(position); if (_position < 0) { - if (gif()) delete _gif; - _gif = 0; + _gif.reset(); } } @@ -1212,15 +1204,15 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con document->automaticLoad(nullptr); bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); - if (loaded && !gif() && _gif != Media::Clip::BadReader) { + if (loaded && !_gif && !_gif.isBad()) { auto that = const_cast(this); - that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(document->location(), document->data(), [that](Media::Clip::Notification notification) { that->clipCallback(notification); }); - if (gif()) _gif->setAutoplay(); + if (_gif) _gif->setAutoplay(); } - bool animating = (gif() && _gif->started()); + bool animating = (_gif && _gif->started()); if (displayLoading) { if (!_radial) { _radial = std_::make_unique(animation(const_cast(this), &Game::step_radial)); @@ -1342,16 +1334,14 @@ void Game::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { case NotificationReinit: { - if (gif()) { + if (_gif) { if (_gif->state() == State::Error) { - delete _gif; - _gif = BadReader; + _gif.setBad(); getResultDocument()->forget(); } else if (_gif->ready() && !_gif->started()) { _gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None); } else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) { - delete _gif; - _gif = nullptr; + _gif.reset(); getResultDocument()->forget(); } } @@ -1360,17 +1350,13 @@ void Game::clipCallback(Media::Clip::Notification notification) { } break; case NotificationRepaint: { - if (gif() && !_gif->currentDisplayed()) { + if (_gif && !_gif->currentDisplayed()) { update(); } } break; } } -Game::~Game() { - if (gif()) deleteAndMark(_gif); -} - } // namespace internal } // namespace Layout } // namespace InlineBots diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index d9327d9d5..4ea9093b0 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -77,10 +77,7 @@ public: // ClickHandlerHost interface void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; - ~Gif(); - private: - QSize countFrameSize() const; enum class StateFlag { @@ -93,11 +90,8 @@ private: return ~StateFlags(flag); } - Media::Clip::Reader *_gif = nullptr; + Media::Clip::ReaderPointer _gif; ClickHandlerPtr _delete; - bool gif() const { - return (!_gif || _gif == Media::Clip::BadReader) ? false : true; - } mutable QPixmap _thumb; void prepareThumb(int32 width, int32 height, const QSize &frame) const; @@ -349,14 +343,9 @@ public: void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; - ~Game(); - private: void countFrameSize(); - bool gif() const { - return (!_gif || _gif == Media::Clip::BadReader) ? false : true; - } void prepareThumb(int32 width, int32 height) const; bool isRadialAnimation(uint64 ms) const; @@ -364,7 +353,7 @@ private: void clipCallback(Media::Clip::Notification notification); - Media::Clip::Reader *_gif = nullptr; + Media::Clip::ReaderPointer _gif; mutable QPixmap _thumb; mutable std_::unique_ptr _radial; Text _title, _description; diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index fb5374dd3..16382fe1c 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -567,12 +567,7 @@ void MediaPreviewWidget::fillEmojiString() { } void MediaPreviewWidget::resetGifAndCache() { - if (_gif) { - if (gif()) { - delete _gif; - } - _gif = nullptr; - } + _gif.reset(); _cacheStatus = CacheNotLoaded; _cachedSize = QSize(); } @@ -592,7 +587,7 @@ QSize MediaPreviewWidget::currentDimensions() const { box = QSize(width() - 2 * st::boxVerticalMargin, height() - 2 * st::boxVerticalMargin); } else { result = _document->dimensions; - if (gif() && _gif->ready()) { + if (_gif && _gif->ready()) { result = QSize(_gif->width(), _gif->height()); } if (_document->sticker()) { @@ -636,15 +631,15 @@ QPixmap MediaPreviewWidget::currentImage() const { } else { _document->automaticLoad(nullptr); if (_document->loaded()) { - if (!_gif && _gif != Media::Clip::BadReader) { + if (!_gif && !_gif.isBad()) { auto that = const_cast(this); - that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) { that->clipCallback(notification); }); - if (gif()) _gif->setAutoplay(); + if (_gif) _gif->setAutoplay(); } } - if (gif() && _gif->started()) { + if (_gif && _gif->started()) { QSize s = currentDimensions(); return _gif->current(s.width(), s.height(), s.width(), s.height(), getms()); } @@ -681,12 +676,11 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) { using namespace Media::Clip; switch (notification) { case NotificationReinit: { - if (gif() && _gif->state() == State::Error) { - delete _gif; - _gif = BadReader; + if (_gif && _gif->state() == State::Error) { + _gif.setBad(); } - if (gif() && _gif->ready() && !_gif->started()) { + if (_gif && _gif->ready() && !_gif->started()) { QSize s = currentDimensions(); _gif->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None); } @@ -695,7 +689,7 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) { } break; case NotificationRepaint: { - if (gif() && !_gif->currentDisplayed()) { + if (_gif && !_gif->currentDisplayed()) { update(); } } break; diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index 3161e0043..ff6a668e6 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -157,10 +157,7 @@ private: Animation _a_shown; DocumentData *_document = nullptr; PhotoData *_photo = nullptr; - Media::Clip::Reader *_gif = nullptr; - bool gif() const { - return (!_gif || _gif == Media::Clip::BadReader) ? false : true; - } + Media::Clip::ReaderPointer _gif; int _emojiSize; QList _emojiList; diff --git a/Telegram/SourceFiles/ui/animation.cpp b/Telegram/SourceFiles/ui/animation.cpp index 83e3bc729..0fd8b7995 100644 --- a/Telegram/SourceFiles/ui/animation.cpp +++ b/Telegram/SourceFiles/ui/animation.cpp @@ -23,6 +23,26 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "media/media_clip_reader.h" +namespace Media { +namespace Clip { + +Reader *const ReaderPointer::BadPointer = SharedMemoryLocation(); + +ReaderPointer::~ReaderPointer() { + if (valid()) { + delete _pointer; + } + _pointer = nullptr; +} + +class Tmp; +void f(Tmp *t) { + delete t; +} + +} // namespace Clip +} // namespace Media + namespace { AnimationManager *_manager = nullptr; diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 4130012c6..dc9e7b83a 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -29,7 +29,58 @@ namespace Media { namespace Clip { class Reader; -static Reader * const BadReader = SharedMemoryLocation(); +class ReaderPointer { +public: + ReaderPointer(std::nullptr_t = nullptr) { + } + explicit ReaderPointer(Reader *pointer) : _pointer(pointer) { + } + ReaderPointer(const ReaderPointer &other) = delete; + ReaderPointer &operator=(const ReaderPointer &other) = delete; + ReaderPointer(ReaderPointer &&other) : _pointer(createAndSwap(other._pointer)) { + } + ReaderPointer &operator=(ReaderPointer &&other) { + swap(other); + return *this; + } + void swap(ReaderPointer &other) { + qSwap(_pointer, other._pointer); + } + Reader *get() const { + return valid() ? _pointer : nullptr; + } + Reader *operator->() const { + return get(); + } + void setBad() { + reset(); + _pointer = BadPointer; + } + void reset() { + ReaderPointer temp; + swap(temp); + } + bool isBad() const { + return (_pointer == BadPointer); + } + bool valid() const { + return _pointer && !isBad(); + } + explicit operator bool() const { + return valid(); + } + ~ReaderPointer(); + +private: + Reader *_pointer = nullptr; + static Reader *const BadPointer; + +}; + +template +inline ReaderPointer MakeReader(Args&&... args) { + return ReaderPointer(new Reader(std_::forward(args)...)); +} class Manager;