diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index f8cafc0c9..2d3a1539c 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2428,6 +2428,7 @@ namespace App { } void regGifItem(ClipReader *reader, HistoryItem *item) { + stopGifItems(); ::gifItems.insert(reader, item); } @@ -2439,6 +2440,16 @@ namespace App { return ::gifItems; } + void stopGifItems() { + while (!::gifItems.isEmpty()) { + if (HistoryItem *playing = ::gifItems.begin().value()) { + if (playing->getMedia() && playing->getMedia()->type() == MediaTypeGif) { + static_cast(playing->getMedia())->stop(playing); + } + } + } + } + QString phoneFromSharedContact(int32 userId) { SharedContactItems::const_iterator i = ::sharedContactItems.constFind(userId); if (i != ::sharedContactItems.cend()) { diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 465c2fa7c..d77bfd846 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -254,6 +254,7 @@ namespace App { void regGifItem(ClipReader *reader, HistoryItem *item); void unregGifItem(ClipReader *reader); const GifItems &gifItems(); + void stopGifItems(); void regMuted(PeerData *peer, int32 changeIn); void unregMuted(PeerData *peer); diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 3888f20d6..9f7ae7e16 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -84,6 +84,7 @@ enum { AnimationTimerDelta = 7, ClipThreadsCount = 8, + AverageGifSize = 320 * 240, SaveRecentEmojisTimeout = 3000, // 3 secs SaveWindowPositionTimeout = 1000, // 1 sec diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp index 2fe92a5fb..700af5991 100644 --- a/Telegram/SourceFiles/gui/animation.cpp +++ b/Telegram/SourceFiles/gui/animation.cpp @@ -124,6 +124,8 @@ void AnimationManager::clipReinit(ClipReader *reader) { if (it != items.cend()) { it.value()->initDimensions(); if (App::main()) emit App::main()->itemResized(it.value(), true); + + Notify::historyItemLayoutChanged(it.value()); } } @@ -359,8 +361,9 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b _clipManagers.at(_threadIndex)->start(this); } -QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh) { +QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) { _currentDisplayed.storeRelease(1); + _lastDisplayMs = ms; int32 factor(cIntRetinaFactor()); QPixmap result(_current); @@ -491,7 +494,8 @@ public: } uint64 nextFrameDelay() { - return qMax(_reader->nextImageDelay(), 5); + int delay = _reader->nextImageDelay(); + return qMax(delay, 5); } void swapBuffers(uint64 ms = 0) { @@ -636,6 +640,7 @@ ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0) { void ClipReadManager::append(ClipReader *reader, const FileLocation &location, const QByteArray &data) { reader->_private = new ClipReaderPrivate(reader, location, data); + _loadLevel.fetchAndAddRelease(AverageGifSize); update(reader); } @@ -669,6 +674,9 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess return false; } + if (result == ClipProcessStarted) { + _loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize); + } if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) { it.key()->_current = reader->_current; it.key()->_currentOriginal = reader->_currentOriginal; @@ -684,6 +692,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) { if (!handleProcessResult(reader, result)) { + _loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height())); delete reader; return ResultHandleRemove; } diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h index d2c9b4e5f..bbe1f2396 100644 --- a/Telegram/SourceFiles/gui/animation.h +++ b/Telegram/SourceFiles/gui/animation.h @@ -500,7 +500,7 @@ public: ClipReader(const FileLocation &location, const QByteArray &data); void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded); - QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh); + QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms); bool currentDisplayed() const { return _currentDisplayed.loadAcquire() > 0; } @@ -530,6 +530,7 @@ private: QPixmap _current; QImage _currentOriginal, _cacheForResize; QAtomicInt _currentDisplayed; + uint64 _lastDisplayMs; int32 _threadIndex; friend class ClipReadManager; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 3982977e4..c586e8c0e 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -152,30 +152,6 @@ void historyInit() { _initTextOptions(); } -void startGif(HistoryItem *row, const FileLocation &file) { - if (row == animated.msg) { - stopGif(); - } else { - animated.start(row, file); - } -} - -void itemReplacedGif(HistoryItem *oldItem, HistoryItem *newItem) { - if (oldItem == animated.msg) { - animated.msg = newItem; - } -} - -void itemRemovedGif(HistoryItem *item) { - if (item == animated.msg) { - animated.stop(true); - } -} - -void stopGif() { - animated.stop(); -} - void DialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const { QRect fullRect(0, 0, w, st::dlgHeight); p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b); @@ -4571,7 +4547,7 @@ HistoryGif::HistoryGif(DocumentData *document) : HistoryFileMedia() , _thumbw(1) , _thumbh(1) , _gif(0) { - setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data)); + setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data)); setStatusSize(FileStatusSizeReady); @@ -4651,7 +4627,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo QRect rthumb(rtlrect(skipx, skipy, width, height, w)); if (animating) { - p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height)); + p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, ms)); } else { p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height)); } @@ -4876,9 +4852,9 @@ void HistoryGif::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, } if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (_gif && _gif->started()) { - lnk = _openl; + lnk = _savel; } else { - lnk = _data->already().isEmpty() ? (_data->loader ? _cancell : _savel) : _openl; + lnk = _data->already().isEmpty() ? (_data->loader ? _cancell : _savel) : _savel; } int32 fullRight = skipx + width, fullBottom = skipy + height; @@ -4900,15 +4876,23 @@ ImagePtr HistoryGif::replyPreview() { void HistoryGif::play(HistoryItem *parent) { if (_gif) { - App::unregGifItem(_gif); - delete _gif; - _gif = 0; + stop(parent); } else { _gif = new ClipReader(_data->location(), _data->data); App::regGifItem(_gif, parent); } } +void HistoryGif::stop(HistoryItem *parent) { + App::unregGifItem(_gif); + delete _gif; + _gif = 0; + + parent->initDimensions(); + if (App::main()) emit App::main()->itemResized(parent); + Notify::historyItemLayoutChanged(parent); +} + HistoryGif::~HistoryGif() { if (_gif) { App::unregGifItem(_gif); @@ -6666,7 +6650,7 @@ void HistoryMessage::initMediaFromText(QString ¤tText) { void HistoryMessage::initMediaFromDocument(DocumentData *doc) { if (doc->sticker()) { _media = new HistorySticker(doc); - } else if (doc->type == AnimatedDocument) { + } else if (doc->type == AnimatedDocument || doc->mime.toLower() == qstr("image/gif")) { _media = new HistoryGif(doc); } else { _media = new HistoryDocument(doc); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index c4f6a0aae..21f309fb2 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -24,11 +24,6 @@ void historyInit(); class HistoryItem; -void startGif(HistoryItem *row, const FileLocation &file); -void itemRemovedGif(HistoryItem *item); -void itemReplacedGif(HistoryItem *oldItem, HistoryItem *newItem); -void stopGif(); - static const uint32 FullItemSel = 0xFFFFFFFF; typedef QMap SelectedItemSet; @@ -1606,6 +1601,8 @@ public: } void play(HistoryItem *parent); + void stop(HistoryItem *parent); + ~HistoryGif(); protected: diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 7a637791d..7ff7ac6a8 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3225,7 +3225,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re } } - stopGif(); + App::stopGifItems(); clearReplyReturns(); clearAllLoadRequests(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index a67beecb7..25b89a349 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1454,7 +1454,6 @@ void MainWidget::itemRemoved(HistoryItem *item) { if (overview && (overview->peer() == item->history()->peer || (overview->peer() && overview->peer() == item->history()->peer->migrateTo()))) { overview->itemRemoved(item); } - itemRemovedGif(item); if (!_toForward.isEmpty()) { SelectedItemSet::iterator i = _toForward.find(item->id); if (i != _toForward.cend() && i.value() == item) { @@ -1476,7 +1475,6 @@ void MainWidget::itemReplaced(HistoryItem *oldItem, HistoryItem *newItem) { if (history.peer() == newItem->history()->peer || (history.peer() && history.peer() == newItem->history()->peer->migrateTo())) { history.itemReplaced(oldItem, newItem); } - itemReplacedGif(oldItem, newItem); if (!_toForward.isEmpty()) { SelectedItemSet::iterator i = _toForward.find(oldItem->id); if (i != _toForward.cend() && i.value() == oldItem) { diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index b2b454d7a..6336a2520 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -2906,7 +2906,7 @@ int32 OverviewWidget::countBestScroll() const { } void OverviewWidget::fastShow(bool back, int32 lastScrollTop) { - stopGif(); + App::stopGifItems(); resizeEvent(0); _scrollSetAfterShow = (lastScrollTop < 0 ? countBestScroll() : lastScrollTop); show(); @@ -2919,7 +2919,7 @@ void OverviewWidget::fastShow(bool back, int32 lastScrollTop) { void OverviewWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) { if (App::app()) App::app()->mtpPause(); - stopGif(); + App::stopGifItems(); (back ? _cacheOver : _cacheUnder) = bgAnimCache; (back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache; diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 47424ee92..c1f177a94 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -1832,7 +1832,7 @@ int32 ProfileWidget::lastScrollTop() const { void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) { if (App::app()) App::app()->mtpPause(); - stopGif(); + App::stopGifItems(); (back ? _cacheOver : _cacheUnder) = bgAnimCache; (back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache;