Start DocumentData::thumbnail move to DocumentMedia.

This commit is contained in:
John Preston 2020-04-15 18:06:34 +04:00
parent 1329870c8e
commit 956c3af0ae
37 changed files with 511 additions and 312 deletions

View File

@ -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<Data::DocumentMedia> 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(

View File

@ -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) {

View File

@ -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) {

View File

@ -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<Window::SessionController*> _controller;
FullMsgId _msgId;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
Image *_thumbnailImage = nullptr;
bool _thumbnailImageLoaded = false;
Fn<void()> _refreshThumbnail;
@ -95,7 +96,6 @@ private:
bool _doc = false;
QPixmap _thumb;
std::shared_ptr<Data::DocumentMedia> _gifMedia;
Media::Clip::ReaderPointer _gifPreview;
object_ptr<Ui::InputField> _field = { nullptr };

View File

@ -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);
}
}

View File

@ -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<StickerIcon> &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) {

View File

@ -452,6 +452,7 @@ DocumentData::DocumentData(not_null<Data::Session*> 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<StickerData>();
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<mtpFileLoader>(
_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<Data::ReplyPreview>(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,

View File

@ -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<Flag>;
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<Data::Session*> _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<FileLoader> _thumbnailLoader;
int _thumbnailSize = 0;
std::unique_ptr<Data::ReplyPreview> _replyPreview;
std::weak_ptr<Data::DocumentMedia> _media;
PhotoData *_goodThumbnailPhoto = nullptr;
not_null<Data::Session*> _owner;
FileLocation _location;
std::unique_ptr<DocumentAdditionalData> _additional;
int32 _duration = -1;
mutable Flags _flags = kStreamingSupportedUnknown;
GoodThumbnailState _goodThumbnailState = GoodThumbnailState();
mutable std::unique_ptr<FileLoader> _loader;
std::unique_ptr<FileLoader> _loader;
};

View File

@ -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<Image>(
std::make_unique<Images::ImageSource>(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();
}

View File

@ -21,10 +21,14 @@ public:
[[nodiscard]] not_null<DocumentData*> 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<DocumentData*> document,
QByteArray data);
[[nodiscard]] bool thumbnailEnoughForSticker() const;
const not_null<DocumentData*> _owner;
std::unique_ptr<Image> _goodThumbnail;
mutable std::unique_ptr<Image> _inlineThumbnail;
std::unique_ptr<Image> _thumbnail;
std::unique_ptr<Image> _sticker;
QByteArray _bytes;
Flags _flags;

View File

@ -60,16 +60,15 @@ void ReplyPreview::prepare(not_null<Image*> 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);
}

View File

@ -2381,9 +2381,11 @@ not_null<DocumentData*> 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<DocumentData*> 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<DocumentData*> Session::document(
const QVector<MTPDocumentAttribute> &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<DocumentData*> 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<DocumentId>(),
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<DocumentId>(),
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<MTPDocumentAttribute> &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<WebPageData*> Session::webpage(WebPageId id) {

View File

@ -499,10 +499,9 @@ public:
const QVector<MTPDocumentAttribute> &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<DocumentData*> original,
const MTPDocument &data);
@ -754,10 +753,9 @@ private:
const QVector<MTPDocumentAttribute> &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);

View File

@ -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());
}

View File

@ -22,7 +22,7 @@ public:
[[nodiscard]] WallPaperId id() const;
[[nodiscard]] std::optional<QColor> 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;

View File

@ -613,6 +613,7 @@ void Element::checkHeavyPart() {
}
void Element::unloadHeavyPart() {
history()->owner().unregisterHeavyViewPart(this);
if (_media) {
_media->unloadHeavyPart();
}

View File

@ -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<HistoryDocumentThumbed>();
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<HistoryDocumentThumbed>()) {
_dataMedia->thumbnailWanted(_realParent->fullId());
}
history()->owner().registerHeavyViewPart(_parent);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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*> 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<DocumentData*> 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*> context, Result *result) : FileBase(context, result)
Video::Video(not_null<Context*> 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*> 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<DocumentData*> document) const {
return;
}
_dataMedia = document->createMediaView();
_dataMedia->thumbnailWanted(fileOrigin());
}
void Game::validateThumbnail(Image *image, QSize size, bool good) const {

View File

@ -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<Data::DocumentMedia> _documentMedia;
Ui::Text::String _title, _description;
QString _duration;
int _durationWidth = 0;
[[nodiscard]] bool withThumbnail() const;
void prepareThumbnail(QSize size) const;
};

