From 956c3af0aecdf5be7c8cd23ec349a372812de16a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 15 Apr 2020 18:06:34 +0400 Subject: [PATCH] Start DocumentData::thumbnail move to DocumentMedia. --- Telegram/SourceFiles/boxes/background_box.cpp | 40 +++++-- .../boxes/background_preview_box.cpp | 20 +++- .../SourceFiles/boxes/edit_caption_box.cpp | 61 ++++++----- Telegram/SourceFiles/boxes/edit_caption_box.h | 4 +- Telegram/SourceFiles/boxes/stickers_box.cpp | 25 +++-- .../chat_helpers/stickers_list_widget.cpp | 8 +- Telegram/SourceFiles/data/data_document.cpp | 98 +++++++++++------ Telegram/SourceFiles/data/data_document.h | 21 ++-- .../SourceFiles/data/data_document_media.cpp | 40 ++++++- .../SourceFiles/data/data_document_media.h | 9 +- .../SourceFiles/data/data_reply_preview.cpp | 9 +- Telegram/SourceFiles/data/data_session.cpp | 48 ++++----- Telegram/SourceFiles/data/data_session.h | 10 +- Telegram/SourceFiles/data/data_wall_paper.cpp | 15 ++- Telegram/SourceFiles/data/data_wall_paper.h | 5 +- .../history/view/history_view_element.cpp | 1 + .../view/media/history_view_document.cpp | 27 +++-- .../history/view/media/history_view_gif.cpp | 24 ++--- .../view/media/history_view_sticker.cpp | 3 +- .../media/history_view_theme_document.cpp | 22 ++-- .../inline_bot_layout_internal.cpp | 58 ++++++---- .../inline_bots/inline_bot_layout_internal.h | 4 +- Telegram/SourceFiles/mainwidget.cpp | 18 +++- .../media/view/media_view_group_thumbs.cpp | 41 ++++++- .../media/view/media_view_group_thumbs.h | 3 + .../media/view/media_view_overlay_widget.cpp | 33 +++--- .../SourceFiles/media/view/media_view_pip.cpp | 6 +- .../SourceFiles/overview/overview_layout.cpp | 102 ++++++++++-------- .../SourceFiles/overview/overview_layout.h | 3 + .../SourceFiles/storage/file_download.cpp | 4 +- .../storage/file_download_mtproto.cpp | 6 ++ .../storage/file_download_mtproto.h | 1 + .../SourceFiles/storage/file_download_web.cpp | 4 +- Telegram/SourceFiles/storage/localstorage.cpp | 9 +- .../storage/serialize_document.cpp | 23 ++-- .../storage/streamed_file_downloader.cpp | 4 +- .../window/window_media_preview.cpp | 14 +-- 37 files changed, 511 insertions(+), 312 deletions(-) diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp index 6882c74b2..56590c10c 100644 --- a/Telegram/SourceFiles/boxes/background_box.cpp +++ b/Telegram/SourceFiles/boxes/background_box.cpp @@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/sender.h" #include "data/data_session.h" #include "data/data_file_origin.h" +#include "data/data_document.h" +#include "data/data_document_media.h" #include "boxes/background_preview_box.h" #include "boxes/confirm_box.h" #include "app.h" @@ -75,6 +77,7 @@ protected: private: struct Paper { Data::WallPaper data; + mutable std::shared_ptr dataMedia; mutable QPixmap thumbnail; }; struct Selected { @@ -252,11 +255,21 @@ void BackgroundBox::Inner::resizeToContentAndPreload() { const auto rows = (count / kBackgroundsInRow) + (count % kBackgroundsInRow ? 1 : 0); - resize(st::boxWideWidth, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); + resize( + st::boxWideWidth, + (rows * (st::backgroundSize.height() + st::backgroundPadding) + + st::backgroundPadding)); const auto preload = kBackgroundsInRow * 3; for (const auto &paper : _papers | ranges::view::take(preload)) { - paper.data.loadThumbnail(); + if (paper.data.localThumbnail()) { + paper.data.loadLocalThumbnail(); + } else if (const auto document = paper.data.document()) { + if (!paper.dataMedia) { + paper.dataMedia = document->createMediaView(); + paper.dataMedia->thumbnailWanted(paper.data.fileOrigin()); + } + } } update(); } @@ -292,15 +305,27 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) { void BackgroundBox::Inner::validatePaperThumbnail( const Paper &paper) const { - Expects(paper.data.thumbnail() != nullptr); - - const auto thumbnail = paper.data.thumbnail(); if (!paper.thumbnail.isNull()) { return; - } else if (!thumbnail->loaded()) { - thumbnail->load(paper.data.fileOrigin()); + } + const auto localThumbnail = paper.data.localThumbnail(); + if (!localThumbnail) { + if (const auto document = paper.data.document()) { + if (!paper.dataMedia) { + paper.dataMedia = document->createMediaView(); + paper.dataMedia->thumbnailWanted(paper.data.fileOrigin()); + } + } + if (!paper.dataMedia || !paper.dataMedia->thumbnail()) { + return; + } + } else if (!localThumbnail->loaded()) { + localThumbnail->load(paper.data.fileOrigin()); return; } + const auto thumbnail = localThumbnail + ? localThumbnail + : paper.dataMedia->thumbnail(); auto original = thumbnail->original(); if (paper.data.isPattern()) { const auto color = *paper.data.backgroundColor(); @@ -314,6 +339,7 @@ void BackgroundBox::Inner::validatePaperThumbnail( original, st::backgroundSize)); paper.thumbnail.setDevicePixelRatio(cRetinaFactor()); + paper.dataMedia = nullptr; } void BackgroundBox::Inner::paintPaper( diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index 9542837c0..311acd79f 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/data_document.h" #include "data/data_document_media.h" +#include "data/data_file_origin.h" #include "base/unixtime.h" #include "boxes/confirm_box.h" #include "boxes/background_preview_box.h" @@ -413,6 +414,9 @@ BackgroundPreviewBox::BackgroundPreviewBox( , _paper(paper) , _media(_paper.document() ? _paper.document()->createMediaView() : nullptr) , _radial([=](crl::time now) { radialAnimationCallback(now); }) { + if (_media) { + _media->thumbnailWanted(_paper.fileOrigin()); + } subscribe(_session->downloaderTaskFinished(), [=] { update(); }); } @@ -430,12 +434,15 @@ void BackgroundPreviewBox::prepare() { } updateServiceBg(_paper.backgroundColor()); - _paper.loadThumbnail(); + _paper.loadLocalThumbnail(); _paper.loadDocument(); - if (_paper.document() && _paper.document()->loading()) { + const auto document = _paper.document(); + if (document && document->loading()) { _radial.start(_media->progress()); } - if (_paper.thumbnail() && !_paper.isPattern()) { + if (!_paper.isPattern() + && (_paper.localThumbnail() + || (document && document->hasThumbnail()))) { createBlurCheckbox(); } setScaledFromThumb(); @@ -647,7 +654,12 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) { } bool BackgroundPreviewBox::setScaledFromThumb() { - const auto thumbnail = _paper.thumbnail(); + const auto localThumbnail = _paper.localThumbnail(); + const auto thumbnail = localThumbnail + ? localThumbnail + : _media + ? _media->thumbnail() + : nullptr; if (!thumbnail || !thumbnail->loaded()) { return false; } else if (_paper.isPattern() && _paper.document() != nullptr) { diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 4fb068103..cf29ffc98 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -61,7 +61,6 @@ EditCaptionBox::EditCaptionBox( QSize dimensions; auto image = (Image*)nullptr; - DocumentData *doc = nullptr; const auto media = item->media(); if (const auto photo = media->photo()) { @@ -69,7 +68,10 @@ EditCaptionBox::EditCaptionBox( dimensions = QSize(photo->width(), photo->height()); image = photo->large(); } else if (const auto document = media->document()) { - image = document->thumbnail(); + _documentMedia = document->createMediaView(); + _documentMedia->thumbnailWanted(_msgId); + // #TODO optimize + streamed GIF view + image = _documentMedia->thumbnail(); dimensions = image ? image->size() : document->dimensions; @@ -82,11 +84,10 @@ EditCaptionBox::EditCaptionBox( } else { _doc = true; } - doc = document; } const auto editData = PrepareEditText(item); - if (!_animated && (dimensions.isEmpty() || doc || !image)) { + if (!_animated && (dimensions.isEmpty() || _documentMedia || !image)) { if (!image) { _thumbw = 0; } else { @@ -114,13 +115,15 @@ EditCaptionBox::EditCaptionBox( }; } - if (doc) { - const auto nameString = doc->isVoiceMessage() + if (_documentMedia) { + const auto document = _documentMedia->owner(); + const auto nameString = document->isVoiceMessage() ? tr::lng_media_audio(tr::now) - : doc->composeNameString(); - setName(nameString, doc->size); - _isImage = doc->isImage(); - _isAudio = (doc->isVoiceMessage() || doc->isAudioFile()); + : document->composeNameString(); + setName(nameString, document->size); + _isImage = document->isImage(); + _isAudio = document->isVoiceMessage() + || document->isAudioFile(); } if (_refreshThumbnail) { _refreshThumbnail(); @@ -158,10 +161,7 @@ EditCaptionBox::EditCaptionBox( maxW, maxH); }; - if (doc) { - _gifMedia = doc->createMediaView(); - } - prepareGifPreview(doc); + prepareGifPreview(); } else { maxW = dimensions.width(); maxH = dimensions.height(); @@ -209,7 +209,7 @@ EditCaptionBox::EditCaptionBox( thumbX = (st::boxWideWidth - thumbWidth) / 2; }; - if (doc && doc->isAnimation()) { + if (_documentMedia && _documentMedia->owner()->isAnimation()) { resizeDimensions(_gifw, _gifh, _gifx); } limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX); @@ -252,12 +252,9 @@ EditCaptionBox::EditCaptionBox( _refreshThumbnail(); update(); } - if (doc && doc->isAnimation()) { - if (!_gifMedia) { - _gifMedia = doc->createMediaView(); - } - if (_gifMedia->loaded() && !_gifPreview) { - prepareGifPreview(doc); + if (_documentMedia && _documentMedia->owner()->isAnimation()) { + if (_documentMedia->loaded() && !_gifPreview) { + prepareGifPreview(); } } }); @@ -314,23 +311,23 @@ void EditCaptionBox::updateEmojiPanelGeometry() { local.x() + _emojiToggle->width() * 3); } -void EditCaptionBox::prepareGifPreview(DocumentData* document) { - Expects(!document || (_gifMedia != nullptr)); - +void EditCaptionBox::prepareGifPreview() { const auto isListEmpty = _preparedList.files.empty(); if (_gifPreview) { return; - } else if (!document && isListEmpty) { + } else if (!_documentMedia && isListEmpty) { return; } const auto callback = [=](Media::Clip::Notification notification) { clipCallback(notification); }; - if (document && document->isAnimation() && _gifMedia->loaded()) { - _gifPreview = Media::Clip::MakeReader( - _gifMedia.get(), - _msgId, - callback); + if (_documentMedia && _documentMedia->owner()->isAnimation()) { + if (_documentMedia->loaded()) { + _gifPreview = Media::Clip::MakeReader( + _documentMedia.get(), + _msgId, + callback); + } } else if (!isListEmpty) { const auto file = &_preparedList.files.front(); if (file->path.isEmpty()) { @@ -343,7 +340,9 @@ void EditCaptionBox::prepareGifPreview(DocumentData* document) { callback); } } - if (_gifPreview) _gifPreview->setAutoplay(); + if (_gifPreview) { + _gifPreview->setAutoplay(); + } } void EditCaptionBox::clipCallback(Media::Clip::Notification notification) { diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.h b/Telegram/SourceFiles/boxes/edit_caption_box.h index 0e7a80b0c..a49f4b029 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.h +++ b/Telegram/SourceFiles/boxes/edit_caption_box.h @@ -57,7 +57,7 @@ protected: private: void updateBoxSize(); - void prepareGifPreview(DocumentData* document = nullptr); + void prepareGifPreview(); void clipCallback(Media::Clip::Notification notification); void setupEmojiPanel(); @@ -87,6 +87,7 @@ private: not_null _controller; FullMsgId _msgId; + std::shared_ptr _documentMedia; Image *_thumbnailImage = nullptr; bool _thumbnailImageLoaded = false; Fn _refreshThumbnail; @@ -95,7 +96,6 @@ private: bool _doc = false; QPixmap _thumb; - std::shared_ptr _gifMedia; Media::Clip::ReaderPointer _gifPreview; object_ptr _field = { nullptr }; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 02af0c396..a3dd46fb7 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -908,7 +908,7 @@ void StickersBox::Inner::paintRowThumbnail( set->accessHash); const auto thumb = set->thumbnail ? set->thumbnail.get() - : set->sticker->thumbnail(); + : set->stickerMedia->thumbnail(); if (!thumb) { return; } @@ -1650,6 +1650,8 @@ void StickersBox::Inner::updateRows() { row->thumbnail = thumbnail; row->sticker = sticker; row->stickerMedia = sticker->createMediaView(); + row->stickerMedia->thumbnailWanted( + Data::FileOriginStickerSet(row->id, row->accessHash)); row->pixw = pixw; row->pixh = pixh; } @@ -1747,8 +1749,10 @@ void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbn const auto size = set.thumbnail ? set.thumbnail->size() - : sticker->thumbnail() - ? sticker->thumbnail()->size() + : sticker->hasThumbnail() + ? QSize( + sticker->thumbnailLocation().width(), + sticker->thumbnailLocation().height()) : QSize(1, 1); auto pixw = size.width(); auto pixh = size.height(); @@ -1913,10 +1917,17 @@ void StickersBox::Inner::readVisibleSets() { ? nullptr : _rows[i]->thumbnail ? _rows[i]->thumbnail.get() - : _rows[i]->sticker->thumbnail(); - if (!thumbnail - || thumbnail->loaded() - || _rows[i]->stickerMedia->loaded()) { + : _rows[i]->stickerMedia + ? _rows[i]->stickerMedia->thumbnail() + : nullptr; + const auto thumbnailLoading = !_rows[i]->sticker + ? false + : _rows[i]->thumbnail + ? !thumbnail->loaded() + : _rows[i]->stickerMedia + ? _rows[i]->sticker->thumbnailLoading() + : false; + if (!thumbnailLoading || _rows[i]->stickerMedia->loaded()) { _session->api().readFeaturedSetDelayed(_rows[i]->id); } } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 9f3b01a8f..265e1ae33 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -748,7 +748,7 @@ void StickersListWidget::Footer::paintSetIcon( const auto origin = icon.sticker->stickerSetOrigin(); const auto thumb = icon.thumbnail ? icon.thumbnail.get() - : icon.sticker->thumbnail(); + : icon.stickerMedia->thumbnail(); if (!thumb) { return; } @@ -988,7 +988,7 @@ void StickersListWidget::readVisibleFeatured( int loaded = 0; for (int j = 0; j < count; ++j) { if (!set.stickers[j].document->hasThumbnail() - || set.stickers[j].document->thumbnail()->loaded() + || !set.stickers[j].document->thumbnailLoading() || set.stickers[j].documentMedia->loaded()) { ++loaded; } @@ -2602,7 +2602,9 @@ void StickersListWidget::fillIcons(QList &icons) { const auto size = thumbnail ? thumbnail->size() : s->hasThumbnail() - ? s->thumbnail()->size() + ? QSize( + s->thumbnailLocation().width(), + s->thumbnailLocation().height()) : QSize(); auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1; if (availw * thumbh > availh * thumbw) { diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 72c3e2552..892f5bf7a 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -452,6 +452,7 @@ DocumentData::DocumentData(not_null owner, DocumentId id) } DocumentData::~DocumentData() { + base::take(_thumbnailLoader).reset(); destroyLoader(); unload(); } @@ -564,7 +565,7 @@ void DocumentData::setattributes( void DocumentData::validateLottieSticker() { if (type == FileDocument && _mimeString == qstr("application/x-tgsticker") - && _thumbnail) { + && hasThumbnail()) { type = StickerDocument; _additional = std::make_unique(); sticker()->animated = true; @@ -590,7 +591,7 @@ bool DocumentData::checkWallPaperProperties() { return true; } if (type != FileDocument - || !_thumbnail + || !hasThumbnail() || !dimensions.width() || !dimensions.height() || dimensions.width() > Storage::kMaxWallPaperDimension @@ -605,20 +606,28 @@ bool DocumentData::checkWallPaperProperties() { void DocumentData::updateThumbnails( const QByteArray &inlineThumbnailBytes, - ImagePtr thumbnail) { + const StorageImageLocation &thumbnail) { if (!inlineThumbnailBytes.isEmpty() && _inlineThumbnailBytes.isEmpty()) { _inlineThumbnailBytes = inlineThumbnailBytes; } - if (thumbnail - && (!_thumbnail - || (sticker() - && (_thumbnail->width() < thumbnail->width() - || _thumbnail->height() < thumbnail->height())))) { - _thumbnail = thumbnail; + if (thumbnail.valid() + && (!_thumbnailLocation.valid() + || _thumbnailLocation.width() < thumbnail.width() + || _thumbnailLocation.height() < thumbnail.height())) { + _thumbnailLocation = thumbnail; + if (_thumbnailLoader) { + const auto origin = base::take(_thumbnailLoader)->fileOrigin(); + loadThumbnail(origin); + // #TODO optimize replace thumbnail in activeMediaView(). + } } } +const StorageImageLocation &DocumentData::thumbnailLocation() const { + return _thumbnailLocation; +} + bool DocumentData::isWallPaper() const { return (type == WallPaperDocument); } @@ -628,17 +637,53 @@ bool DocumentData::isPatternWallPaper() const { } bool DocumentData::hasThumbnail() const { - return !_thumbnail->isNull(); + return _thumbnailLocation.valid() + && (_thumbnailLocation.width() > 0) + && (_thumbnailLocation.height() > 0); } -Image *DocumentData::thumbnail() const { - return _thumbnail ? _thumbnail.get() : nullptr; +bool DocumentData::thumbnailLoading() const { + return _thumbnailLoader != nullptr; +} + +bool DocumentData::thumbnailFailed() const { + return (_flags & Flag::ThumbnailFailed); } void DocumentData::loadThumbnail(Data::FileOrigin origin) { - if (_thumbnail && !_thumbnail->loaded()) { - _thumbnail->load(origin); + if (_thumbnailLoader || (_flags & Flag::ThumbnailFailed)) { + return; + } else if (const auto active = activeMediaView()) { + if (active->thumbnail()) { + return; + } } + const auto autoLoading = false; + _thumbnailLoader = std::make_unique( + _thumbnailLocation.file(), + origin, + UnknownFileLocation, + QString(), + _thumbnailSize, + LoadToCacheAsWell, + LoadFromCloudOrLocal, + autoLoading, + Data::kImageCacheTag); + _thumbnailLoader->updates( + ) | rpl::start_with_error_done([=](bool started) { + _thumbnailLoader = nullptr; + _flags |= Flag::ThumbnailFailed; + }, [=] { + if (!_thumbnailLoader->cancelled()) { + if (auto image = _thumbnailLoader->imageData(); image.isNull()) { + _flags |= Flag::ThumbnailFailed; + } else if (const auto active = activeMediaView()) { + active->setThumbnail(std::move(image)); + } + } + _thumbnailLoader = nullptr; + }) | rpl::release(); + _thumbnailLoader->start(); } Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const { @@ -765,7 +810,7 @@ void DocumentData::finishLoad() { } } -void DocumentData::destroyLoader() const { +void DocumentData::destroyLoader() { if (!_loader) { return; } @@ -1140,7 +1185,7 @@ bool DocumentData::isStickerSetInstalled() const { } Image *DocumentData::getReplyPreview(Data::FileOrigin origin) { - if (!_thumbnail) { + if (!hasThumbnail()) { return nullptr; } else if (!_replyPreview) { _replyPreview = std::make_unique(this); @@ -1275,19 +1320,15 @@ QByteArray DocumentData::fileReference() const { void DocumentData::refreshFileReference(const QByteArray &value) { _fileReference = value; - _thumbnail->refreshFileReference(value); - if (const auto data = sticker()) { - data->loc.refreshFileReference(value); - } + _thumbnailLocation.refreshFileReference(value); } void DocumentData::refreshStickerThumbFileReference() { - if (const auto data = sticker()) { - if (_thumbnail->loading()) { - data->loc.refreshFileReference( - _thumbnail->location().fileReference()); - } - } + // #TODO optimize + //if (_thumbnailLoader) { + // _thumbnailLocation.refreshFileReference( + // _thumbnailLoader->fileReference()); + //} } QString DocumentData::filename() const { @@ -1462,11 +1503,6 @@ void DocumentData::recountIsImage() { } } -bool DocumentData::thumbnailEnoughForSticker() const { - return !_thumbnail->isNull() - && ((_thumbnail->width() >= 128) || (_thumbnail->height() >= 128)); -} - void DocumentData::setRemoteLocation( int32 dc, uint64 access, diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 2550ce11d..c89eeabe9 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -61,7 +61,6 @@ struct StickerData : public DocumentAdditionalData { bool animated = false; QString alt; MTPInputStickerSet set = MTP_inputStickerSetEmpty(); - StorageImageLocation loc; // doc thumb location }; struct SongData : public DocumentAdditionalData { @@ -132,7 +131,6 @@ public: [[nodiscard]] Data::FileOrigin stickerSetOrigin() const; [[nodiscard]] Data::FileOrigin stickerOrGifOrigin() const; [[nodiscard]] bool isStickerSetInstalled() const; - [[nodiscard]] bool thumbnailEnoughForSticker() const; [[nodiscard]] SongData *song(); [[nodiscard]] const SongData *song() const; [[nodiscard]] VoiceData *voice(); @@ -158,11 +156,13 @@ public: [[nodiscard]] bool isPatternWallPaper() const; [[nodiscard]] bool hasThumbnail() const; + [[nodiscard]] bool thumbnailLoading() const; + [[nodiscard]] bool thumbnailFailed() const; void loadThumbnail(Data::FileOrigin origin); - [[nodiscard]] Image *thumbnail() const; void updateThumbnails( const QByteArray &inlineThumbnailBytes, - ImagePtr thumbnail); + const StorageImageLocation &thumbnail); + const StorageImageLocation &thumbnailLocation() const; [[nodiscard]] QByteArray inlineThumbnailBytes() const { return _inlineThumbnailBytes; @@ -248,6 +248,7 @@ private: ImageType = 0x08, DownloadCancelled = 0x10, LoadedInMediaCache = 0x20, + ThumbnailFailed = 0x40, }; using Flags = base::flags; friend constexpr bool is_flag_type(Flag) { return true; }; @@ -284,10 +285,12 @@ private: void finishLoad(); void handleLoaderUpdates(); - void destroyLoader() const; + void destroyLoader(); bool saveFromDataChecked(); + const not_null _owner; + // Two types of location: from MTProto by dc+access or from web by url int32 _dc = 0; uint64 _access = 0; @@ -298,19 +301,19 @@ private: WebFileLocation _urlLocation; QByteArray _inlineThumbnailBytes; - ImagePtr _thumbnail; + StorageImageLocation _thumbnailLocation; + std::unique_ptr _thumbnailLoader; + int _thumbnailSize = 0; std::unique_ptr _replyPreview; std::weak_ptr _media; PhotoData *_goodThumbnailPhoto = nullptr; - not_null _owner; - FileLocation _location; std::unique_ptr _additional; int32 _duration = -1; mutable Flags _flags = kStreamingSupportedUnknown; GoodThumbnailState _goodThumbnailState = GoodThumbnailState(); - mutable std::unique_ptr _loader; + std::unique_ptr _loader; }; diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp index bbb18e185..0056b8cfc 100644 --- a/Telegram/SourceFiles/data/data_document_media.cpp +++ b/Telegram/SourceFiles/data/data_document_media.cpp @@ -130,6 +130,30 @@ Image *DocumentMedia::thumbnailInline() const { return _inlineThumbnail.get(); } +Image *DocumentMedia::thumbnail() const { + return _thumbnail.get(); +} + +void DocumentMedia::thumbnailWanted(Data::FileOrigin origin) { + if (!_thumbnail) { + _owner->loadThumbnail(origin); + } +} + +QSize DocumentMedia::thumbnailSize() const { + if (const auto image = _thumbnail.get()) { + return image->size(); + } + const auto &location = _owner->thumbnailLocation(); + return { location.width(), location.height() }; +} + +void DocumentMedia::setThumbnail(QImage thumbnail) { + _thumbnail = std::make_unique( + std::make_unique(std::move(thumbnail), "PNG")); + _owner->session().downloaderTaskFinished().notify(); +} + void DocumentMedia::checkStickerLarge() { if (_sticker) { return; @@ -224,9 +248,19 @@ bool DocumentMedia::canBePlayed() const { && (loaded() || _owner->canBeStreamed()); } +bool DocumentMedia::thumbnailEnoughForSticker() const { + const auto &location = owner()->thumbnailLocation(); + const auto size = _thumbnail + ? QSize(_thumbnail->width(), _thumbnail->height()) + : location.valid() + ? QSize(location.width(), location.height()) + : QSize(); + return (size.width() >= 128) || (size.height() >= 128); +} + void DocumentMedia::checkStickerSmall() { const auto data = _owner->sticker(); - if ((data && data->animated) || _owner->thumbnailEnoughForSticker()) { + if ((data && data->animated) || thumbnailEnoughForSticker()) { _owner->loadThumbnail(_owner->stickerSetOrigin()); if (data && data->animated) { automaticLoad(_owner->stickerSetOrigin(), nullptr); @@ -243,8 +277,8 @@ Image *DocumentMedia::getStickerLarge() { Image *DocumentMedia::getStickerSmall() { const auto data = _owner->sticker(); - if ((data && data->animated) || _owner->thumbnailEnoughForSticker()) { - return _owner->thumbnail(); + if ((data && data->animated) || thumbnailEnoughForSticker()) { + return thumbnail(); } return _sticker.get(); } diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h index 9d6a2fdc6..919b7fabe 100644 --- a/Telegram/SourceFiles/data/data_document_media.h +++ b/Telegram/SourceFiles/data/data_document_media.h @@ -21,10 +21,14 @@ public: [[nodiscard]] not_null owner() const; void goodThumbnailWanted(); - [[nodiscard]] Image *goodThumbnail() const; + [[nodiscard]] Image *goodThumbnail() const; // #TODO optimize QImage-wrap void setGoodThumbnail(QImage thumbnail); [[nodiscard]] Image *thumbnailInline() const; + [[nodiscard]] Image *thumbnail() const; + [[nodiscard]] QSize thumbnailSize() const; + void thumbnailWanted(Data::FileOrigin origin); + void setThumbnail(QImage thumbnail); void checkStickerLarge(); void checkStickerSmall(); @@ -55,9 +59,12 @@ private: not_null document, QByteArray data); + [[nodiscard]] bool thumbnailEnoughForSticker() const; + const not_null _owner; std::unique_ptr _goodThumbnail; mutable std::unique_ptr _inlineThumbnail; + std::unique_ptr _thumbnail; std::unique_ptr _sticker; QByteArray _bytes; Flags _flags; diff --git a/Telegram/SourceFiles/data/data_reply_preview.cpp b/Telegram/SourceFiles/data/data_reply_preview.cpp index 78e1dccce..001cbc060 100644 --- a/Telegram/SourceFiles/data/data_reply_preview.cpp +++ b/Telegram/SourceFiles/data/data_reply_preview.cpp @@ -60,16 +60,15 @@ void ReplyPreview::prepare(not_null image, Images::Options options) { Image *ReplyPreview::image(Data::FileOrigin origin) { if (_document) { - const auto thumbnail = _document->thumbnail(); - Assert(thumbnail != nullptr); - if (!_image || (!_good && thumbnail->loaded())) { + const auto thumbnail = _documentMedia->thumbnail(); + if (!_image || (!_good && thumbnail)) { const auto option = _document->isVideoMessage() ? Images::Option::Circled : Images::Option::None; - if (thumbnail->loaded()) { + if (thumbnail) { prepare(thumbnail, option); } else { - thumbnail->load(origin); + _documentMedia->thumbnailWanted(origin); if (const auto image = _documentMedia->thumbnailInline()) { prepare(image, option | Images::Option::Blurred); } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index f9895844f..67c69ce02 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2381,9 +2381,11 @@ not_null Session::processDocument( case mtpc_document: { const auto &fields = data.c_document(); const auto mime = qs(fields.vmime_type()); + // #TODO optimize const auto format = Core::IsMimeSticker(mime) ? "WEBP" : "JPG"; + Images::Create(std::move(thumb), format); return document( fields.vid().v, fields.vaccess_hash().v, @@ -2392,10 +2394,9 @@ not_null Session::processDocument( fields.vattributes().v, mime, QByteArray(), - Images::Create(std::move(thumb), format), + StorageImageLocation(), fields.vdc_id().v, - fields.vsize().v, - StorageImageLocation()); + fields.vsize().v); } break; } Unexpected("Type in Session::document() with thumb."); @@ -2409,10 +2410,9 @@ not_null Session::document( const QVector &attributes, const QString &mime, const QByteArray &inlineThumbnailBytes, - const ImagePtr &thumbnail, + const StorageImageLocation &thumbnailLocation, int32 dc, - int32 size, - const StorageImageLocation &thumbLocation) { + int32 size) { const auto result = document(id); documentApplyFields( result, @@ -2422,10 +2422,9 @@ not_null Session::document( attributes, mime, inlineThumbnailBytes, - thumbnail, + thumbnailLocation, dc, - size, - thumbLocation); + size); return result; } @@ -2489,6 +2488,7 @@ DocumentData *Session::documentFromWeb( DocumentData *Session::documentFromWeb( const MTPDwebDocument &data, ImagePtr thumb) { + // #TODO optimize thumb const auto result = document( rand_value(), uint64(0), @@ -2497,10 +2497,9 @@ DocumentData *Session::documentFromWeb( data.vattributes().v, data.vmime_type().v, QByteArray(), - thumb, + StorageImageLocation(), MTP::maindc(), - int32(0), // data.vsize().v - StorageImageLocation()); + int32(0)); // data.vsize().v result->setWebLocation(WebFileLocation( data.vurl().v, data.vaccess_hash().v)); @@ -2510,6 +2509,7 @@ DocumentData *Session::documentFromWeb( DocumentData *Session::documentFromWeb( const MTPDwebDocumentNoProxy &data, ImagePtr thumb) { + // #TODO optimize thumb const auto result = document( rand_value(), uint64(0), @@ -2518,10 +2518,9 @@ DocumentData *Session::documentFromWeb( data.vattributes().v, data.vmime_type().v, QByteArray(), - thumb, + StorageImageLocation(), MTP::maindc(), - int32(0), // data.vsize().v - StorageImageLocation()); + int32(0)); // data.vsize().v result->setContentUrl(qs(data.vurl())); return result; } @@ -2539,7 +2538,8 @@ void Session::documentApplyFields( const MTPDdocument &data) { const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data); const auto thumbnailSize = FindDocumentThumbnail(data); - const auto thumbnail = Images::Create(data, thumbnailSize); + // #TODO optimize + const auto thumbnail = Images::Create(data, thumbnailSize)->location(); documentApplyFields( document, data.vaccess_hash().v, @@ -2550,8 +2550,7 @@ void Session::documentApplyFields( inlineThumbnailBytes, thumbnail, data.vdc_id().v, - data.vsize().v, - thumbnail->location()); + data.vsize().v); } void Session::documentApplyFields( @@ -2562,16 +2561,15 @@ void Session::documentApplyFields( const QVector &attributes, const QString &mime, const QByteArray &inlineThumbnailBytes, - const ImagePtr &thumbnail, + const StorageImageLocation &thumbnailLocation, int32 dc, - int32 size, - const StorageImageLocation &thumbLocation) { + int32 size) { if (!date) { return; } document->date = date; document->setMimeString(mime); - document->updateThumbnails(inlineThumbnailBytes, thumbnail); + document->updateThumbnails(inlineThumbnailBytes, thumbnailLocation); document->size = size; document->setattributes(attributes); @@ -2580,12 +2578,6 @@ void Session::documentApplyFields( if (dc != 0 && access != 0) { document->setRemoteLocation(dc, access, fileReference); } - - if (document->sticker() - && !document->sticker()->loc.valid() - && thumbLocation.valid()) { - document->sticker()->loc = thumbLocation; - } } not_null Session::webpage(WebPageId id) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index b3c9ec4cb..c654b40f3 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -499,10 +499,9 @@ public: const QVector &attributes, const QString &mime, const QByteArray &inlineThumbnailBytes, - const ImagePtr &thumbnail, + const StorageImageLocation &thumbnailLocation, int32 dc, - int32 size, - const StorageImageLocation &thumbLocation); + int32 size); void documentConvert( not_null original, const MTPDocument &data); @@ -754,10 +753,9 @@ private: const QVector &attributes, const QString &mime, const QByteArray &inlineThumbnailBytes, - const ImagePtr &thumbnail, + const StorageImageLocation &thumbnailLocation, int32 dc, - int32 size, - const StorageImageLocation &thumbLocation); + int32 size); DocumentData *documentFromWeb( const MTPDwebDocument &data, ImagePtr thumb); diff --git a/Telegram/SourceFiles/data/data_wall_paper.cpp b/Telegram/SourceFiles/data/data_wall_paper.cpp index 334ec8fbf..b1140e184 100644 --- a/Telegram/SourceFiles/data/data_wall_paper.cpp +++ b/Telegram/SourceFiles/data/data_wall_paper.cpp @@ -118,12 +118,8 @@ DocumentData *WallPaper::document() const { return _document; } -Image *WallPaper::thumbnail() const { - return _thumbnail - ? _thumbnail.get() - : _document - ? _document->thumbnail() - : nullptr; +Image *WallPaper::localThumbnail() const { + return _thumbnail.get(); } bool WallPaper::isPattern() const { @@ -143,7 +139,7 @@ bool WallPaper::isDark() const { } bool WallPaper::isLocal() const { - return !document() && thumbnail(); + return !document() && _thumbnail; } bool WallPaper::isBlurred() const { @@ -187,10 +183,13 @@ QString WallPaper::shareUrl() const { : base + '?' + params.join('&'); } -void WallPaper::loadThumbnail() const { +void WallPaper::loadLocalThumbnail() const { if (_thumbnail) { _thumbnail->load(fileOrigin()); } +} + +void WallPaper::loadDocumentThumbnail() const { if (_document) { _document->loadThumbnail(fileOrigin()); } diff --git a/Telegram/SourceFiles/data/data_wall_paper.h b/Telegram/SourceFiles/data/data_wall_paper.h index adab3d803..cd8eab377 100644 --- a/Telegram/SourceFiles/data/data_wall_paper.h +++ b/Telegram/SourceFiles/data/data_wall_paper.h @@ -22,7 +22,7 @@ public: [[nodiscard]] WallPaperId id() const; [[nodiscard]] std::optional backgroundColor() const; [[nodiscard]] DocumentData *document() const; - [[nodiscard]] Image *thumbnail() const; + [[nodiscard]] Image *localThumbnail() const; // #TODO optimize QImage-wrap [[nodiscard]] bool isPattern() const; [[nodiscard]] bool isDefault() const; [[nodiscard]] bool isCreator() const; @@ -34,7 +34,8 @@ public: [[nodiscard]] QString shareUrl() const; void loadDocument() const; - void loadThumbnail() const; + void loadLocalThumbnail() const; + void loadDocumentThumbnail() const; [[nodiscard]] FileOrigin fileOrigin() const; [[nodiscard]] MTPInputWallPaper mtpInput() const; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 00edb1698..1d7e5fe29 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -613,6 +613,7 @@ void Element::checkHeavyPart() { } void Element::unloadHeavyPart() { + history()->owner().unregisterHeavyViewPart(this); if (_media) { _media->unloadHeavyPart(); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index dabdc9542..4ec79f4e7 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -104,11 +104,10 @@ void Document::createComponents(bool caption) { mask |= HistoryDocumentVoice::Bit(); } else { mask |= HistoryDocumentNamed::Bit(); - if (const auto thumb = _data->thumbnail()) { + if (_data->hasThumbnail()) { if (!_data->isSong() - && thumb->width() - && thumb->height() && !Data::IsExecutableName(_data->filename())) { + _data->loadThumbnail(_realParent->fullId()); mask |= HistoryDocumentThumbed::Bit(); } } @@ -157,9 +156,9 @@ QSize Document::countOptimalSize() { } auto thumbed = Get(); if (thumbed) { - _data->loadThumbnail(_realParent->fullId()); - auto tw = style::ConvertScale(_data->thumbnail()->width()); - auto th = style::ConvertScale(_data->thumbnail()->height()); + const auto &location = _data->thumbnailLocation(); + auto tw = style::ConvertScale(location.width()); + auto th = style::ConvertScale(location.height()); if (tw > th) { thumbed->_thumbw = (tw * st::msgFileThumbSize) / th; } else { @@ -278,15 +277,10 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; QRect rthumb(style::rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top() - topMinus, st::msgFileThumbSize, st::msgFileThumbSize, width())); QPixmap thumb; - if (const auto normal = _data->thumbnail()) { - if (normal->loaded()) { - thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius); - } else { - _data->loadThumbnail(_realParent->fullId()); - if (const auto blurred = _dataMedia->thumbnailInline()) { - thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius); - } - } + if (const auto normal = _dataMedia->thumbnail()) { + thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius); + } else if (const auto blurred = _dataMedia->thumbnailInline()) { + thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius); } p.drawPixmap(rthumb.topLeft(), thumb); if (selected) { @@ -515,6 +509,9 @@ void Document::ensureDataMediaCreated() const { return; } _dataMedia = _data->createMediaView(); + if (Get()) { + _dataMedia->thumbnailWanted(_realParent->fullId()); + } history()->owner().registerHeavyViewPart(_parent); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 5c729ec0f..b8a4e6e10 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -103,10 +103,9 @@ QSize Gif::sizeForAspectRatio() const { //if (!_data->dimensions.isEmpty()) { // return _data->dimensions; //} - if (const auto thumb = _data->thumbnail()) { - if (!thumb->size().isEmpty()) { - return thumb->size(); - } + if (_data->hasThumbnail()) { + const auto &location = _data->thumbnailLocation(); + return { location.width(), location.height() }; } return { 1, 1 }; } @@ -240,8 +239,9 @@ QSize Gif::videoSize() const { return streamed->player().videoSize(); } else if (!_data->dimensions.isEmpty()) { return _data->dimensions; - } else if (const auto thumbnail = _data->thumbnail()) { - return thumbnail->size(); + } else if (_data->hasThumbnail()) { + const auto &location = _data->thumbnailLocation(); + return QSize(location.width(), location.height()); } else { return QSize(1, 1); } @@ -417,8 +417,8 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms if (good) { good->load({}); } - const auto normal = _data->thumbnail(); - if (normal && normal->loaded()) { + const auto normal = _dataMedia->thumbnail(); + if (normal) { if (normal->width() >= kUseNonBlurredThreshold || normal->height() >= kUseNonBlurredThreshold) { p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); @@ -1087,6 +1087,7 @@ void Gif::ensureDataMediaCreated() const { } _dataMedia = _data->createMediaView(); _dataMedia->goodThumbnailWanted(); + _dataMedia->thumbnailWanted(_realParent->fullId()); history()->owner().registerHeavyViewPart(_parent); } @@ -1140,8 +1141,8 @@ void Gif::validateGroupedCache( const auto good = _dataMedia->goodThumbnail(); const auto useGood = (good && good->loaded()); - const auto thumb = _data->thumbnail(); - const auto useThumb = (thumb && thumb->loaded()); + const auto thumb = _dataMedia->thumbnail(); + const auto useThumb = (thumb != nullptr); const auto image = useGood ? good : useThumb @@ -1153,9 +1154,6 @@ void Gif::validateGroupedCache( && thumb->height() < kUseNonBlurredThreshold)); if (good && !useGood) { good->load({}); - if (!useThumb) { - _data->loadThumbnail(_realParent->fullId()); - } } const auto loadLevel = useGood ? 3 : useThumb ? 2 : image ? 1 : 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index 549b1d895..fe99b7ba2 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -225,7 +225,7 @@ QPixmap Sticker::paintedPixmap(bool selected) const { return selected ? good->pixColored(o, c, w, h) : good->pix(o, w, h); - } else if (const auto thumbnail = _data->thumbnail()) { + } else if (const auto thumbnail = _dataMedia->thumbnail()) { return selected ? thumbnail->pixBlurredColored(o, c, w, h) : thumbnail->pixBlurred(o, w, h); @@ -262,6 +262,7 @@ void Sticker::ensureDataMediaCreated() const { } _dataMedia = _data->createMediaView(); _dataMedia->goodThumbnailWanted(); + _dataMedia->thumbnailWanted(_parent->data()->fullId()); _parent->history()->owner().registerHeavyViewPart(_parent); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp index 56cc6a679..aca5d7ddb 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp @@ -64,8 +64,9 @@ QSize ThemeDocument::countOptimalSize() { if (_data->isTheme()) { return st::historyThemeSize; } - auto tw = style::ConvertScale(_data->thumbnail()->width()); - auto th = style::ConvertScale(_data->thumbnail()->height()); + const auto &location = _data->thumbnailLocation(); + auto tw = style::ConvertScale(location.width()); + auto th = style::ConvertScale(location.height()); if (!tw || !th) { tw = th = 1; } @@ -86,8 +87,9 @@ QSize ThemeDocument::countCurrentSize(int newWidth) { _pixh = st::historyThemeSize.height(); return st::historyThemeSize; } - auto tw = style::ConvertScale(_data->thumbnail()->width()); - auto th = style::ConvertScale(_data->thumbnail()->height()); + const auto &location = _data->thumbnailLocation(); + auto tw = style::ConvertScale(location.width()); + auto th = style::ConvertScale(location.height()); if (!tw || !th) { tw = th = 1; } @@ -193,6 +195,7 @@ void ThemeDocument::ensureDataMediaCreated() const { } _dataMedia = _data->createMediaView(); _dataMedia->goodThumbnailWanted(); + _dataMedia->thumbnailWanted(_realParent->fullId()); _parent->history()->owner().registerHeavyViewPart(_parent); } @@ -209,11 +212,11 @@ void ThemeDocument::validateThumbnail() const { good->load({}); } } - if (_thumbnailGood >= 0 || !_data->thumbnail()) { + if (_thumbnailGood >= 0 || !_dataMedia->thumbnail()) { return; } - if (_data->thumbnail()->loaded()) { - prepareThumbnailFrom(_data->thumbnail(), 0); + if (const auto normal = _dataMedia->thumbnail()) { + prepareThumbnailFrom(normal, 0); } else if (_thumbnail.isNull()) { if (const auto blurred = _dataMedia->thumbnailInline()) { prepareThumbnailFrom(blurred, -1); @@ -234,8 +237,9 @@ void ThemeDocument::prepareThumbnailFrom( ? Images::Option::TransparentBackground : Images::Option(0)); auto original = image->original(); - auto tw = isTheme ? _pixw : style::ConvertScale(_data->thumbnail()->width()); - auto th = isTheme ? _pixh : style::ConvertScale(_data->thumbnail()->height()); + const auto &location = _data->thumbnailLocation(); + auto tw = isTheme ? _pixw : style::ConvertScale(location.width()); + auto th = isTheme ? _pixh : style::ConvertScale(location.height()); if (!tw || !th) { tw = th = 1; } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 113cf1a9d..9c905e3f2 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -63,9 +63,7 @@ int FileBase::content_width() const { if (document->dimensions.width() > 0) { return document->dimensions.width(); } - if (const auto thumb = document->thumbnail()) { - return style::ConvertScale(thumb->width()); - } + return style::ConvertScale(document->thumbnailLocation().width()); } return 0; } @@ -75,9 +73,7 @@ int FileBase::content_height() const { if (document->dimensions.height() > 0) { return document->dimensions.height(); } - if (const auto thumb = document->thumbnail()) { - return style::ConvertScale(thumb->height()); - } + return style::ConvertScale(document->thumbnailLocation().height()); } return 0; } @@ -91,15 +87,6 @@ int FileBase::content_duration() const { return getResultDuration(); } -Image *FileBase::content_thumb() const { - if (const auto document = getShownDocument()) { - if (const auto thumb = document->thumbnail()) { - return thumb; - } - } - return getResultThumb(); -} - Gif::Gif(not_null context, Result *result) : FileBase(context, result) { } @@ -329,7 +316,7 @@ void Gif::validateThumbnail( void Gif::prepareThumbnail(QSize size, QSize frame) const { if (const auto document = getShownDocument()) { ensureDataMediaCreated(document); - validateThumbnail(document->thumbnail(), size, frame, true); + validateThumbnail(_dataMedia->thumbnail(), size, frame, true); validateThumbnail(_dataMedia->thumbnailInline(), size, frame, false); } else { validateThumbnail(getResultThumb(), size, frame, true); @@ -341,6 +328,7 @@ void Gif::ensureDataMediaCreated(not_null document) const { return; } _dataMedia = document->createMediaView(); + _dataMedia->thumbnailWanted(fileOrigin()); } void Gif::ensureAnimation() const { @@ -679,7 +667,8 @@ void Photo::prepareThumbnail(QSize size, QSize frame) const { } } -Video::Video(not_null context, Result *result) : FileBase(context, result) +Video::Video(not_null context, Result *result) +: FileBase(context, result) , _link(getResultPreviewHandler()) , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) { @@ -689,8 +678,17 @@ Video::Video(not_null context, Result *result) : FileBase(context, res } } +bool Video::withThumbnail() const { + if (const auto document = getShownDocument()) { + if (document->hasThumbnail()) { + return true; + } + } + return getResultThumb() != nullptr; +} + void Video::initDimensions() { - const auto withThumb = (content_thumb() != nullptr); + const auto withThumb = withThumbnail(); _maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft; int32 textWidth = _maxw - (withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0); @@ -719,7 +717,7 @@ void Video::initDimensions() { void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) const { int left = st::inlineThumbSize + st::inlineThumbSkip; - const auto withThumb = (content_thumb() != nullptr); + const auto withThumb = withThumbnail(); if (withThumb) { prepareThumbnail({ st::inlineThumbSize, st::inlineThumbSize }); if (_thumb.isNull()) { @@ -767,9 +765,22 @@ TextState Video::getState( } void Video::prepareThumbnail(QSize size) const { - Expects(content_thumb() != nullptr); - - const auto thumb = content_thumb(); + const auto document = getShownDocument(); + if (document->hasThumbnail()) { + if (!_documentMedia) { + _documentMedia = document->createMediaView(); + _documentMedia->thumbnailWanted(fileOrigin()); + } + if (!_documentMedia->thumbnail()) { + return; + } + } + const auto thumb = document->hasThumbnail() + ? _documentMedia->thumbnail() + : getResultThumb(); + if (!thumb) { + return; + } const auto origin = fileOrigin(); if (thumb->loaded()) { if (_thumb.size() != size * cIntRetinaFactor()) { @@ -1424,7 +1435,7 @@ void Game::prepareThumbnail(QSize size) const { validateThumbnail(photo->thumbnailInline(), size, false); } else if (const auto document = getResultDocument()) { Assert(_dataMedia != nullptr); - validateThumbnail(document->thumbnail(), size, true); + validateThumbnail(_dataMedia->thumbnail(), size, true); validateThumbnail(_dataMedia->thumbnailInline(), size, false); } } @@ -1434,6 +1445,7 @@ void Game::ensureDataMediaCreated(not_null document) const { return; } _dataMedia = document->createMediaView(); + _dataMedia->thumbnailWanted(fileOrigin()); } void Game::validateThumbnail(Image *image, QSize size, bool good) const { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index dfedcffe5..8fdb0e395 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -38,7 +38,7 @@ protected: int content_width() const; int content_height() const; int content_duration() const; - Image *content_thumb() const; + }; class DeleteSavedGifClickHandler : public LeftButtonClickHandler { @@ -224,10 +224,12 @@ private: ClickHandlerPtr _link; mutable QPixmap _thumb; + mutable std::shared_ptr _documentMedia; Ui::Text::String _title, _description; QString _duration; int _durationWidth = 0; + [[nodiscard]] bool withThumbnail() const; void prepareThumbnail(QSize size) const; }; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 0317a4455..8b2d06a1d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1330,6 +1330,8 @@ void MainWidget::setChatBackground( _background = std::make_unique(background); if (const auto document = _background->data.document()) { _background->dataMedia = document->createMediaView(); + _background->dataMedia->thumbnailWanted( + _background->data.fileOrigin()); } _background->data.loadDocument(); checkChatBackground(); @@ -1352,9 +1354,9 @@ void MainWidget::setReadyChatBackground( if (image.isNull() && !background.document() - && background.thumbnail() - && background.thumbnail()->loaded()) { - image = background.thumbnail()->original(); + && background.localThumbnail() + && background.localThumbnail()->loaded()) { + image = background.localThumbnail()->original(); } const auto resetToDefault = image.isNull() @@ -1381,7 +1383,7 @@ float64 MainWidget::chatBackgroundProgress() const { return 1.; } else if (const auto document = _background->data.document()) { return _background->dataMedia->progress(); - } else if (const auto thumbnail = _background->data.thumbnail()) { + } else if (const auto thumbnail = _background->data.localThumbnail()) { return thumbnail->progress(); } } @@ -1415,7 +1417,13 @@ void MainWidget::checkChatBackground() { } Image *MainWidget::newBackgroundThumb() { - return _background ? _background->data.thumbnail() : nullptr; + return !_background + ? nullptr + : _background->data.localThumbnail() + ? _background->data.localThumbnail() + : _background->dataMedia + ? _background->dataMedia->thumbnail() + : nullptr; } void MainWidget::messageDataReceived(ChannelData *channel, MsgId msgId) { diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp index 4f6a6ab5a..c320a3492 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user_photos.h" #include "data/data_photo.h" #include "data/data_document.h" +#include "data/data_document_media.h" #include "data/data_media_types.h" #include "data/data_session.h" #include "data/data_web_page.h" @@ -133,6 +134,11 @@ public: Image *image, Data::FileOrigin origin, Fn handler); + Thumb( + Key key, + not_null document, + Data::FileOrigin origin, + Fn handler); int leftToUpdate() const; int rightToUpdate() const; @@ -158,6 +164,7 @@ private: ClickHandlerPtr _link; const Key _key; + std::shared_ptr _documentMedia; Image *_image = nullptr; Data::FileOrigin _origin; State _state = State::Alive; @@ -186,6 +193,22 @@ GroupThumbs::Thumb::Thumb( validateImage(); } +GroupThumbs::Thumb::Thumb( + Key key, + not_null document, + Data::FileOrigin origin, + Fn handler) +: _key(key) +, _documentMedia(document->createMediaView()) +, _origin(origin) { + _link = std::make_shared(std::move(handler)); + _fullWidth = std::min( + wantedPixSize().width(), + st::mediaviewGroupWidthMax); + _documentMedia->thumbnailWanted(origin); + validateImage(); +} + QSize GroupThumbs::Thumb::wantedPixSize() const { const auto originalWidth = _image ? std::max(_image->width(), 1) : 1; const auto originalHeight = _image ? std::max(_image->height(), 1) : 1; @@ -195,6 +218,9 @@ QSize GroupThumbs::Thumb::wantedPixSize() const { } void GroupThumbs::Thumb::validateImage() { + if (!_image && _documentMedia) { + _image = _documentMedia->thumbnail(); + } if (!_full.isNull() || !_image) { return; } @@ -524,7 +550,7 @@ auto GroupThumbs::createThumb(Key key) if (const auto photo = media->photo()) { return createThumb(key, photo->thumbnail()); } else if (const auto document = media->document()) { - return createThumb(key, document->thumbnail()); + return createThumb(key, document); } } } @@ -559,7 +585,7 @@ auto GroupThumbs::createThumb( if (const auto photo = base::get_if(&item)) { return createThumb(key, (*photo)->thumbnail()); } else if (const auto document = base::get_if(&item)) { - return createThumb(key, (*document)->thumbnail()); + return createThumb(key, (*document)); } return createThumb(key, nullptr); } @@ -575,6 +601,17 @@ auto GroupThumbs::createThumb(Key key, Image *image) }); } +auto GroupThumbs::createThumb(Key key, not_null document) +-> std::unique_ptr { + const auto weak = base::make_weak(this); + const auto origin = ComputeFileOrigin(key, _context); + return std::make_unique(key, document, origin, [=] { + if (const auto strong = weak.get()) { + strong->_activateStream.fire_copy(key); + } + }); +} + auto GroupThumbs::validateCacheEntry(Key key) -> not_null { const auto i = _cache.find(key); return (i != _cache.end()) diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h index dfd54da50..3126d1ba3 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h @@ -101,6 +101,9 @@ private: const WebPageCollage &collage, int index); std::unique_ptr createThumb(Key key, Image *image); + std::unique_ptr createThumb( + Key key, + not_null document); void update(); void countUpdatedRect(); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 9d97db4f6..6f9d83c6e 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1979,6 +1979,8 @@ void OverlayWidget::displayDocument( _doc = doc; if (_doc) { _docMedia = _doc->createMediaView(); + _docMedia->goodThumbnailWanted(); + _docMedia->thumbnailWanted(fileOrigin()); } _rotation = _doc ? _doc->owner().mediaRotation().get(_doc) : 0; _themeCloudData = cloud; @@ -1990,8 +1992,8 @@ void OverlayWidget::displayDocument( if (_doc->sticker()) { if (const auto image = _docMedia->getStickerLarge()) { _staticContent = image->pix(fileOrigin()); - } else if (_doc->hasThumbnail()) { - _staticContent = _doc->thumbnail()->pixBlurred( + } else if (const auto thumbnail = _docMedia->thumbnail()) { + _staticContent = thumbnail->pixBlurred( fileOrigin(), _doc->dimensions.width(), _doc->dimensions.height()); @@ -2036,7 +2038,8 @@ void OverlayWidget::displayDocument( } } else { _doc->loadThumbnail(fileOrigin()); - int32 tw = _doc->thumbnail()->width(), th = _doc->thumbnail()->height(); + const auto tw = _docMedia->thumbnailSize().width(); + const auto th = _docMedia->thumbnailSize().height(); if (!tw || !th) { _docThumbx = _docThumby = _docThumbw = 0; } else if (tw > th) { @@ -2187,22 +2190,18 @@ void OverlayWidget::startStreamingPlayer() { void OverlayWidget::initStreamingThumbnail() { Expects(_doc != nullptr); - const auto media = _doc->activeMediaView(); - const auto good = media ? media->goodThumbnail() : nullptr; + const auto good = _docMedia->goodThumbnail(); const auto useGood = (good && good->loaded()); - const auto thumb = _doc->thumbnail(); - const auto useThumb = (thumb && thumb->loaded()); - - // #TODO optimize - const auto blurred = media ? media->thumbnailInline() : nullptr; - + const auto thumbnail = _docMedia->thumbnail(); + const auto useThumb = (thumbnail != nullptr); + const auto blurred = _docMedia->thumbnailInline(); if (good && !useGood) { good->load({}); - } else if (thumb && !useThumb) { - thumb->load(fileOrigin()); + } else if (thumbnail) { + thumbnail->load(fileOrigin()); } const auto size = useGood ? good->size() : _doc->dimensions; - if (!useGood && !thumb && !blurred) { + if (!useGood && !thumbnail && !blurred) { return; } else if (size.isEmpty()) { return; @@ -2214,7 +2213,7 @@ void OverlayWidget::initStreamingThumbnail() { _staticContent = (useGood ? good : useThumb - ? thumb + ? thumbnail : blurred ? blurred : Image::BlankMedia().get())->pixNoCache( @@ -2827,9 +2826,9 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { p.drawText(_docIconRect.x() + (_docIconRect.width() - _docExtWidth) / 2, _docIconRect.y() + st::mediaviewFileExtTop + st::mediaviewFileExtFont->ascent, _docExt); } } - } else { + } else if (const auto thumbnail = _docMedia->thumbnail()) { int32 rf(cIntRetinaFactor()); - p.drawPixmap(_docIconRect.topLeft(), _doc->thumbnail()->pix(fileOrigin(), _docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mediaviewFileIconSize * rf, st::mediaviewFileIconSize * rf)); + p.drawPixmap(_docIconRect.topLeft(), thumbnail->pix(fileOrigin(), _docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mediaviewFileIconSize * rf, st::mediaviewFileIconSize * rf)); } paintRadialLoading(p, radial, radialOpacity); diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index a6f564ea8..bedd02522 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -1371,13 +1371,13 @@ QImage Pip::videoFrame(const FrameRequest &request) const { return _instance.frame(request); } const auto &cover = _instance.info().video.cover; + + // #TODO optimize always use when available const auto media = _data->activeMediaView(); const auto good = media ? media->goodThumbnail() : nullptr; const auto useGood = (good && good->loaded()); - const auto thumb = _data->thumbnail(); + const auto thumb = media ? media->thumbnail() : nullptr; const auto useThumb = (thumb && thumb->loaded()); - - // #TODO optimize always use when available const auto blurred = media ? media->thumbnailInline() : nullptr; const auto state = !cover.isNull() diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 85e47e3da..f3ae9c434 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -195,12 +195,13 @@ const style::RoundCheckbox &ItemBase::checkboxStyle() const { } void ItemBase::ensureCheckboxCreated() { - if (!_check) { - const auto repaint = [=] { - _parent->history()->session().data().requestItemRepaint(_parent); - }; - _check = std::make_unique(repaint, checkboxStyle()); + if (_check) { + return; } + const auto repaint = [=] { + _parent->history()->session().data().requestItemRepaint(_parent); + }; + _check = std::make_unique(repaint, checkboxStyle()); } ItemBase::~ItemBase() = default; @@ -255,11 +256,12 @@ void RadialProgressItem::radialAnimationCallback(crl::time now) const { } void RadialProgressItem::ensureRadial() { - if (!_radial) { - _radial = std::make_unique([=](crl::time now) { - radialAnimationCallback(now); - }); + if (_radial) { + return; } + _radial = std::make_unique([=](crl::time now) { + radialAnimationCallback(now); + }); } void RadialProgressItem::checkRadialFinished() const { @@ -438,8 +440,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const const auto selected = (selection == FullSelection); const auto blurred = _dataMedia->thumbnailInline(); - const auto thumbLoaded = _data->hasThumbnail() - && _data->thumbnail()->loaded(); + const auto thumbnail = _dataMedia->thumbnail(); const auto goodLoaded = _dataMedia->goodThumbnail() && _dataMedia->goodThumbnail()->loaded(); @@ -454,14 +455,14 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const const auto radial = isRadialAnimation(); const auto radialOpacity = radial ? _radial->opacity() : 0.; - if ((blurred || thumbLoaded || goodLoaded) + if ((blurred || thumbnail || goodLoaded) && ((_pix.width() != _width * cIntRetinaFactor()) - || (_pixBlurred && (thumbLoaded || goodLoaded)))) { + || (_pixBlurred && (thumbnail || goodLoaded)))) { auto size = _width * cIntRetinaFactor(); auto img = goodLoaded ? _dataMedia->goodThumbnail()->original() - : thumbLoaded - ? _data->thumbnail()->original() + : thumbnail + ? thumbnail->original() : Images::prepareBlur(blurred->original()); if (img.width() == img.height()) { if (img.width() != size) { @@ -475,7 +476,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const img.setDevicePixelRatio(cRetinaFactor()); _pix = App::pixmapFromImageInPlace(std::move(img)); - _pixBlurred = !(thumbLoaded || goodLoaded); + _pixBlurred = !(thumbnail || goodLoaded); } if (_pix.isNull()) { @@ -549,6 +550,7 @@ void Video::ensureDataMediaCreated() const { } _dataMedia = _data->createMediaView(); _dataMedia->goodThumbnailWanted(); + _dataMedia->thumbnailWanted(parent()->fullId()); } float64 Video::dataProgress() const { @@ -679,15 +681,17 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const if (_data->hasThumbnail()) { ensureDataMediaCreated(); } - p.setPen(Qt::NoPen); - const auto thumbLoaded = _data->hasThumbnail() - && _data->thumbnail()->loaded(); + const auto thumbnail = _dataMedia + ? _dataMedia->thumbnail() + : nullptr; const auto blurred = _dataMedia ? _dataMedia->thumbnailInline() : nullptr; - if (thumbLoaded || blurred) { - const auto thumb = thumbLoaded - ? _data->thumbnail()->pixCircled( + + p.setPen(Qt::NoPen); + if (thumbnail || blurred) { + const auto thumb = thumbnail + ? thumbnail->pixCircled( parent()->fullId(), inner.width(), inner.height()) @@ -707,7 +711,7 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const ? _openl : _savel; if (selected) { - p.setBrush((thumbLoaded || blurred) ? st::msgDateImgBgSelected : st::msgFileInBgSelected); + p.setBrush((thumbnail || blurred) ? st::msgDateImgBgSelected : st::msgFileInBgSelected); } else if (_data->hasThumbnail()) { auto over = ClickHandler::showAsActive(checkLink); p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, _a_iconOver.value(over ? 1. : 0.))); @@ -931,8 +935,8 @@ Document::Document( if (withThumb()) { _data->loadThumbnail(parent->fullId()); - auto tw = style::ConvertScale(_data->thumbnail()->width()); - auto th = style::ConvertScale(_data->thumbnail()->height()); + auto tw = style::ConvertScale(_data->thumbnailLocation().width()); + auto th = style::ConvertScale(_data->thumbnailLocation().height()); if (tw > th) { _thumbw = (tw * _st.fileThumbSize) / th; } else { @@ -1045,16 +1049,18 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con if (clip.intersects(rthumb)) { if (wthumb) { ensureDataMediaCreated(); - const auto thumbLoaded = _data->thumbnail()->loaded(); + const auto thumbnail = _dataMedia->thumbnail(); + const auto thumbLoaded = (thumbnail != nullptr); const auto blurred = _dataMedia->thumbnailInline(); - if (thumbLoaded || blurred) { - if (_thumb.isNull() || (thumbLoaded && !_thumbLoaded)) { - _thumbLoaded = thumbLoaded; - auto options = Images::Option::Smooth | Images::Option::None; - if (!_thumbLoaded) options |= Images::Option::Blurred; - _thumb = (_thumbLoaded - ? _data->thumbnail() - : blurred)->pixNoCache(parent()->fullId(), _thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize); + if (thumbnail || blurred) { + if (_thumb.isNull() || (thumbnail && !_thumbLoaded)) { + _thumbLoaded = (thumbnail != nullptr); + auto options = Images::Option::Smooth + | (_thumbLoaded + ? Images::Option::None + : Images::Option::Blurred); + const auto image = thumbnail ? thumbnail : blurred; + _thumb = image->pixNoCache(parent()->fullId(), _thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize); } p.drawPixmap(rthumb.topLeft(), _thumb); } else { @@ -1307,6 +1313,7 @@ void Document::ensureDataMediaCreated() const { return; } _dataMedia = _data->createMediaView(); + _dataMedia->thumbnailWanted(parent()->fullId()); } float64 Document::dataProgress() const { @@ -1332,8 +1339,6 @@ bool Document::iconAnimated() const { bool Document::withThumb() const { return !_data->isSong() && _data->hasThumbnail() - && _data->thumbnail()->width() - && _data->thumbnail()->height() && !Data::IsExecutableName(_data->filename()); } @@ -1465,9 +1470,9 @@ Link::Link( th = style::ConvertScale(_page->photo->height()); } else if (_page && _page->document && _page->document->hasThumbnail()) { _page->document->loadThumbnail(parent->fullId()); - - tw = style::ConvertScale(_page->document->thumbnail()->width()); - th = style::ConvertScale(_page->document->thumbnail()->height()); + const auto &location = _page->document->thumbnailLocation(); + tw = style::ConvertScale(location.width()); + th = style::ConvertScale(location.height()); } if (tw > st::linksPhotoSize) { if (th > tw) { @@ -1559,10 +1564,13 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P } p.drawPixmapLeft(pixLeft, pixTop, _width, pix); } else if (_page && _page->document && _page->document->hasThumbnail()) { - auto roundRadius = _page->document->isVideoMessage() - ? ImageRoundRadius::Ellipse - : ImageRoundRadius::Small; - p.drawPixmapLeft(pixLeft, pixTop, _width, _page->document->thumbnail()->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius)); + ensureDocumentMediaCreated(); + if (const auto thumbnail = _documentMedia->thumbnail()) { + auto roundRadius = _page->document->isVideoMessage() + ? ImageRoundRadius::Ellipse + : ImageRoundRadius::Small; + p.drawPixmapLeft(pixLeft, pixTop, _width, thumbnail->pixSingle(parent()->fullId(), _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius)); + } } else { const auto index = _letter.isEmpty() ? 0 @@ -1638,6 +1646,14 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P paintCheckbox(p, { checkLeft, checkTop }, selected, context); } +void Link::ensureDocumentMediaCreated() { + if (_documentMedia) { + return; + } + _documentMedia = _page->document->createMediaView(); + _documentMedia->thumbnailWanted(parent()->fullId()); +} + TextState Link::getState( QPoint point, StateRequest request) const { diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index abe9e42a4..0dea20464 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -364,11 +364,14 @@ protected: const style::RoundCheckbox &checkboxStyle() const override; private: + void ensureDocumentMediaCreated(); + ClickHandlerPtr _photol; QString _title, _letter; int _titlew = 0; WebPageData *_page = nullptr; + std::shared_ptr _documentMedia; int _pixw = 0; int _pixh = 0; Ui::Text::String _text = { st::msgMinWidth }; diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 75ad3fa36..8a64b833e 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -44,9 +44,7 @@ FileLoader::FileLoader( } FileLoader::~FileLoader() { - if (!_finished) { - cancel(); - } + Expects(_finished); } Main::Session &FileLoader::session() const { diff --git a/Telegram/SourceFiles/storage/file_download_mtproto.cpp b/Telegram/SourceFiles/storage/file_download_mtproto.cpp index 118792cf6..6cfc746bd 100644 --- a/Telegram/SourceFiles/storage/file_download_mtproto.cpp +++ b/Telegram/SourceFiles/storage/file_download_mtproto.cpp @@ -78,6 +78,12 @@ mtpFileLoader::mtpFileLoader( { location }) { } +mtpFileLoader::~mtpFileLoader() { + if (!_finished) { + cancel(); + } +} + Data::FileOrigin mtpFileLoader::fileOrigin() const { return DownloadMtprotoTask::fileOrigin(); } diff --git a/Telegram/SourceFiles/storage/file_download_mtproto.h b/Telegram/SourceFiles/storage/file_download_mtproto.h index 0906d47d0..2cc2c73e4 100644 --- a/Telegram/SourceFiles/storage/file_download_mtproto.h +++ b/Telegram/SourceFiles/storage/file_download_mtproto.h @@ -36,6 +36,7 @@ public: LoadFromCloudSetting fromCloud, bool autoLoading, uint8 cacheTag); + ~mtpFileLoader(); Data::FileOrigin fileOrigin() const override; uint64 objId() const override; diff --git a/Telegram/SourceFiles/storage/file_download_web.cpp b/Telegram/SourceFiles/storage/file_download_web.cpp index 5d1878382..097912ad0 100644 --- a/Telegram/SourceFiles/storage/file_download_web.cpp +++ b/Telegram/SourceFiles/storage/file_download_web.cpp @@ -453,7 +453,9 @@ webFileLoader::webFileLoader( } webFileLoader::~webFileLoader() { - cancelRequest(); + if (!_finished) { + cancel(); + } } QString webFileLoader::url() const { diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 55b4c7eb4..bfc611b03 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -3945,11 +3945,12 @@ void importOldRecentStickers() { attributes, mime, QByteArray(), - ImagePtr(), + StorageImageLocation(), dc, - size, - StorageImageLocation()); - if (!doc->sticker()) continue; + size); + if (!doc->sticker()) { + continue; + } if (value > 0) { def.stickers.push_back(doc); diff --git a/Telegram/SourceFiles/storage/serialize_document.cpp b/Telegram/SourceFiles/storage/serialize_document.cpp index 0be4e1592..c29391514 100644 --- a/Telegram/SourceFiles/storage/serialize_document.cpp +++ b/Telegram/SourceFiles/storage/serialize_document.cpp @@ -46,14 +46,10 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) { stream << qint32(StickerSetTypeEmpty); } break; } - writeStorageImageLocation(stream, document->sticker()->loc); + writeStorageImageLocation(stream, document->_thumbnailLocation); } else { stream << qint32(document->getDuration()); - if (const auto thumb = document->thumbnail()) { - writeStorageImageLocation(stream, thumb->location()); - } else { - writeStorageImageLocation(stream, StorageImageLocation()); - } + writeStorageImageLocation(stream, document->thumbnailLocation()); } } @@ -147,10 +143,9 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & attributes, mime, QByteArray(), - Images::Create(*thumb), + *thumb, dc, - size, - *thumb); + size); } DocumentData *Document::readStickerFromStream(int streamAppVersion, QDataStream &stream, const StickerSetInfo &info) { @@ -176,18 +171,12 @@ int Document::sizeInStream(DocumentData *document) { if (auto sticker = document->sticker()) { // type == StickerDocument // + altlen + alt + type-of-set result += stringSize(sticker->alt) + sizeof(qint32); - // + sticker loc - result += Serialize::storageImageLocationSize(document->sticker()->loc); } else { // + duration result += sizeof(qint32); - // + thumb loc - if (const auto thumb = document->thumbnail()) { - result += Serialize::storageImageLocationSize(thumb->location()); - } else { - result += Serialize::storageImageLocationSize(StorageImageLocation()); - } } + // + thumb loc + result += Serialize::storageImageLocationSize(document->thumbnailLocation()); return result; } diff --git a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp index db3558efa..3cd0a6eb1 100644 --- a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp +++ b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp @@ -63,7 +63,9 @@ StreamedFileDownloader::StreamedFileDownloader( } StreamedFileDownloader::~StreamedFileDownloader() { - cancelHook(); + if (!_finished) { + cancel(); + } } uint64 StreamedFileDownloader::objId() const { diff --git a/Telegram/SourceFiles/window/window_media_preview.cpp b/Telegram/SourceFiles/window/window_media_preview.cpp index ea2cb7064..1f142afe9 100644 --- a/Telegram/SourceFiles/window/window_media_preview.cpp +++ b/Telegram/SourceFiles/window/window_media_preview.cpp @@ -116,6 +116,7 @@ void MediaPreviewWidget::showPreview( _photo = nullptr; _document = document; _documentMedia = _document->createMediaView(); + _documentMedia->thumbnailWanted(_origin); fillEmojiString(); resetGifAndCache(); } @@ -255,9 +256,9 @@ QPixmap MediaPreviewWidget::currentImage() const { _cacheStatus = CacheLoaded; } else if (_cacheStatus != CacheThumbLoaded && _document->hasThumbnail() - && _document->thumbnail()->loaded()) { + && _documentMedia->thumbnail()) { QSize s = currentDimensions(); - _cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height()); + _cache = _documentMedia->thumbnail()->pixBlurred(_origin, s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } } @@ -280,14 +281,13 @@ QPixmap MediaPreviewWidget::currentImage() const { if (_cacheStatus != CacheThumbLoaded && _document->hasThumbnail()) { QSize s = currentDimensions(); - if (_document->thumbnail()->loaded()) { - _cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height()); + const auto thumbnail = _documentMedia->thumbnail(); + if (thumbnail) { + _cache = thumbnail->pixBlurred(_origin, s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } else if (const auto blurred = _documentMedia->thumbnailInline()) { - _cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height()); + _cache = blurred->pixBlurred(_origin, s.width(), s.height()); _cacheStatus = CacheThumbLoaded; - } else { - _document->thumbnail()->load(_origin); } } }