tdesktop/Telegram/SourceFiles/ui/image/image_location.h

617 lines
13 KiB
C
Raw Normal View History

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class FileLoader;
namespace Storage {
namespace Cache {
struct Key;
} // namespace Cache
} // namespace Storage
namespace Data {
struct UpdatedFileReferences;
} // namespace Data
enum LoadFromCloudSetting {
LoadFromCloudOrLocal,
LoadFromLocalOnly,
};
enum LoadToCacheSetting {
LoadToFileOnly,
LoadToCacheAsWell,
};
using InMemoryKey = std::pair<uint64, uint64>;
namespace std {
template<>
struct hash<InMemoryKey> {
size_t operator()(InMemoryKey value) const {
auto seed = hash<uint64>()(value.first);
seed ^= hash<uint64>()(value.second)
+ std::size_t(0x9e3779b9)
+ (seed << 6) + (seed >> 2);
return seed;
}
};
} // namespace std
class StorageFileLocation {
public:
// Those are used in serialization, don't change.
enum class Type : uint8 {
Legacy = 0x00,
Encrypted = 0x01,
Document = 0x02,
Secure = 0x03,
Takeout = 0x04,
Photo = 0x05,
PeerPhoto = 0x06,
StickerSetThumb = 0x07,
};
StorageFileLocation() = default;
StorageFileLocation(
int32 dcId,
int32 self,
const MTPInputFileLocation &tl);
[[nodiscard]] StorageFileLocation convertToModern(
Type type,
uint64 id,
uint64 accessHash) const;
[[nodiscard]] int32 dcId() const;
[[nodiscard]] uint64 objectId() const;
[[nodiscard]] MTPInputFileLocation tl(int32 self) const;
[[nodiscard]] QByteArray serialize() const;
[[nodiscard]] int serializeSize() const;
[[nodiscard]] static std::optional<StorageFileLocation> FromSerialized(
const QByteArray &serialized);
[[nodiscard]] Type type() const;
[[nodiscard]] bool valid() const;
[[nodiscard]] Storage::Cache::Key cacheKey() const;
[[nodiscard]] Storage::Cache::Key bigFileBaseCacheKey() const;
2019-04-03 20:05:29 +00:00
// We have to allow checking this because of a serialization bug.
[[nodiscard]] bool isDocumentThumbnail() const;
[[nodiscard]] QByteArray fileReference() const;
bool refreshFileReference(const Data::UpdatedFileReferences &updates);
bool refreshFileReference(const QByteArray &data);
[[nodiscard]] static const StorageFileLocation &Invalid();
private:
friend bool operator==(
const StorageFileLocation &a,
const StorageFileLocation &b);
2019-04-12 12:33:21 +00:00
friend bool operator<(
const StorageFileLocation &a,
const StorageFileLocation &b);
uint16 _dcId = 0;
Type _type = Type::Legacy;
uint8 _sizeLetter = 0;
int32 _localId = 0;
uint64 _id = 0;
uint64 _accessHash = 0;
uint64 _volumeId = 0;
2019-05-20 14:57:25 +00:00
uint32 _inMessagePeerId = 0; // > 0 'userId', < 0 '-channelId'.
uint32 _inMessageId = 0;
QByteArray _fileReference;
};
inline bool operator!=(
const StorageFileLocation &a,
const StorageFileLocation &b) {
return !(a == b);
}
2019-04-12 12:33:21 +00:00
inline bool operator>(
const StorageFileLocation &a,
const StorageFileLocation &b) {
return (b < a);
}
inline bool operator<=(
const StorageFileLocation &a,
const StorageFileLocation &b) {
return !(b < a);
}
inline bool operator>=(
const StorageFileLocation &a,
const StorageFileLocation &b) {
return !(a < b);
}
class StorageImageLocation {
public:
StorageImageLocation() = default;
2018-07-13 16:49:46 +00:00
StorageImageLocation(
const StorageFileLocation &file,
int width,
int height);
2018-07-13 16:49:46 +00:00
[[nodiscard]] QByteArray serialize() const;
[[nodiscard]] int serializeSize() const;
[[nodiscard]] static std::optional<StorageImageLocation> FromSerialized(
const QByteArray &serialized);
[[nodiscard]] StorageImageLocation convertToModern(
StorageFileLocation::Type type,
uint64 id,
uint64 accessHash) const {
return StorageImageLocation(
_file.convertToModern(type, id, accessHash),
_width,
_height);
}
[[nodiscard]] const StorageFileLocation &file() const {
return _file;
}
[[nodiscard]] int width() const {
return _width;
}
[[nodiscard]] int height() const {
return _height;
}
void setSize(int width, int height) {
_width = width;
_height = height;
}
[[nodiscard]] StorageFileLocation::Type type() const {
return _file.type();
}
[[nodiscard]] bool valid() const {
return _file.valid();
2018-07-13 16:49:46 +00:00
}
[[nodiscard]] QByteArray fileReference() const {
return _file.fileReference();
}
bool refreshFileReference(const QByteArray &data) {
return _file.refreshFileReference(data);
}
bool refreshFileReference(const Data::UpdatedFileReferences &updates) {
return _file.refreshFileReference(updates);
}
[[nodiscard]] static const StorageImageLocation &Invalid() {
static auto result = StorageImageLocation();
return result;
}
private:
2018-07-13 16:49:46 +00:00
friend inline bool operator==(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return (a._file == b._file);
}
2019-04-12 12:33:21 +00:00
friend inline bool operator<(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return (a._file < b._file);
}
StorageFileLocation _file;
int _width = 0;
int _height = 0;
2015-05-19 15:46:45 +00:00
};
inline bool operator!=(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return !(a == b);
}
2019-04-12 12:33:21 +00:00
inline bool operator>(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return (b < a);
}
inline bool operator<=(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return !(b < a);
}
inline bool operator>=(
const StorageImageLocation &a,
const StorageImageLocation &b) {
return !(a < b);
}
class WebFileLocation {
public:
WebFileLocation() = default;
WebFileLocation(const QByteArray &url, uint64 accessHash)
: _accessHash(accessHash)
, _url(url) {
}
bool isNull() const {
return _url.isEmpty();
}
uint64 accessHash() const {
return _accessHash;
}
const QByteArray &url() const {
return _url;
}
static WebFileLocation Null;
private:
uint64 _accessHash = 0;
QByteArray _url;
2018-07-13 16:49:46 +00:00
friend inline bool operator==(
const WebFileLocation &a,
const WebFileLocation &b) {
return (a._accessHash == b._accessHash)
2018-07-13 16:49:46 +00:00
&& (a._url == b._url);
}
2019-04-12 12:33:21 +00:00
friend inline bool operator<(
const WebFileLocation &a,
const WebFileLocation &b) {
return std::tie(a._accessHash, a._url)
< std::tie(b._accessHash, b._url);
}
};
inline bool operator!=(const WebFileLocation &a, const WebFileLocation &b) {
return !(a == b);
}
2019-04-12 12:33:21 +00:00
inline bool operator>(const WebFileLocation &a, const WebFileLocation &b) {
return (b < a);
}
inline bool operator<=(const WebFileLocation &a, const WebFileLocation &b) {
return !(b < a);
}
inline bool operator>=(const WebFileLocation &a, const WebFileLocation &b) {
return !(a < b);
}
struct GeoPointLocation {
float64 lat = 0.;
float64 lon = 0.;
uint64 access = 0;
int32 width = 0;
int32 height = 0;
int32 zoom = 0;
int32 scale = 0;
};
inline bool operator==(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return (a.lat == b.lat)
&& (a.lon == b.lon)
&& (a.access == b.access)
&& (a.width == b.width)
&& (a.height == b.height)
&& (a.zoom == b.zoom)
&& (a.scale == b.scale);
}
2019-04-12 12:33:21 +00:00
inline bool operator<(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return std::tie(
a.access,
a.lat,
a.lon,
a.width,
a.height,
a.zoom,
a.scale)
< std::tie(
b.access,
b.lat,
b.lon,
b.width,
b.height,
b.zoom,
b.scale);
}
inline bool operator!=(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return !(a == b);
}
2019-04-12 12:33:21 +00:00
inline bool operator>(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return (b < a);
}
inline bool operator<=(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return !(b < a);
}
inline bool operator>=(
const GeoPointLocation &a,
const GeoPointLocation &b) {
return !(a < b);
}
struct PlainUrlLocation {
QString url;
friend inline bool operator==(
const PlainUrlLocation &a,
const PlainUrlLocation &b) {
return (a.url == b.url);
}
friend inline bool operator<(
const PlainUrlLocation &a,
const PlainUrlLocation &b) {
return (a.url < b.url);
}
};
struct InMemoryLocation {
QByteArray bytes;
friend inline bool operator==(
const InMemoryLocation &a,
const InMemoryLocation &b) {
return (a.bytes == b.bytes);
}
friend inline bool operator<(
const InMemoryLocation &a,
const InMemoryLocation &b) {
return (a.bytes < b.bytes);
}
};
class DownloadLocation {
public:
base::variant<
StorageFileLocation,
WebFileLocation,
GeoPointLocation,
PlainUrlLocation,
InMemoryLocation> data;
[[nodiscard]] QByteArray serialize() const;
[[nodiscard]] int serializeSize() const;
[[nodiscard]] static std::optional<DownloadLocation> FromSerialized(
const QByteArray &serialized);
[[nodiscard]] DownloadLocation convertToModern(
StorageFileLocation::Type type,
uint64 id,
uint64 accessHash) const;
[[nodiscard]] Storage::Cache::Key cacheKey() const;
[[nodiscard]] bool valid() const;
[[nodiscard]] QByteArray fileReference() const;
bool refreshFileReference(const QByteArray &data);
bool refreshFileReference(const Data::UpdatedFileReferences &updates);
private:
friend inline bool operator==(
const DownloadLocation &a,
const DownloadLocation &b) {
return (a.data == b.data);
}
friend inline bool operator<(
const DownloadLocation &a,
const DownloadLocation &b) {
return (a.data < b.data);
}
};
class ImageLocation {
public:
ImageLocation() = default;
ImageLocation(
const DownloadLocation &file,
int width,
int height);
[[nodiscard]] QByteArray serialize() const;
[[nodiscard]] int serializeSize() const;
[[nodiscard]] static std::optional<ImageLocation> FromSerialized(
const QByteArray &serialized);
[[nodiscard]] ImageLocation convertToModern(
StorageFileLocation::Type type,
uint64 id,
uint64 accessHash) const {
return ImageLocation(
_file.convertToModern(type, id, accessHash),
_width,
_height);
}
[[nodiscard]] const DownloadLocation &file() const {
return _file;
}
[[nodiscard]] int width() const {
return _width;
}
[[nodiscard]] int height() const {
return _height;
}
void setSize(int width, int height) {
_width = width;
_height = height;
}
[[nodiscard]] bool valid() const {
return _file.valid();
}
[[nodiscard]] QByteArray fileReference() const {
return _file.fileReference();
}
bool refreshFileReference(const QByteArray &data) {
return _file.refreshFileReference(data);
}
bool refreshFileReference(const Data::UpdatedFileReferences &updates) {
return _file.refreshFileReference(updates);
}
[[nodiscard]] static const ImageLocation &Invalid() {
static auto result = ImageLocation();
return result;
}
private:
friend inline bool operator==(
const ImageLocation &a,
const ImageLocation &b) {
return (a._file == b._file);
}
friend inline bool operator<(
const ImageLocation &a,
const ImageLocation &b) {
return (a._file < b._file);
}
DownloadLocation _file;
int _width = 0;
int _height = 0;
};
struct ImageWithLocation {
ImageLocation location;
int bytesCount = 0;
QByteArray bytes;
QImage preloaded;
};
2018-10-11 15:54:57 +00:00
class Image;
class ImagePtr {
public:
2018-10-11 15:54:57 +00:00
ImagePtr();
explicit ImagePtr(not_null<Image*> data);
2018-10-11 15:54:57 +00:00
Image *operator->() const;
Image *get() const;
2018-10-11 15:54:57 +00:00
explicit operator bool() const;
private:
2018-10-11 15:54:57 +00:00
not_null<Image*> _data;
};
InMemoryKey inMemoryKey(const StorageFileLocation &location);
inline InMemoryKey inMemoryKey(const StorageImageLocation &location) {
return inMemoryKey(location.file());
}
inline InMemoryKey inMemoryKey(const WebFileLocation &location) {
auto result = InMemoryKey();
const auto &url = location.url();
const auto sha = hashSha1(url.data(), url.size());
bytes::copy(
bytes::object_as_span(&result),
bytes::make_span(sha).subspan(0, sizeof(result)));
return result;
}
inline InMemoryKey inMemoryKey(const GeoPointLocation &location) {
return InMemoryKey(
(uint64(std::round(std::abs(location.lat + 360.) * 1000000)) << 32)
| uint64(std::round(std::abs(location.lon + 360.) * 1000000)),
(uint64(location.width) << 32) | uint64(location.height));
}
inline QSize shrinkToKeepAspect(int32 width, int32 height, int32 towidth, int32 toheight) {
int32 w = qMax(width, 1), h = qMax(height, 1);
if (w * toheight > h * towidth) {
h = qRound(h * towidth / float64(w));
w = towidth;
} else {
w = qRound(w * toheight / float64(h));
h = toheight;
}
return QSize(qMax(w, 1), qMax(h, 1));
}
class PsFileBookmark;
class ReadAccessEnabler {
public:
ReadAccessEnabler(const PsFileBookmark *bookmark);
ReadAccessEnabler(const std::shared_ptr<PsFileBookmark> &bookmark);
bool failed() const {
return _failed;
}
~ReadAccessEnabler();
private:
const PsFileBookmark *_bookmark;
bool _failed;
};
class FileLocation {
public:
FileLocation() = default;
explicit FileLocation(const QString &name);
static FileLocation InMediaCacheLocation();
[[nodiscard]] bool check() const;
[[nodiscard]] const QString &name() const;
void setBookmark(const QByteArray &bookmark);
QByteArray bookmark() const;
[[nodiscard]] bool isEmpty() const {
return name().isEmpty();
}
[[nodiscard]] bool inMediaCache() const;
bool accessEnable() const;
void accessDisable() const;
QString fname;
QDateTime modified;
qint32 size;
private:
std::shared_ptr<PsFileBookmark> _bookmark;
};
inline bool operator==(const FileLocation &a, const FileLocation &b) {
return (a.name() == b.name())
&& (a.modified == b.modified)
&& (a.size == b.size);
}
inline bool operator!=(const FileLocation &a, const FileLocation &b) {
return !(a == b);
}