pausing gifs that are not currently displayed
This commit is contained in:
		
							parent
							
								
									322eef660e
								
							
						
					
					
						commit
						fdb93f700d
					
				
					 4 changed files with 75 additions and 18 deletions
				
			
		| 
						 | 
					@ -2441,7 +2441,7 @@ namespace App {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void stopGifItems() {
 | 
						void stopGifItems() {
 | 
				
			||||||
		while (!::gifItems.isEmpty()) {
 | 
							if (!::gifItems.isEmpty()) {
 | 
				
			||||||
			if (HistoryItem *playing = ::gifItems.begin().value()) {
 | 
								if (HistoryItem *playing = ::gifItems.begin().value()) {
 | 
				
			||||||
				if (playing->getMedia() && playing->getMedia()->type() == MediaTypeGif) {
 | 
									if (playing->getMedia() && playing->getMedia()->type() == MediaTypeGif) {
 | 
				
			||||||
					static_cast<HistoryGif*>(playing->getMedia())->stop(playing);
 | 
										static_cast<HistoryGif*>(playing->getMedia())->stop(playing);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,8 +83,9 @@ enum {
 | 
				
			||||||
	LocalEncryptKeySize = 256, // 2048 bit
 | 
						LocalEncryptKeySize = 256, // 2048 bit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AnimationTimerDelta = 7,
 | 
						AnimationTimerDelta = 7,
 | 
				
			||||||
	ClipThreadsCount = 8,
 | 
						ClipThreadsCount = 4,
 | 
				
			||||||
	AverageGifSize = 320 * 240,
 | 
						AverageGifSize = 320 * 240,
 | 
				
			||||||
 | 
						WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SaveRecentEmojisTimeout = 3000, // 3 secs
 | 
						SaveRecentEmojisTimeout = 3000, // 3 secs
 | 
				
			||||||
	SaveWindowPositionTimeout = 1000, // 1 sec
 | 
						SaveWindowPositionTimeout = 1000, // 1 sec
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -330,6 +330,8 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data) : _
 | 
				
			||||||
, _width(0)
 | 
					, _width(0)
 | 
				
			||||||
, _height(0)
 | 
					, _height(0)
 | 
				
			||||||
, _currentDisplayed(1)
 | 
					, _currentDisplayed(1)
 | 
				
			||||||
 | 
					, _paused(0)
 | 
				
			||||||
 | 
					, _lastDisplayMs(getms())
 | 
				
			||||||
, _private(0) {
 | 
					, _private(0) {
 | 
				
			||||||
	if (_clipThreads.size() < ClipThreadsCount) {
 | 
						if (_clipThreads.size() < ClipThreadsCount) {
 | 
				
			||||||
		_threadIndex = _clipThreads.size();
 | 
							_threadIndex = _clipThreads.size();
 | 
				
			||||||
| 
						 | 
					@ -365,8 +367,15 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) {
 | 
					QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) {
 | 
				
			||||||
	_currentDisplayed.storeRelease(1);
 | 
						_lastDisplayMs.set(ms);
 | 
				
			||||||
	_lastDisplayMs = ms;
 | 
						_currentDisplayed.set(true);
 | 
				
			||||||
 | 
						if (_paused.get()) {
 | 
				
			||||||
 | 
							_paused.set(false);
 | 
				
			||||||
 | 
							if (_clipManagers.size() <= _threadIndex) error();
 | 
				
			||||||
 | 
							if (_state != ClipError) {
 | 
				
			||||||
 | 
								_clipManagers.at(_threadIndex)->update(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 factor(cIntRetinaFactor());
 | 
						int32 factor(cIntRetinaFactor());
 | 
				
			||||||
	QPixmap result(_current);
 | 
						QPixmap result(_current);
 | 
				
			||||||
| 
						 | 
					@ -441,8 +450,10 @@ public:
 | 
				
			||||||
	, _accessed(false)
 | 
						, _accessed(false)
 | 
				
			||||||
	, _buffer(_data.isEmpty() ? 0 : &_data)
 | 
						, _buffer(_data.isEmpty() ? 0 : &_data)
 | 
				
			||||||
	, _reader(0)
 | 
						, _reader(0)
 | 
				
			||||||
 | 
						, _previousMs(0)
 | 
				
			||||||
	, _currentMs(0)
 | 
						, _currentMs(0)
 | 
				
			||||||
	, _nextUpdateMs(0) {
 | 
						, _nextUpdateMs(0)
 | 
				
			||||||
 | 
						, _paused(false) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (_data.isEmpty() && !_location->accessEnable()) {
 | 
							if (_data.isEmpty() && !_location->accessEnable()) {
 | 
				
			||||||
			error();
 | 
								error();
 | 
				
			||||||
| 
						 | 
					@ -476,6 +487,7 @@ public:
 | 
				
			||||||
		if (_current.isNull()) { // first frame read, but not yet prepared
 | 
							if (_current.isNull()) { // first frame read, but not yet prepared
 | 
				
			||||||
			_currentOriginal.setDevicePixelRatio(_request.factor);
 | 
								_currentOriginal.setDevicePixelRatio(_request.factor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_previousMs = _currentMs;
 | 
				
			||||||
			_currentMs = ms;
 | 
								_currentMs = ms;
 | 
				
			||||||
			_current = _prepareFrame(_request, _currentOriginal, _currentCache, true);
 | 
								_current = _prepareFrame(_request, _currentOriginal, _currentCache, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -483,7 +495,7 @@ public:
 | 
				
			||||||
				return error();
 | 
									return error();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return ClipProcessStarted;
 | 
								return ClipProcessStarted;
 | 
				
			||||||
		} else if (ms >= _nextUpdateMs) {
 | 
							} else if (!_paused && ms >= _nextUpdateMs) {
 | 
				
			||||||
			swapBuffers();
 | 
								swapBuffers();
 | 
				
			||||||
			return ClipProcessRedraw;
 | 
								return ClipProcessRedraw;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -508,6 +520,7 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void swapBuffers(uint64 ms = 0) {
 | 
						void swapBuffers(uint64 ms = 0) {
 | 
				
			||||||
 | 
							_previousMs = _currentMs;
 | 
				
			||||||
		_currentMs = qMax(ms, _nextUpdateMs);
 | 
							_currentMs = qMax(ms, _nextUpdateMs);
 | 
				
			||||||
		qSwap(_currentOriginal, _nextOriginal);
 | 
							qSwap(_currentOriginal, _nextOriginal);
 | 
				
			||||||
		qSwap(_current, _next);
 | 
							qSwap(_current, _next);
 | 
				
			||||||
| 
						 | 
					@ -628,13 +641,15 @@ private:
 | 
				
			||||||
	QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache;
 | 
						QImage _currentOriginal, _nextOriginal, _currentCache, _nextCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 _framesLeft;
 | 
						int32 _framesLeft;
 | 
				
			||||||
	uint64 _currentMs, _nextUpdateMs;
 | 
						uint64 _previousMs, _currentMs, _nextUpdateMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _paused;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	friend class ClipReadManager;
 | 
						friend class ClipReadManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0) {
 | 
					ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0), _needReProcess(false) {
 | 
				
			||||||
	moveToThread(thread);
 | 
						moveToThread(thread);
 | 
				
			||||||
	connect(thread, SIGNAL(started()), this, SLOT(process()));
 | 
						connect(thread, SIGNAL(started()), this, SLOT(process()));
 | 
				
			||||||
	connect(this, SIGNAL(processDelayed()), this, SLOT(process()), Qt::QueuedConnection);
 | 
						connect(this, SIGNAL(processDelayed()), this, SLOT(process()), Qt::QueuedConnection);
 | 
				
			||||||
| 
						 | 
					@ -669,7 +684,7 @@ void ClipReadManager::stop(ClipReader *reader) {
 | 
				
			||||||
	emit processDelayed();
 | 
						emit processDelayed();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result) {
 | 
					bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
 | 
				
			||||||
	QMutexLocker lock(&_readerPointersMutex);
 | 
						QMutexLocker lock(&_readerPointersMutex);
 | 
				
			||||||
	ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
 | 
						ReaderPointers::iterator it = _readerPointers.find(reader->_interface);
 | 
				
			||||||
	if (result == ClipProcessError) {
 | 
						if (result == ClipProcessError) {
 | 
				
			||||||
| 
						 | 
					@ -686,10 +701,20 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
 | 
				
			||||||
	if (result == ClipProcessStarted) {
 | 
						if (result == ClipProcessStarted) {
 | 
				
			||||||
		_loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize);
 | 
							_loadLevel.fetchAndAddRelease(reader->_currentOriginal.width() * reader->_currentOriginal.height() - AverageGifSize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!reader->_paused && (result == ClipProcessRedraw || result == ClipProcessWait)) {
 | 
				
			||||||
 | 
							if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
 | 
				
			||||||
 | 
								reader->_paused = true;
 | 
				
			||||||
 | 
								it.key()->_paused.set(true);
 | 
				
			||||||
 | 
								if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause >= qMax(reader->_previousMs, ms)) {
 | 
				
			||||||
 | 
									it.key()->_paused.set(false);
 | 
				
			||||||
 | 
									reader->_paused = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) {
 | 
						if (result == ClipProcessReinit || result == ClipProcessRedraw || result == ClipProcessStarted) {
 | 
				
			||||||
		it.key()->_current = reader->_current;
 | 
							it.key()->_current = reader->_current;
 | 
				
			||||||
		it.key()->_currentOriginal = reader->_currentOriginal;
 | 
							it.key()->_currentOriginal = reader->_currentOriginal;
 | 
				
			||||||
		it.key()->_currentDisplayed.storeRelease(0);
 | 
							it.key()->_currentDisplayed.set(false);
 | 
				
			||||||
		if (result == ClipProcessReinit) {
 | 
							if (result == ClipProcessReinit) {
 | 
				
			||||||
			emit reinit(it.key());
 | 
								emit reinit(it.key());
 | 
				
			||||||
		} else if (result == ClipProcessRedraw) {
 | 
							} else if (result == ClipProcessRedraw) {
 | 
				
			||||||
| 
						 | 
					@ -700,7 +725,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
 | 
					ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
 | 
				
			||||||
	if (!handleProcessResult(reader, result)) {
 | 
						if (!handleProcessResult(reader, result, ms)) {
 | 
				
			||||||
		_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height()));
 | 
							_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_currentOriginal.width() * reader->_currentOriginal.height()));
 | 
				
			||||||
		delete reader;
 | 
							delete reader;
 | 
				
			||||||
		return ResultHandleRemove;
 | 
							return ResultHandleRemove;
 | 
				
			||||||
| 
						 | 
					@ -719,7 +744,10 @@ ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPriva
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClipReadManager::process() {
 | 
					void ClipReadManager::process() {
 | 
				
			||||||
	if (_processingInThread) return;
 | 
						if (_processingInThread) {
 | 
				
			||||||
 | 
							_needReProcess = true;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_timer.stop();
 | 
						_timer.stop();
 | 
				
			||||||
	_processingInThread = thread();
 | 
						_processingInThread = thread();
 | 
				
			||||||
| 
						 | 
					@ -734,6 +762,9 @@ void ClipReadManager::process() {
 | 
				
			||||||
					_readers.insert(i.value(), 0);
 | 
										_readers.insert(i.value(), 0);
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					it.value() = ms;
 | 
										it.value() = ms;
 | 
				
			||||||
 | 
										if (it.key()->_paused && !i.key()->_paused.get()) {
 | 
				
			||||||
 | 
											it.key()->_paused = false;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				i.value()->_request = i.key()->_request;
 | 
									i.value()->_request = i.key()->_request;
 | 
				
			||||||
				i.value() = 0;
 | 
									i.value() = 0;
 | 
				
			||||||
| 
						 | 
					@ -754,15 +785,17 @@ void ClipReadManager::process() {
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			i.value() = i.key()->_nextUpdateMs;
 | 
								i.value() = i.key()->_nextUpdateMs;
 | 
				
			||||||
 | 
								ms = getms();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (i.value() < minms) {
 | 
							if (!i.key()->_paused && i.value() < minms) {
 | 
				
			||||||
			minms = i.value();
 | 
								minms = i.value();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		++i;
 | 
							++i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms = getms();
 | 
						ms = getms();
 | 
				
			||||||
	if (minms <= ms) {
 | 
						if (_needReProcess || minms <= ms) {
 | 
				
			||||||
 | 
							_needReProcess = false;
 | 
				
			||||||
		_timer.start(1);
 | 
							_timer.start(1);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		_timer.start(minms - ms);
 | 
							_timer.start(minms - ms);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -493,6 +493,28 @@ struct ClipFrameRequest {
 | 
				
			||||||
	bool rounded;
 | 
						bool rounded;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Type>
 | 
				
			||||||
 | 
					class Atomic {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Atomic(const Type &value = Type()) : _v(1, value) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Type get() const {
 | 
				
			||||||
 | 
							QVector<Type> v(_v);
 | 
				
			||||||
 | 
							return v.at(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void set(const Type &value) {
 | 
				
			||||||
 | 
							QVector<Type> v(1, value);
 | 
				
			||||||
 | 
							_v = v;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QVector<Type> _v;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClipReaderPrivate;
 | 
					class ClipReaderPrivate;
 | 
				
			||||||
class ClipReader {
 | 
					class ClipReader {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
| 
						 | 
					@ -502,7 +524,7 @@ public:
 | 
				
			||||||
	void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded);
 | 
						void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded);
 | 
				
			||||||
	QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms);
 | 
						QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms);
 | 
				
			||||||
	bool currentDisplayed() const {
 | 
						bool currentDisplayed() const {
 | 
				
			||||||
		return _currentDisplayed.loadAcquire() > 0;
 | 
							return _currentDisplayed.get();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 width() const;
 | 
						int32 width() const;
 | 
				
			||||||
| 
						 | 
					@ -529,8 +551,8 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QPixmap _current;
 | 
						QPixmap _current;
 | 
				
			||||||
	QImage _currentOriginal, _cacheForResize;
 | 
						QImage _currentOriginal, _cacheForResize;
 | 
				
			||||||
	QAtomicInt _currentDisplayed;
 | 
						Atomic<bool> _currentDisplayed, _paused;
 | 
				
			||||||
	uint64 _lastDisplayMs;
 | 
						Atomic<uint64> _lastDisplayMs;
 | 
				
			||||||
	int32 _threadIndex;
 | 
						int32 _threadIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	friend class ClipReadManager;
 | 
						friend class ClipReadManager;
 | 
				
			||||||
| 
						 | 
					@ -580,7 +602,7 @@ private:
 | 
				
			||||||
	ReaderPointers _readerPointers;
 | 
						ReaderPointers _readerPointers;
 | 
				
			||||||
	QMutex _readerPointersMutex;
 | 
						QMutex _readerPointersMutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result);
 | 
						bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum ResultHandleState {
 | 
						enum ResultHandleState {
 | 
				
			||||||
		ResultHandleRemove,
 | 
							ResultHandleRemove,
 | 
				
			||||||
| 
						 | 
					@ -594,5 +616,6 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QTimer _timer;
 | 
						QTimer _timer;
 | 
				
			||||||
	QThread *_processingInThread;
 | 
						QThread *_processingInThread;
 | 
				
			||||||
 | 
						bool _needReProcess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue