WebDocument wrap to HistoryPhoto supported.

Only WebDocument with a valid 'size' field value and with a valid
'documentAttributeImageSize' attribute works wrapped as a photo.
This commit is contained in:
John Preston 2017-03-05 20:33:32 +03:00
parent 7b5985445c
commit 31e3c6a2c6
6 changed files with 255 additions and 72 deletions

View File

@ -340,8 +340,6 @@ enum {
FileLoaderQueueStopTimeout = 5000,
DownloadPartSize = 64 * 1024, // 64kb for photo
DocumentDownloadPartSize = 128 * 1024, // 128kb for document
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb
MaxFileQueries = 16, // max 16 file parts downloaded at the same time
MaxWebFileQueries = 8, // max 8 http[s] files downloaded at the same time

View File

@ -3457,8 +3457,29 @@ QString HistoryInvoice::fillAmountAndCurrency(int amount, const QString &currenc
void HistoryInvoice::fillFromData(const MTPDmessageMediaInvoice &data) {
// init attach
if (data.has_photo()) {
// _attach = std::make_unique<HistoryPhoto>(_parent, data.vphoto.c_webDocument(), QString());
if (data.has_photo() && data.vphoto.type() == mtpc_webDocument) {
auto &doc = data.vphoto.c_webDocument();
auto imageSize = QSize();
for (auto &attribute : doc.vattributes.v) {
if (attribute.type() == mtpc_documentAttributeImageSize) {
auto &size = attribute.c_documentAttributeImageSize();
imageSize = QSize(size.vw.v, size.vh.v);
break;
}
}
if (!imageSize.isEmpty()) {
auto thumbsize = shrinkToKeepAspect(imageSize.width(), imageSize.height(), 100, 100);
auto thumb = ImagePtr(thumbsize.width(), thumbsize.height());
auto mediumsize = shrinkToKeepAspect(imageSize.width(), imageSize.height(), 320, 320);
auto medium = ImagePtr(mediumsize.width(), mediumsize.height());
auto full = ImagePtr(WebFileImageLocation(imageSize.width(), imageSize.height(), doc.vdc_id.v, doc.vurl.v, doc.vaccess_hash.v), doc.vsize.v);
auto photoId = rand_value<PhotoId>();
auto photo = App::photoSet(photoId, 0, 0, unixtime(), thumb, medium, full);
_attach = std::make_unique<HistoryPhoto>(_parent, photo, QString());
}
}
auto statusText = TextWithEntities { fillAmountAndCurrency(data.vtotal_amount.v, qs(data.vcurrency)), EntitiesInText() };

View File

@ -45,6 +45,9 @@ struct DataRequested {
};
QMap<int32, DataRequested> DataRequestedMap;
constexpr auto kDownloadPhotoPartSize = 64 * 1024; // 64kb for photo
constexpr auto kDownloadDocumentPartSize = 128 * 1024; // 128kb for document
} // namespace
struct FileLoaderQueue {
@ -361,11 +364,11 @@ mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, L
_queue = &i.value();
}
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, int32 version, LocationType type, const QString &to, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
mtpFileLoader::mtpFileLoader(int32 dc, uint64 id, uint64 accessHash, int32 version, LocationType type, const QString &to, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
: FileLoader(to, size, type, toCache, fromCloud, autoLoading)
, _dc(dc)
, _id(id)
, _access(access)
, _accessHash(accessHash)
, _version(version) {
auto shiftedDcId = MTP::downloadDcId(_dc, 0);
auto i = queues.find(shiftedDcId);
@ -375,6 +378,18 @@ mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, i
_queue = &i.value();
}
mtpFileLoader::mtpFileLoader(const WebFileImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading)
: FileLoader(QString(), size, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading)
, _dc(location->dc())
, _urlLocation(location) {
auto shiftedDcId = MTP::downloadDcId(_dc, 0);
auto i = queues.find(shiftedDcId);
if (i == queues.cend()) {
i = queues.insert(shiftedDcId, FileLoaderQueue(MaxFileQueries));
}
_queue = &i.value();
}
int32 mtpFileLoader::currentOffset(bool includeSkipped) const {
return (_fileIsOpen ? _file.size() : _data.size()) - (includeSkipped ? 0 : _skippedBytes);
}
@ -398,36 +413,24 @@ namespace {
}
bool mtpFileLoader::loadPart() {
if (_finished || _lastComplete || (!_requests.isEmpty() && !_size)) {
if (_finished || _lastComplete || (!_dcIndexByRequest.isEmpty() && !_size)) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): loadPart() returned, _finished=%2, _lastComplete=%3, _requests.size()=%4, _size=%5").arg(_id).arg(Logs::b(_finished)).arg(Logs::b(_lastComplete)).arg(_requests.size()).arg(_size));
DEBUG_LOG(("FileLoader(%1): loadPart() returned, _finished=%2, _lastComplete=%3, _requests.size()=%4, _size=%5").arg(_id).arg(Logs::b(_finished)).arg(Logs::b(_lastComplete)).arg(_dcIndexByRequest.size()).arg(_size));
}
return false;
}
if (_size && _nextRequestOffset >= _size) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): loadPart() returned, _size=%2, _nextRequestOffset=%3, _requests=%4").arg(_id).arg(_size).arg(_nextRequestOffset).arg(serializereqs(_requests)));
DEBUG_LOG(("FileLoader(%1): loadPart() returned, _size=%2, _nextRequestOffset=%3, _requests=%4").arg(_id).arg(_size).arg(_nextRequestOffset).arg(serializereqs(_dcIndexByRequest)));
}
return false;
}
int32 limit = DocumentDownloadPartSize;
MTPInputFileLocation loc;
if (_location) {
loc = MTP_inputFileLocation(MTP_long(_location->volume()), MTP_int(_location->local()), MTP_long(_location->secret()));
limit = DownloadPartSize;
} else {
switch (_locationType) {
case VideoFileLocation:
case AudioFileLocation:
case DocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_access), MTP_int(_version)); break;
default: cancel(true); return false; break;
}
}
int32 offset = _nextRequestOffset, dcIndex = 0;
DataRequested &dr(DataRequestedMap[_dc]);
auto offset = _nextRequestOffset;
auto dcIndex = 0;
auto &dr = DataRequestedMap[_dc];
if (_size) {
for (int32 i = 1; i < MTPDownloadSessionsCount; ++i) {
for (auto i = 1; i != MTPDownloadSessionsCount; ++i) {
if (dr.v[i] < dr.v[dcIndex]) {
dcIndex = i;
}
@ -436,47 +439,86 @@ bool mtpFileLoader::loadPart() {
App::app()->killDownloadSessionsStop(_dc);
mtpRequestId reqId = MTP::send(MTPupload_GetFile(loc, MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::downloadDcId(_dc, dcIndex), 50);
++_queue->queries;
dr.v[dcIndex] += limit;
_requests.insert(reqId, dcIndex);
_nextRequestOffset += limit;
auto requestId = makeRequest(offset, dcIndex);
_dcIndexByRequest.insert(requestId, dcIndex);
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): requested part with offset=%2, _queue->queries=%3, _nextRequestOffset=%4, _requests=%5").arg(_id).arg(offset).arg(_queue->queries).arg(_nextRequestOffset).arg(serializereqs(_requests)));
DEBUG_LOG(("FileLoader(%1): requested part with offset=%2, _queue->queries=%3, _nextRequestOffset=%4, _requests=%5").arg(_id).arg(offset).arg(_queue->queries).arg(_nextRequestOffset).arg(serializereqs(_dcIndexByRequest)));
}
return true;
}
void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req) {
Requests::iterator i = _requests.find(req);
if (i == _requests.cend()) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): request req=%2 for offset=%3 not found in _requests=%4").arg(_id).arg(req).arg(offset).arg(serializereqs(_requests)));
}
return loadNext();
int mtpFileLoader::partSize() const {
if (_locationType == UnknownFileLocation) {
return kDownloadPhotoPartSize;
}
return kDownloadDocumentPartSize;
}
mtpRequestId mtpFileLoader::makeRequest(int offset, int dcIndex) {
auto limit = partSize();
DataRequestedMap[_dc].v[dcIndex] += limit;
++_queue->queries;
_nextRequestOffset += limit;
if (_urlLocation) {
return MTP::send(MTPupload_GetWebFile(MTP_inputWebFileLocation(MTP_bytes(_urlLocation->url()), MTP_long(_urlLocation->accessHash())), MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::webPartLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::downloadDcId(_dc, dcIndex), 50);
}
MTPInputFileLocation loc;
if (_location) {
loc = MTP_inputFileLocation(MTP_long(_location->volume()), MTP_int(_location->local()), MTP_long(_location->secret()));
} else {
loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_accessHash), MTP_int(_version));
}
return MTP::send(MTPupload_GetFile(loc, MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::normalPartLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::downloadDcId(_dc, dcIndex), 50);
}
void mtpFileLoader::normalPartLoaded(int offset, const MTPupload_File &result, mtpRequestId req) {
if (result.type() != mtpc_upload_file) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): bad cons received! %2").arg(_id).arg(result.type()));
}
return cancel(true);
}
auto bytes = gsl::as_bytes(gsl::make_span(result.c_upload_file().vbytes.v));
return partLoaded(offset, bytes, req);
}
int32 limit = (_locationType == UnknownFileLocation) ? DownloadPartSize : DocumentDownloadPartSize;
int32 dcIndex = i.value();
void mtpFileLoader::webPartLoaded(int offset, const MTPupload_WebFile &result, mtpRequestId req) {
if (result.type() != mtpc_upload_webFile) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): bad cons received! %2").arg(_id).arg(result.type()));
}
return cancel(true);
}
auto &webFile = result.c_upload_webFile();
if (webFile.vsize.v != _size) {
LOG(("MTP Error: Bad size provided by bot for webDocument: %1, real: %2").arg(_size).arg(webFile.vsize.v));
return cancel(true);
}
auto bytes = gsl::as_bytes(gsl::make_span(webFile.vbytes.v));
return partLoaded(offset, bytes, req);
}
void mtpFileLoader::partLoaded(int offset, base::const_byte_span bytes, mtpRequestId req) {
auto i = _dcIndexByRequest.find(req);
if (i == _dcIndexByRequest.cend()) {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): request req=%2 for offset=%3 not found in _requests=%4").arg(_id).arg(req).arg(offset).arg(serializereqs(_dcIndexByRequest)));
}
return loadNext();
}
auto limit = partSize();
auto dcIndex = i.value();
DataRequestedMap[_dc].v[dcIndex] -= limit;
--_queue->queries;
_requests.erase(i);
auto &d = result.c_upload_file();
auto &bytes = d.vbytes.v;
_dcIndexByRequest.erase(i);
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): got part with offset=%2, bytes=%3, _queue->queries=%4, _nextRequestOffset=%5, _requests=%6").arg(_id).arg(offset).arg(bytes.size()).arg(_queue->queries).arg(_nextRequestOffset).arg(serializereqs(_requests)));
DEBUG_LOG(("FileLoader(%1): got part with offset=%2, bytes=%3, _queue->queries=%4, _nextRequestOffset=%5, _requests=%6").arg(_id).arg(offset).arg(bytes.size()).arg(_queue->queries).arg(_nextRequestOffset).arg(serializereqs(_dcIndexByRequest)));
}
if (bytes.size()) {
@ -488,7 +530,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
_skippedBytes += offset - fsize;
}
_file.seek(offset);
if (_file.write(bytes.data(), bytes.size()) != qint64(bytes.size())) {
if (_file.write(reinterpret_cast<const char*>(bytes.data()), bytes.size()) != qint64(bytes.size())) {
return cancel(true);
}
} else {
@ -498,20 +540,22 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
_data.resize(offset);
}
if (offset == _data.size()) {
_data.append(bytes.data(), bytes.size());
_data.append(reinterpret_cast<const char*>(bytes.data()), bytes.size());
} else {
_skippedBytes -= bytes.size();
if (int64(offset + bytes.size()) > _data.size()) {
_data.resize(offset + bytes.size());
}
memcpy(_data.data() + offset, bytes.data(), bytes.size());
auto src = bytes;
auto dst = gsl::make_span(_data).subspan(offset, bytes.size());
base::copy_bytes(gsl::as_writeable_bytes(dst), src);
}
}
}
if (!bytes.size() || (bytes.size() % 1024)) { // bad next offset
_lastComplete = true;
}
if (_requests.isEmpty() && (_lastComplete || (_size && _nextRequestOffset >= _size))) {
if (_dcIndexByRequest.isEmpty() && (_lastComplete || (_size && _nextRequestOffset >= _size))) {
if (!_fname.isEmpty() && (_toCache == LoadToCacheAsWell)) {
if (!_fileIsOpen) _fileIsOpen = _file.open(QIODevice::WriteOnly);
if (!_fileIsOpen) {
@ -534,7 +578,9 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
}
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
if (_locationType != UnknownFileLocation) { // audio, video, document
if (_urlLocation) {
Local::writeImage(storageKey(*_urlLocation), StorageImageSaved(_data));
} else if (_locationType != UnknownFileLocation) { // audio, video, document
MediaKey mkey = mediaKey(_locationType, _dc, _id, _version);
if (!_fname.isEmpty()) {
Local::writeFileLocation(mkey, FileLocation(_fname));
@ -552,7 +598,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
}
} else {
if (DebugLogging::FileLoader() && _id) {
DEBUG_LOG(("FileLoader(%1): not done yet, _lastComplete=%2, _size=%3, _nextRequestOffset=%4, _requests=%5").arg(_id).arg(Logs::b(_lastComplete)).arg(_size).arg(_nextRequestOffset).arg(serializereqs(_requests)));
DEBUG_LOG(("FileLoader(%1): not done yet, _lastComplete=%2, _size=%3, _nextRequestOffset=%4, _requests=%5").arg(_id).arg(Logs::b(_lastComplete)).arg(_size).arg(_nextRequestOffset).arg(serializereqs(_dcIndexByRequest)));
}
}
if (_finished) {
@ -572,17 +618,17 @@ bool mtpFileLoader::partFailed(const RPCError &error) {
}
void mtpFileLoader::cancelRequests() {
if (_requests.isEmpty()) return;
if (_dcIndexByRequest.isEmpty()) return;
int32 limit = (_locationType == UnknownFileLocation) ? DownloadPartSize : DocumentDownloadPartSize;
auto limit = partSize();
DataRequested &dr(DataRequestedMap[_dc]);
for (Requests::const_iterator i = _requests.cbegin(), e = _requests.cend(); i != e; ++i) {
for (auto i = _dcIndexByRequest.cbegin(), e = _dcIndexByRequest.cend(); i != e; ++i) {
MTP::cancel(i.key());
int32 dcIndex = i.value();
dr.v[dcIndex] -= limit;
}
_queue->queries -= _requests.size();
_requests.clear();
_queue->queries -= _dcIndexByRequest.size();
_dcIndexByRequest.clear();
if (!_queue->queries) {
Messenger::Instance().killDownloadSessionsStart(_dc);
@ -597,7 +643,9 @@ bool mtpFileLoader::tryLoadLocal() {
return true;
}
if (_location) {
if (_urlLocation) {
_localTaskId = Local::startImageLoad(storageKey(*_urlLocation), this);
} else if (_location) {
_localTaskId = Local::startImageLoad(storageKey(*_location), this);
} else {
if (_toCache == LoadToCacheAsWell) {

View File

@ -169,12 +169,14 @@ protected:
};
class StorageImageLocation;
class WebFileImageLocation;
class mtpFileLoader : public FileLoader, public RPCSender {
Q_OBJECT
public:
mtpFileLoader(const StorageImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading);
mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, int32 version, LocationType type, const QString &toFile, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading);
mtpFileLoader(int32 dc, uint64 id, uint64 accessHash, int32 version, LocationType type, const QString &toFile, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading);
mtpFileLoader(const WebFileImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading);
int32 currentOffset(bool includeSkipped = false) const override;
@ -188,28 +190,35 @@ public:
~mtpFileLoader();
protected:
private:
bool tryLoadLocal() override;
void cancelRequests() override;
typedef QMap<mtpRequestId, int32> Requests;
Requests _requests;
int partSize() const;
mtpRequestId makeRequest(int offset, int dcIndex);
QMap<mtpRequestId, int> _dcIndexByRequest;
bool loadPart() override;
void partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req);
void normalPartLoaded(int offset, const MTPupload_File &result, mtpRequestId req);
void webPartLoaded(int offset, const MTPupload_WebFile &result, mtpRequestId req);
void partLoaded(int offset, base::const_byte_span bytes, mtpRequestId req);
bool partFailed(const RPCError &error);
bool _lastComplete = false;
int32 _skippedBytes = 0;
int32 _nextRequestOffset = 0;
int32 _dc;
int32 _dc; // for photo locations
const StorageImageLocation *_location = nullptr;
uint64 _id = 0; // for other locations
uint64 _access = 0;
uint64 _id = 0; // for document locations
uint64 _accessHash = 0;
int32 _version = 0;
const WebFileImageLocation *_urlLocation = nullptr; // for webdocument locations
};
class webFileLoaderPrivate;

View File

@ -364,6 +364,9 @@ Image *blank() {
using StorageImages = QMap<StorageKey, StorageImage*>;
StorageImages storageImages;
using WebFileImages = QMap<StorageKey, WebFileImage*>;
WebFileImages webFileImages;
int64 globalAcquiredSize = 0;
uint64 PixKey(int width, int height, Images::Options options) {
@ -377,6 +380,7 @@ uint64 SinglePixKey(Images::Options options) {
} // namespace
StorageImageLocation StorageImageLocation::Null;
WebFileImageLocation WebFileImageLocation::Null;
bool Image::isNull() const {
return (this == blank());
@ -809,6 +813,9 @@ void clearStorageImages() {
for (auto image : base::take(webImages)) {
delete image;
}
for (auto image : base::take(webFileImages)) {
delete image;
}
}
void clearAllImages() {
@ -995,6 +1002,29 @@ FileLoader *StorageImage::createLoader(LoadFromCloudSetting fromCloud, bool auto
return new mtpFileLoader(&_location, _size, fromCloud, autoLoading);
}
WebFileImage::WebFileImage(const WebFileImageLocation &location, int32 size)
: _location(location)
, _size(size) {
}
int32 WebFileImage::countWidth() const {
return _location.width();
}
int32 WebFileImage::countHeight() const {
return _location.height();
}
void WebFileImage::setInformation(int32 size, int32 width, int32 height) {
_size = size;
_location.setSize(width, height);
}
FileLoader *WebFileImage::createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) {
if (_location.isNull()) return 0;
return new mtpFileLoader(&_location, _size, fromCloud, autoLoading);
}
DelayedStorageImage::DelayedStorageImage() : StorageImage(StorageImageLocation())
, _loadRequested(false)
, _loadCancelled(false)
@ -1188,6 +1218,15 @@ StorageImage *getImage(const StorageImageLocation &location, const QByteArray &b
return i.value();
}
WebFileImage *getImage(const WebFileImageLocation &location, int32 size) {
auto key = storageKey(location);
auto i = webFileImages.constFind(key);
if (i == webFileImages.cend()) {
i = webFileImages.insert(key, new WebFileImage(location, size));
}
return i.value();
}
} // namespace internal
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark) : _bookmark(bookmark), _failed(_bookmark ? !_bookmark->enable() : false) {

View File

@ -82,8 +82,7 @@ inline int32 unpackIntSecond(uint64 v) {
class StorageImageLocation {
public:
StorageImageLocation() : _widthheight(0), _dclocal(0), _volume(0), _secret(0) {
}
StorageImageLocation() = default;
StorageImageLocation(int32 width, int32 height, int32 dc, const uint64 &volume, int32 local, const uint64 &secret) : _widthheight(packIntInt(width, height)), _dclocal(packIntInt(dc, local)), _volume(volume), _secret(secret) {
}
StorageImageLocation(int32 width, int32 height, const MTPDfileLocation &location) : _widthheight(packIntInt(width, height)), _dclocal(packIntInt(location.vdc_id.v, location.vlocal_id.v)), _volume(location.vvolume_id.v), _secret(location.vsecret.v) {
@ -116,10 +115,10 @@ public:
static StorageImageLocation Null;
private:
uint64 _widthheight;
uint64 _dclocal;
uint64 _volume;
uint64 _secret;
uint64 _widthheight = 0;
uint64 _dclocal = 0;
uint64 _volume = 0;
uint64 _secret = 0;
friend inline bool operator==(const StorageImageLocation &a, const StorageImageLocation &b) {
return (a._dclocal == b._dclocal) && (a._volume == b._volume) && (a._secret == b._secret);
@ -131,6 +130,51 @@ inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation
return !(a == b);
}
class WebFileImageLocation {
public:
WebFileImageLocation() = default;
WebFileImageLocation(int32 width, int32 height, int32 dc, const QByteArray &url, uint64 accessHash) : _widthheight(packIntInt(width, height)), _accessHash(accessHash), _url(url), _dc(dc) {
}
bool isNull() const {
return !_dc;
}
int32 width() const {
return unpackIntFirst(_widthheight);
}
int32 height() const {
return unpackIntSecond(_widthheight);
}
void setSize(int32 width, int32 height) {
_widthheight = packIntInt(width, height);
}
int32 dc() const {
return _dc;
}
uint64 accessHash() const {
return _accessHash;
}
const QByteArray &url() const {
return _url;
}
static WebFileImageLocation Null;
private:
uint64 _widthheight = 0;
uint64 _accessHash = 0;
QByteArray _url;
int32 _dc = 0;
friend inline bool operator==(const WebFileImageLocation &a, const WebFileImageLocation &b) {
return (a._dc == b._dc) && (a._accessHash == b._accessHash) && (a._url == b._url);
}
};
inline bool operator!=(const WebFileImageLocation &a, const WebFileImageLocation &b) {
return !(a == b);
}
namespace Images {
QImage prepareBlur(QImage image);
@ -290,6 +334,11 @@ inline StorageKey storageKey(const MTPDfileLocation &location) {
inline StorageKey storageKey(const StorageImageLocation &location) {
return storageKey(location.dc(), location.volume(), location.local());
}
inline StorageKey storageKey(const WebFileImageLocation &location) {
auto url = location.url();
auto sha = hashSha1(url.data(), url.size());
return storageKey(location.dc(), *reinterpret_cast<const uint64*>(sha.data()), *reinterpret_cast<const int32*>(sha.data() + sizeof(uint64)));
}
class RemoteImage : public Image {
public:
@ -356,6 +405,22 @@ protected:
};
class WebFileImage : public RemoteImage {
public:
WebFileImage(const WebFileImageLocation &location, int32 size = 0);
protected:
void setInformation(int32 size, int32 width, int32 height) override;
FileLoader *createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) override;
WebFileImageLocation _location;
int32 _size;
int32 countWidth() const override;
int32 countHeight() const override;
};
class DelayedStorageImage : public StorageImage {
public:
@ -426,6 +491,7 @@ namespace internal {
Image *getImage(int32 width, int32 height);
StorageImage *getImage(const StorageImageLocation &location, int32 size = 0);
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes);
WebFileImage *getImage(const WebFileImageLocation &location, int32 size = 0);
} // namespace internal
class ImagePtr : public ManagedPtr<Image> {
@ -447,6 +513,8 @@ public:
}
ImagePtr(const StorageImageLocation &location, const QByteArray &bytes) : Parent(internal::getImage(location, bytes)) {
}
ImagePtr(const WebFileImageLocation &location, int32 size = 0) : Parent(internal::getImage(location, size)) {
}
ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def = ImagePtr());
ImagePtr(int32 width, int32 height) : Parent(internal::getImage(width, height)) {
}