View File

@ -1330,6 +1330,8 @@ void MainWidget::setChatBackground(
_background = std::make_unique<SettingBackground>(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) {

View File

@ -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<void()> handler);
Thumb(
Key key,
not_null<DocumentData*> document,
Data::FileOrigin origin,
Fn<void()> handler);
int leftToUpdate() const;
int rightToUpdate() const;
@ -158,6 +164,7 @@ private:
ClickHandlerPtr _link;
const Key _key;
std::shared_ptr<Data::DocumentMedia> _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<DocumentData*> document,
Data::FileOrigin origin,
Fn<void()> handler)
: _key(key)
, _documentMedia(document->createMediaView())
, _origin(origin) {
_link = std::make_shared<LambdaClickHandler>(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<PhotoData*>(&item)) {
return createThumb(key, (*photo)->thumbnail());
} else if (const auto document = base::get_if<DocumentData*>(&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<DocumentData*> document)
-> std::unique_ptr<Thumb> {
const auto weak = base::make_weak(this);
const auto origin = ComputeFileOrigin(key, _context);
return std::make_unique<Thumb>(key, document, origin, [=] {
if (const auto strong = weak.get()) {
strong->_activateStream.fire_copy(key);
}
});
}
auto GroupThumbs::validateCacheEntry(Key key) -> not_null<Thumb*> {
const auto i = _cache.find(key);
return (i != _cache.end())

View File

@ -101,6 +101,9 @@ private:
const WebPageCollage &collage,
int index);
std::unique_ptr<Thumb> createThumb(Key key, Image *image);
std::unique_ptr<Thumb> createThumb(
Key key,
not_null<DocumentData*> document);
void update();
void countUpdatedRect();

View File

@ -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);

View File

@ -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()

View File

@ -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<Checkbox>(repaint, checkboxStyle());
if (_check) {
return;
}
const auto repaint = [=] {
_parent->history()->session().data().requestItemRepaint(_parent);
};
_check = std::make_unique<Checkbox>(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<Ui::RadialAnimation>([=](crl::time now) {
radialAnimationCallback(now);
});
if (_radial) {
return;
}
_radial = std::make_unique<Ui::RadialAnimation>([=](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 {

View File

@ -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<Data::DocumentMedia> _documentMedia;
int _pixw = 0;
int _pixh = 0;
Ui::Text::String _text = { st::msgMinWidth };

View File

@ -44,9 +44,7 @@ FileLoader::FileLoader(
}
FileLoader::~FileLoader() {
if (!_finished) {
cancel();
}
Expects(_finished);
}
Main::Session &FileLoader::session() const {

View File

@ -78,6 +78,12 @@ mtpFileLoader::mtpFileLoader(
{ location }) {
}
mtpFileLoader::~mtpFileLoader() {
if (!_finished) {
cancel();
}
}
Data::FileOrigin mtpFileLoader::fileOrigin() const {
return DownloadMtprotoTask::fileOrigin();
}

View File

@ -36,6 +36,7 @@ public:
LoadFromCloudSetting fromCloud,
bool autoLoading,
uint8 cacheTag);
~mtpFileLoader();
Data::FileOrigin fileOrigin() const override;
uint64 objId() const override;

View File

@ -453,7 +453,9 @@ webFileLoader::webFileLoader(
}
webFileLoader::~webFileLoader() {
cancelRequest();
if (!_finished) {
cancel();
}
}
QString webFileLoader::url() const {

View File

@ -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);

View File

@ -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;
}

View File

@ -63,7 +63,9 @@ StreamedFileDownloader::StreamedFileDownloader(
}
StreamedFileDownloader::~StreamedFileDownloader() {
cancelHook();
if (!_finished) {
cancel();
}
}
uint64 StreamedFileDownloader::objId() const {

View File

@ -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);
}
}
}