From 29a498b9598219f1ad92fd8115029c5e64909da7 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 28 May 2020 17:05:44 +0400
Subject: [PATCH] Use Data::CloudImage for location thumbnails.

---
 Telegram/SourceFiles/data/data_location.cpp   | 59 ++++++++++++----
 Telegram/SourceFiles/data/data_location.h     | 68 ++++---------------
 .../SourceFiles/data/data_media_types.cpp     | 10 +--
 Telegram/SourceFiles/data/data_media_types.h  | 12 ++--
 Telegram/SourceFiles/data/data_session.cpp    | 21 ++++--
 Telegram/SourceFiles/data/data_session.h      |  4 +-
 .../view/media/history_view_location.cpp      | 24 ++++---
 .../view/media/history_view_location.h        | 19 +++++-
 8 files changed, 124 insertions(+), 93 deletions(-)

diff --git a/Telegram/SourceFiles/data/data_location.cpp b/Telegram/SourceFiles/data/data_location.cpp
index 0c608b868..c26e50e71 100644
--- a/Telegram/SourceFiles/data/data_location.cpp
+++ b/Telegram/SourceFiles/data/data_location.cpp
@@ -13,7 +13,53 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 namespace Data {
 namespace {
 
-GeoPointLocation ComputeLocation(const Data::LocationPoint &point) {
+[[nodiscard]] QString AsString(float64 value) {
+	constexpr auto kPrecision = 6;
+	return QString::number(value, 'f', kPrecision);
+}
+
+} // namespace
+
+LocationPoint::LocationPoint(const MTPDgeoPoint &point)
+: _lat(point.vlat().v)
+, _lon(point.vlong().v)
+, _access(point.vaccess_hash().v) {
+}
+
+QString LocationPoint::latAsString() const {
+	return AsString(_lat);
+}
+
+QString LocationPoint::lonAsString() const {
+	return AsString(_lon);
+}
+
+MTPGeoPoint LocationPoint::toMTP() const {
+	return MTP_geoPoint(
+		MTP_double(_lon),
+		MTP_double(_lat),
+		MTP_long(_access));
+}
+
+float64 LocationPoint::lat() const {
+	return _lat;
+}
+
+float64 LocationPoint::lon() const {
+	return _lon;
+}
+
+uint64 LocationPoint::accessHash() const {
+	return _access;
+}
+
+size_t LocationPoint::hash() const {
+	return QtPrivate::QHashCombine().operator()(
+		std::hash<float64>()(_lat),
+		_lon);
+}
+
+GeoPointLocation ComputeLocation(const LocationPoint &point) {
 	const auto scale = 1 + (cScale() * cIntRetinaFactor()) / 200;
 	const auto zoom = 13 + (scale - 1);
 	const auto w = st::locationSize.width() / scale;
@@ -30,15 +76,4 @@ GeoPointLocation ComputeLocation(const Data::LocationPoint &point) {
 	return result;
 }
 
-} // namespace
-
-LocationThumbnail::LocationThumbnail(const LocationPoint &point)
-: point(point)
-, thumb(Images::Create(ComputeLocation(point))) {
-}
-
-void LocationThumbnail::load(FileOrigin origin) {
-	thumb->load(origin);
-}
-
 } // namespace Data
diff --git a/Telegram/SourceFiles/data/data_location.h b/Telegram/SourceFiles/data/data_location.h
index 00350af3e..7d9a59b4a 100644
--- a/Telegram/SourceFiles/data/data_location.h
+++ b/Telegram/SourceFiles/data/data_location.h
@@ -14,58 +14,28 @@ struct FileOrigin;
 class LocationPoint {
 public:
 	LocationPoint() = default;
-	explicit LocationPoint(const MTPDgeoPoint &point)
-	: _lat(point.vlat().v)
-	, _lon(point.vlong().v)
-	, _access(point.vaccess_hash().v) {
-	}
+	explicit LocationPoint(const MTPDgeoPoint &point);
 
-	QString latAsString() const {
-		return AsString(_lat);
-	}
-	QString lonAsString() const {
-		return AsString(_lon);
-	}
-	MTPGeoPoint toMTP() const {
-		return MTP_geoPoint(
-			MTP_double(_lon),
-			MTP_double(_lat),
-			MTP_long(_access));
-	}
+	[[nodiscard]] QString latAsString() const;
+	[[nodiscard]] QString lonAsString() const;
+	[[nodiscard]] MTPGeoPoint toMTP() const;
 
-	float64 lat() const {
-		return _lat;
-	}
-	float64 lon() const {
-		return _lon;
-	}
-	uint64 accessHash() const {
-		return _access;
-	}
+	[[nodiscard]] float64 lat() const;
+	[[nodiscard]] float64 lon() const;
+	[[nodiscard]] uint64 accessHash() const;
 
-	inline size_t hash() const {
-#ifndef OS_MAC_OLD
-		return QtPrivate::QHashCombine().operator()(
-				std::hash<float64>()(_lat),
-				_lon);
-#else // OS_MAC_OLD
-		const auto h1 = std::hash<float64>()(_lat);
-		const auto h2 = std::hash<float64>()(_lon);
-		return ((h1 << 16) | (h1 >> 16)) ^ h2;
-#endif // OS_MAC_OLD
-	}
+	[[nodiscard]] size_t hash() const;
 
 private:
-	static QString AsString(float64 value) {
-		constexpr auto kPrecision = 6;
-		return QString::number(value, 'f', kPrecision);
-	}
-
-	friend inline bool operator==(const LocationPoint &a, const LocationPoint &b) {
+	friend inline bool operator==(
+			const LocationPoint &a,
+			const LocationPoint &b) {
 		return (a._lat == b._lat) && (a._lon == b._lon);
 	}
 
-	friend inline bool operator<(const LocationPoint &a, const LocationPoint &b) {
+	friend inline bool operator<(
+			const LocationPoint &a,
+			const LocationPoint &b) {
 		return (a._lat < b._lat) || ((a._lat == b._lat) && (a._lon < b._lon));
 	}
 
@@ -75,15 +45,7 @@ private:
 
 };
 
-struct LocationThumbnail {
-	LocationThumbnail(const LocationPoint &point);
-
-	LocationPoint point;
-	ImagePtr thumb;
-
-	void load(FileOrigin origin);
-
-};
+[[nodiscard]] GeoPointLocation ComputeLocation(const LocationPoint &point);
 
 } // namespace Data
 
diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp
index 72b167b92..b4aeb8817 100644
--- a/Telegram/SourceFiles/data/data_media_types.cpp
+++ b/Telegram/SourceFiles/data/data_media_types.cpp
@@ -173,7 +173,7 @@ const Invoice *Media::invoice() const {
 	return nullptr;
 }
 
-LocationThumbnail *Media::location() const {
+Data::CloudImage *Media::location() const {
 	return nullptr;
 }
 
@@ -782,6 +782,7 @@ MediaLocation::MediaLocation(
 	const QString &title,
 	const QString &description)
 : Media(parent)
+, _point(point)
 , _location(parent->history()->owner().location(point))
 , _title(title)
 , _description(description) {
@@ -790,12 +791,12 @@ MediaLocation::MediaLocation(
 std::unique_ptr<Media> MediaLocation::clone(not_null<HistoryItem*> parent) {
 	return std::make_unique<MediaLocation>(
 		parent,
-		_location->point,
+		_point,
 		_title,
 		_description);
 }
 
-LocationThumbnail *MediaLocation::location() const {
+Data::CloudImage *MediaLocation::location() const {
 	return _location;
 }
 
@@ -826,7 +827,7 @@ TextForMimeData MediaLocation::clipboardText() const {
 	if (!descriptionResult.text.isEmpty()) {
 		result.append(std::move(descriptionResult));
 	}
-	result.append(LocationClickHandler(_location->point).dragText());
+	result.append(LocationClickHandler(_point).dragText());
 	return result;
 }
 
@@ -844,6 +845,7 @@ std::unique_ptr<HistoryView::Media> MediaLocation::createView(
 	return std::make_unique<HistoryView::Location>(
 		message,
 		_location,
+		_point,
 		_title,
 		_description);
 }
diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h
index b410d4fed..7baa7c558 100644
--- a/Telegram/SourceFiles/data/data_media_types.h
+++ b/Telegram/SourceFiles/data/data_media_types.h
@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "data/data_location.h"
+
 class HistoryItem;
 
 namespace base {
@@ -27,8 +29,7 @@ class Media;
 
 namespace Data {
 
-class LocationPoint;
-struct LocationThumbnail;
+class CloudImage;
 
 enum class CallFinishReason : char {
 	Missed,
@@ -77,7 +78,7 @@ public:
 	virtual const Call *call() const;
 	virtual GameData *game() const;
 	virtual const Invoice *invoice() const;
-	virtual LocationThumbnail *location() const;
+	virtual Data::CloudImage *location() const;
 	virtual PollData *poll() const;
 
 	virtual bool uploading() const;
@@ -236,7 +237,7 @@ public:
 
 	std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
 
-	LocationThumbnail *location() const override;
+	Data::CloudImage *location() const override;
 	QString chatListText() const override;
 	QString notificationText() const override;
 	QString pinnedTextSubstring() const override;
@@ -249,7 +250,8 @@ public:
 		not_null<HistoryItem*> realParent) override;
 
 private:
-	not_null<LocationThumbnail*> _location;
+	LocationPoint _point;
+	not_null<Data::CloudImage*> _location;
 	QString _title;
 	QString _description;
 
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 8e1370a1d..79da37b0d 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -3025,13 +3025,22 @@ void Session::applyUpdate(const MTPDupdateChatDefaultBannedRights &update) {
 	}
 }
 
-not_null<LocationThumbnail*> Session::location(const LocationPoint &point) {
+not_null<Data::CloudImage*> Session::location(const LocationPoint &point) {
 	const auto i = _locations.find(point);
-	return (i != _locations.cend())
-		? i->second.get()
-		: _locations.emplace(
-			point,
-			std::make_unique<LocationThumbnail>(point)).first->second.get();
+	if (i != _locations.cend()) {
+		return i->second.get();
+	}
+	const auto result = _locations.emplace(
+		point,
+		std::make_unique<Data::CloudImage>(_session)).first->second.get();
+	const auto location = Data::ComputeLocation(point);
+	result->set(ImageWithLocation{
+		.location = ImageLocation(
+			{ location },
+			location.width,
+			location.height)
+	});
+	return result;
 }
 
 void Session::registerPhotoItem(
diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h
index 32454f246..6f3ac2e83 100644
--- a/Telegram/SourceFiles/data/data_session.h
+++ b/Telegram/SourceFiles/data/data_session.h
@@ -561,7 +561,7 @@ public:
 	not_null<PollData*> processPoll(const MTPPoll &data);
 	not_null<PollData*> processPoll(const MTPDmessageMediaPoll &data);
 
-	[[nodiscard]] not_null<LocationThumbnail*> location(
+	[[nodiscard]] not_null<Data::CloudImage*> location(
 		const LocationPoint &point);
 
 	void registerPhotoItem(
@@ -939,7 +939,7 @@ private:
 		base::flat_set<not_null<ViewElement*>>> _webpageViews;
 	std::unordered_map<
 		LocationPoint,
-		std::unique_ptr<LocationThumbnail>> _locations;
+		std::unique_ptr<Data::CloudImage>> _locations;
 	std::unordered_map<
 		PollId,
 		std::unique_ptr<PollData>> _polls;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.cpp b/Telegram/SourceFiles/history/view/media/history_view_location.cpp
index 36d7c7c11..57a386a71 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_location.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_location.cpp
@@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/image/image.h"
 #include "ui/text_options.h"
 #include "data/data_file_origin.h"
-#include "data/data_location.h"
+#include "data/data_cloud_file.h"
 #include "app.h"
 #include "styles/style_history.h"
 
@@ -24,14 +24,15 @@ namespace HistoryView {
 
 Location::Location(
 	not_null<Element*> parent,
-	not_null<Data::LocationThumbnail*> location,
+	not_null<Data::CloudImage*> data,
+	Data::LocationPoint point,
 	const QString &title,
 	const QString &description)
 : Media(parent)
-, _data(location)
+, _data(data)
 , _title(st::msgMinWidth)
 , _description(st::msgMinWidth)
-, _link(std::make_shared<LocationClickHandler>(_data->point)) {
+, _link(std::make_shared<LocationClickHandler>(point)) {
 	if (!title.isEmpty()) {
 		_title.setText(
 			st::webPageTitleStyle,
@@ -48,6 +49,14 @@ Location::Location(
 	}
 }
 
+void Location::ensureMediaCreated() const {
+	if (_media) {
+		return;
+	}
+	_media = _data->createView();
+	_data->load(_parent->data()->fullId());
+}
+
 QSize Location::countOptimalSize() {
 	auto tw = fullWidth();
 	auto th = fullHeight();
@@ -155,14 +164,13 @@ void Location::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
 		App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
 	}
 
-	const auto contextId = _parent->data()->fullId();
-	_data->load(contextId);
 	auto roundRadius = ImageRoundRadius::Large;
 	auto roundCorners = ((isBubbleTop() && _title.isEmpty() && _description.isEmpty()) ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
 		| (isBubbleBottom() ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None);
 	auto rthumb = QRect(paintx, painty, paintw, painth);
-	if (_data && !_data->thumb->isNull()) {
-		const auto &pix = _data->thumb->pixSingle(contextId, paintw, painth, paintw, painth, roundRadius, roundCorners);
+	ensureMediaCreated();
+	if (const auto thumbnail = _media->image()) {
+		const auto &pix = thumbnail->pixSingle({}, paintw, painth, paintw, painth, roundRadius, roundCorners);
 		p.drawPixmap(rthumb.topLeft(), pix);
 	} else {
 		App::complexLocationRect(p, rthumb, roundRadius, roundCorners);
diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.h b/Telegram/SourceFiles/history/view/media/history_view_location.h
index 89e66b17a..2538dc3e5 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_location.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_location.h
@@ -8,9 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #pragma once
 
 #include "history/view/media/history_view_media.h"
+#include "data/data_location.h"
 
 namespace Data {
-struct LocationThumbnail;
+class CloudImage;
+class CloudImageView;
 } // namespace Data
 
 namespace HistoryView {
@@ -19,7 +21,8 @@ class Location : public Media {
 public:
 	Location(
 		not_null<Element*> parent,
-		not_null<Data::LocationThumbnail*> location,
+		not_null<Data::CloudImage*> data,
+		Data::LocationPoint point,
 		const QString &title = QString(),
 		const QString &description = QString());
 
@@ -54,14 +57,24 @@ public:
 		return isBubbleBottom();
 	}
 
+	void unloadHeavyPart() override {
+		_media = nullptr;
+	}
+	bool hasHeavyPart() const override {
+		return (_media != nullptr);
+	}
+
 private:
+	void ensureMediaCreated() const;
+
 	QSize countOptimalSize() override;
 	QSize countCurrentSize(int newWidth) override;
 
 	TextSelection toDescriptionSelection(TextSelection selection) const;
 	TextSelection fromDescriptionSelection(TextSelection selection) const;
 
-	const not_null<Data::LocationThumbnail*> _data;
+	const not_null<Data::CloudImage*> _data;
+	mutable std::shared_ptr<Data::CloudImageView> _media;
 	Ui::Text::String _title, _description;
 	ClickHandlerPtr _link;