From b8cb7928318e8509603c0e78f903cce938f91e55 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 16 Jan 2019 16:39:35 +0400
Subject: [PATCH] Read background image async.

---
 Telegram/SourceFiles/mainwidget.cpp | 96 ++++++++++++++++++-----------
 Telegram/SourceFiles/mainwidget.h   |  5 +-
 2 files changed, 65 insertions(+), 36 deletions(-)

diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index b93f43b9d..8115f271a 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -220,6 +220,11 @@ StackItemSection::StackItemSection(
 , _memento(std::move(memento)) {
 }
 
+struct MainWidget::SettingBackground {
+	Data::WallPaper data;
+	base::binary_guard generating;
+};
+
 MainWidget::MainWidget(
 	QWidget *parent,
 	not_null<Window::Controller*> controller)
@@ -1414,11 +1419,12 @@ void MainWidget::updateScrollColors() {
 }
 
 void MainWidget::setChatBackground(const Data::WallPaper &background) {
-	_background = std::make_unique<Data::WallPaper>(background);
-	if (_background->document) {
-		_background->document->save(Data::FileOrigin(), QString());
-	} else if (_background->thumb) {
-		_background->thumb->loadEvenCancelled(Data::FileOrigin());
+	_background = std::make_unique<SettingBackground>();
+	_background->data = background;
+	if (_background->data.document) {
+		_background->data.document->save(Data::FileOrigin(), QString());
+	} else if (_background->data.thumb) {
+		_background->data.thumb->loadEvenCancelled(Data::FileOrigin());
 	}
 	checkChatBackground();
 
@@ -1433,71 +1439,91 @@ bool MainWidget::chatBackgroundLoading() {
 
 float64 MainWidget::chatBackgroundProgress() const {
 	if (_background) {
-		if (_background->document) {
-			return _background->document->progress();
-		} else if (_background->thumb) {
-			return _background->thumb->progress();
+		if (_background->generating.alive()) {
+			return 1.;
+		} else if (_background->data.document) {
+			return _background->data.document->progress();
+		} else if (_background->data.thumb) {
+			return _background->data.thumb->progress();
 		}
 	}
 	return 1.;
 }
 
 void MainWidget::checkChatBackground() {
-	using namespace Window::Theme;
-
-	if (!_background) {
+	if (!_background || _background->generating.alive()) {
 		return;
 	}
-	const auto document = _background->document;
+	const auto document = _background->data.document;
 	if (document && !document->loaded()) {
 		return;
-	} else if (!document && !_background->thumb->loaded()) {
+	} else if (!document && !_background->data.thumb->loaded()) {
 		return;
 	}
 
-	auto image = [&] {
-		if (!document) {
-			const auto &thumb = _background->thumb;
-			return thumb
-				? thumb->pixNoCache(Data::FileOrigin()).toImage()
-				: QImage();
-		}
-		auto bytes = document->data();
+	if (!document) {
+		const auto &thumb = _background->data.thumb;
+		setGeneratedBackground(thumb
+			? thumb->pixNoCache(Data::FileOrigin()).toImage()
+			: QImage());
+		return;
+	}
+	auto [left, right] = base::make_binary_guard();
+	_background->generating = std::move(left);
+	crl::async([
+		this,
+		bytes = document->data(),
+		path = document->filepath(),
+		guard = std::move(right)
+	]() mutable {
 		auto format = QByteArray();
-		const auto path = document->filepath();
 		if (bytes.isEmpty()) {
-			QFile f(document->filepath());
+			QFile f(path);
 			if (f.size() <= App::kImageSizeLimit
 				&& f.open(QIODevice::ReadOnly)) {
 				bytes = f.readAll();
 			}
 		}
-		return bytes.isEmpty()
+		auto image = bytes.isEmpty()
 			? QImage()
 			: App::readImage(bytes, &format, false, nullptr);
-	}();
+		crl::on_main([
+			this,
+			guard = std::move(guard),
+			image = std::move(image)
+		]() mutable {
+			if (!guard.alive()) {
+				return;
+			}
+			setGeneratedBackground(std::move(image));
+		});
+	});
+}
+
+ImagePtr MainWidget::newBackgroundThumb() {
+	return _background ? _background->data.thumb : ImagePtr();
+}
+
+void MainWidget::setGeneratedBackground(QImage &&image) {
+	using namespace Window::Theme;
 
 	if (image.isNull()) {
 		Background()->setImage(kDefaultBackground);
 	} else if (false
-		|| _background->id == kInitialBackground
-		|| _background->id == kDefaultBackground) {
-		Background()->setImage(_background->id);
+		|| _background->data.id == kInitialBackground
+		|| _background->data.id == kDefaultBackground) {
+		Background()->setImage(_background->data.id);
 	} else {
 		Background()->setImage(
-			_background->id,
+			_background->data.id,
 			std::move(image));
 	}
-	const auto tile = (_background->id == kInitialBackground);
+	const auto tile = (_background->data.id == kInitialBackground);
 	Background()->setTile(tile);
 	_background = nullptr;
 	crl::on_main(this, [=] { update(); });
 }
 
-ImagePtr MainWidget::newBackgroundThumb() {
-	return _background ? _background->thumb : ImagePtr();
-}
-
 void MainWidget::messageDataReceived(ChannelData *channel, MsgId msgId) {
 	_history->messageDataReceived(channel, msgId);
 }
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index a25604631..374b6c14d 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -454,6 +454,8 @@ private:
 	void ensureFirstColumnResizeAreaCreated();
 	void ensureThirdColumnResizeAreaCreated();
 
+	void setGeneratedBackground(QImage &&image);
+
 	not_null<Window::Controller*> _controller;
 	bool _started = false;
 
@@ -543,7 +545,8 @@ private:
 	QMap<mtpRequestId, PeerData*> _viewsIncrementByRequest;
 	SingleTimer _viewsIncrementTimer;
 
-	std::unique_ptr<Data::WallPaper> _background;
+	struct SettingBackground;
+	std::unique_ptr<SettingBackground> _background;
 
 	bool _firstColumnResizing = false;
 	int _firstColumnResizingShift = 0;