Move inline thumbnail image to DocumentMedia.

This commit is contained in:
John Preston 2020-04-08 19:09:29 +04:00
parent 6ca43153bb
commit bdd3c51ab8
32 changed files with 432 additions and 283 deletions

View File

@ -396,6 +396,8 @@ PRIVATE
data/data_poll.h
data/data_pts_waiter.cpp
data/data_pts_waiter.h
data/data_reply_preview.cpp
data/data_reply_preview.h
data/data_search_controller.cpp
data/data_search_controller.h
data/data_session.cpp

View File

@ -442,7 +442,7 @@ void GifsListWidget::processPanelHideFinished() {
if (const auto result = item->getResult()) {
result->unload();
}
item->unloadAnimation();
item->unloadHeavyPart();
};
// Preserve panel state through visibility toggles.
//clearInlineRows(false);

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_streaming.h"
#include "data/data_document_good_thumbnail.h"
#include "data/data_document_media.h"
#include "data/data_reply_preview.h"
#include "lang/lang_keys.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "main/main_session.h"
@ -470,6 +471,12 @@ DocumentData::DocumentData(not_null<Data::Session*> owner, DocumentId id)
, _owner(owner) {
}
DocumentData::~DocumentData() {
destroyLoader();
unload();
ActiveCache().remove(this);
}
Data::Session &DocumentData::owner() const {
return *_owner;
}
@ -616,10 +623,11 @@ bool DocumentData::checkWallPaperProperties() {
}
void DocumentData::updateThumbnails(
ImagePtr thumbnailInline,
const QByteArray &inlineThumbnailBytes,
ImagePtr thumbnail) {
if (thumbnailInline && !_thumbnailInline) {
_thumbnailInline = thumbnailInline;
if (!inlineThumbnailBytes.isEmpty()
&& _inlineThumbnailBytes.isEmpty()) {
_inlineThumbnailBytes = inlineThumbnailBytes;
}
if (thumbnail
&& (!_thumbnail
@ -642,10 +650,6 @@ bool DocumentData::hasThumbnail() const {
return !_thumbnail->isNull();
}
Image *DocumentData::thumbnailInline() const {
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
}
Image *DocumentData::thumbnail() const {
return _thumbnail ? _thumbnail.get() : nullptr;
}
@ -750,7 +754,6 @@ void DocumentData::unload() {
// Also, you can't unload() images that you don't own
// from the destructor, because they're already destroyed.
//
//_thumbnailInline->unload();
//_thumbnail->unload();
if (sticker()) {
if (sticker()->image) {
@ -758,7 +761,7 @@ void DocumentData::unload() {
sticker()->image = nullptr;
}
}
_replyPreview.clear();
_replyPreview = nullptr;
if (!_data.isEmpty()) {
ActiveCache().decrement(_data.size());
_data.clear();
@ -1192,28 +1195,10 @@ bool DocumentData::isStickerSetInstalled() const {
Image *DocumentData::getReplyPreview(Data::FileOrigin origin) {
if (!_thumbnail) {
return nullptr;
} else if (_replyPreview
&& (_replyPreview.good() || !_thumbnail->loaded())) {
return _replyPreview.image();
} else if (!_replyPreview) {
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
}
const auto option = isVideoMessage()
? Images::Option::Circled
: Images::Option::None;
if (_thumbnail->loaded()) {
_replyPreview.prepare(
_thumbnail.get(),
origin,
option);
} else {
_thumbnail->load(origin);
if (_thumbnailInline) {
_replyPreview.prepare(
_thumbnailInline.get(),
origin,
option | Images::Option::Blurred);
}
}
return _replyPreview.image();
return _replyPreview->image(origin);
}
StickerData *DocumentData::sticker() const {
@ -1653,12 +1638,6 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
}
}
DocumentData::~DocumentData() {
destroyLoader();
unload();
ActiveCache().remove(this);
}
QString DocumentData::ComposeNameString(
const QString &filename,
const QString &songTitle,

View File

@ -33,6 +33,7 @@ class Loader;
namespace Data {
class Session;
class DocumentMedia;
class ReplyPreview;
} // namespace Data
namespace Main {
@ -84,9 +85,10 @@ namespace Serialize {
class Document;
} // namespace Serialize;
class DocumentData {
class DocumentData final {
public:
DocumentData(not_null<Data::Session*> owner, DocumentId id);
~DocumentData();
[[nodiscard]] Data::Session &owner() const;
[[nodiscard]] Main::Session &session() const;
@ -175,12 +177,15 @@ public:
[[nodiscard]] bool hasThumbnail() const;
void loadThumbnail(Data::FileOrigin origin);
[[nodiscard]] Image *thumbnailInline() const;
[[nodiscard]] Image *thumbnail() const;
void updateThumbnails(
ImagePtr thumbnailInline,
const QByteArray &inlineThumbnailBytes,
ImagePtr thumbnail);
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
return _inlineThumbnailBytes;
}
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
[[nodiscard]] bool goodThumbnailChecked() const;
[[nodiscard]] bool goodThumbnailGenerating() const;
@ -242,8 +247,6 @@ public:
void setInappPlaybackFailed();
[[nodiscard]] bool inappPlaybackFailed() const;
~DocumentData();
DocumentId id = 0;
DocumentType type = FileDocument;
QSize dimensions;
@ -310,9 +313,9 @@ private:
QString _mimeString;
WebFileLocation _urlLocation;
ImagePtr _thumbnailInline;
QByteArray _inlineThumbnailBytes;
ImagePtr _thumbnail;
Data::ReplyPreview _replyPreview;
std::unique_ptr<Data::ReplyPreview> _replyPreview;
std::weak_ptr<Data::DocumentMedia> _media;
PhotoData *_goodThumbnailPhoto = nullptr;

View File

@ -108,6 +108,19 @@ void DocumentMedia::setGoodThumbnail(QImage thumbnail) {
_owner->session().downloaderTaskFinished().notify();
}
Image *DocumentMedia::thumbnailInline() const {
if (!_inlineThumbnail) {
auto image = Images::FromInlineBytes(_owner->inlineThumbnailBytes());
if (!image.isNull()) {
_inlineThumbnail = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(
std::move(image),
"PNG"));
}
}
return _inlineThumbnail.get();
}
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
const auto data = document->data();
const auto type = document->isWallPaper()

View File

@ -20,8 +20,9 @@ public:
[[nodiscard]] Image *goodThumbnail() const;
void setGoodThumbnail(QImage thumbnail);
[[nodiscard]] Image *thumbnailInline() const;
// For DocumentData.
void validateGoodThumbnail();
static void CheckGoodThumbnail(not_null<DocumentData*> document);
private:
@ -36,6 +37,7 @@ private:
const not_null<DocumentData*> _owner;
std::unique_ptr<Image> _goodThumbnail;
mutable std::unique_ptr<Image> _inlineThumbnail;
Flags _flags;
};

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_reply_preview.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
#include "main/main_session.h"
@ -22,6 +23,8 @@ PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
, _owner(owner) {
}
PhotoData::~PhotoData() = default;
Data::Session &PhotoData::owner() const {
return *_owner;
}
@ -105,37 +108,14 @@ void PhotoData::unload() {
_thumbnailSmall->unload();
_thumbnail->unload();
_large->unload();
_replyPreview.clear();
_replyPreview = nullptr;
}
Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
if (_replyPreview
&& (_replyPreview.good() || !_thumbnailSmall->loaded())) {
return _replyPreview.image();
if (!_replyPreview) {
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
}
if (_thumbnailSmall->isDelayedStorageImage()
&& !_large->isNull()
&& !_large->isDelayedStorageImage()
&& _large->loaded()) {
_replyPreview.prepare(
_large.get(),
origin,
Images::Option(0));
} else if (_thumbnailSmall->loaded()) {
_replyPreview.prepare(
_thumbnailSmall.get(),
origin,
Images::Option(0));
} else {
_thumbnailSmall->load(origin);
if (_thumbnailInline) {
_replyPreview.prepare(
_thumbnailInline.get(),
origin,
Images::Option::Blurred);
}
}
return _replyPreview.image();
return _replyPreview->image(origin);
}
void PhotoData::setRemoteLocation(

View File

@ -15,11 +15,13 @@ class Session;
namespace Data {
class Session;
class ReplyPreview;
} // namespace Data
class PhotoData {
class PhotoData final {
public:
PhotoData(not_null<Data::Session*> owner, PhotoId id);
~PhotoData();
[[nodiscard]] Data::Session &owner() const;
[[nodiscard]] Main::Session &session() const;
@ -97,7 +99,7 @@ private:
int32 _dc = 0;
uint64 _access = 0;
QByteArray _fileReference;
Data::ReplyPreview _replyPreview;
std::unique_ptr<Data::ReplyPreview> _replyPreview;
not_null<Data::Session*> _owner;

View File

@ -0,0 +1,101 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_reply_preview.h"
#include "data/data_file_origin.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_photo.h"
#include "ui/image/image.h"
#include "ui/image/image_source.h"
namespace Data {
ReplyPreview::ReplyPreview(not_null<DocumentData*> document)
: _document(document)
, _documentMedia(_document->createMediaView()) {
}
ReplyPreview::ReplyPreview(not_null<PhotoData*> photo)
: _photo(photo) {
}
void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
if (image->isNull() || !image->loaded()) {
return;
}
int w = image->width(), h = image->height();
if (w <= 0) w = 1;
if (h <= 0) h = 1;
auto thumbSize = (w > h)
? QSize(
w * st::msgReplyBarSize.height() / h,
st::msgReplyBarSize.height())
: QSize(
st::msgReplyBarSize.height(),
h * st::msgReplyBarSize.height() / w);
thumbSize *= cIntRetinaFactor();
const auto prepareOptions = Images::Option::Smooth
| Images::Option::TransparentBackground
| options;
auto outerSize = st::msgReplyBarSize.height();
auto bitmap = image->pixNoCache(
FileOrigin(),
thumbSize.width(),
thumbSize.height(),
prepareOptions,
outerSize,
outerSize);
_image = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(
bitmap.toImage(),
"PNG"));
_good = ((options & Images::Option::Blurred) == 0);
}
Image *ReplyPreview::image(Data::FileOrigin origin) {
if (_document) {
const auto thumbnail = _document->thumbnail();
Assert(thumbnail != nullptr);
if (!_image || (!_good && thumbnail->loaded())) {
const auto option = _document->isVideoMessage()
? Images::Option::Circled
: Images::Option::None;
if (thumbnail->loaded()) {
prepare(thumbnail, option);
} else {
thumbnail->load(origin);
if (const auto image = _documentMedia->thumbnailInline()) {
prepare(image, option | Images::Option::Blurred);
}
}
}
} else {
Assert(_photo != nullptr);
const auto small = _photo->thumbnailSmall();
const auto large = _photo->large();
if (!_image || (!_good && (small->loaded() || large->loaded()))) {
if (small->isDelayedStorageImage()
&& !large->isNull()
&& !large->isDelayedStorageImage()
&& large->loaded()) {
prepare(large, Images::Option(0));
} else if (small->loaded()) {
prepare(small, Images::Option(0));
} else {
small->load(origin);
if (const auto blurred = _photo->thumbnailInline()) {
prepare(blurred, Images::Option::Blurred);
}
}
}
}
return _image.get();
}
} // namespace Data

View File

@ -0,0 +1,36 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class DocumentData;
class PhotoData;
namespace Data {
class DocumentMedia;
struct FileOrigin;
class ReplyPreview {
public:
explicit ReplyPreview(not_null<DocumentData*> document);
explicit ReplyPreview(not_null<PhotoData*> photo);
[[nodiscard]] Image *image(Data::FileOrigin origin);
private:
void prepare(not_null<Image*> image, Images::Options options);
std::unique_ptr<Image> _image;
bool _good = false;
DocumentData *_document = nullptr;
PhotoData *_photo = nullptr;
std::shared_ptr<DocumentMedia> _documentMedia;
};
} // namespace Data

View File

@ -126,19 +126,20 @@ std::vector<UnavailableReason> ExtractUnavailableReasons(
}) | ranges::to_vector;
}
MTPPhotoSize FindDocumentInlineThumbnail(const MTPDdocument &data) {
QByteArray FindDocumentInlineThumbnail(const MTPDdocument &data) {
const auto thumbs = data.vthumbs();
if (!thumbs) {
return MTP_photoSizeEmpty(MTP_string());
return QByteArray();
}
const auto &list = thumbs->v;
const auto i = ranges::find(
list,
mtpc_photoStrippedSize,
&MTPPhotoSize::type);
return (i != list.end())
? (*i)
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
if (i == list.end()) {
return QByteArray();
}
return i->c_photoStrippedSize().vbytes().v;
}
MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
@ -2371,7 +2372,7 @@ not_null<DocumentData*> Session::processDocument(
fields.vdate().v,
fields.vattributes().v,
mime,
ImagePtr(),
QByteArray(),
Images::Create(std::move(thumb), format),
fields.vdc_id().v,
fields.vsize().v,
@ -2388,7 +2389,7 @@ not_null<DocumentData*> Session::document(
TimeId date,
const QVector<MTPDocumentAttribute> &attributes,
const QString &mime,
const ImagePtr &thumbnailInline,
const QByteArray &inlineThumbnailBytes,
const ImagePtr &thumbnail,
int32 dc,
int32 size,
@ -2401,7 +2402,7 @@ not_null<DocumentData*> Session::document(
date,
attributes,
mime,
thumbnailInline,
inlineThumbnailBytes,
thumbnail,
dc,
size,
@ -2476,7 +2477,7 @@ DocumentData *Session::documentFromWeb(
base::unixtime::now(),
data.vattributes().v,
data.vmime_type().v,
ImagePtr(),
QByteArray(),
thumb,
MTP::maindc(),
int32(0), // data.vsize().v
@ -2497,7 +2498,7 @@ DocumentData *Session::documentFromWeb(
base::unixtime::now(),
data.vattributes().v,
data.vmime_type().v,
ImagePtr(),
QByteArray(),
thumb,
MTP::maindc(),
int32(0), // data.vsize().v
@ -2517,7 +2518,7 @@ void Session::documentApplyFields(
void Session::documentApplyFields(
not_null<DocumentData*> document,
const MTPDdocument &data) {
const auto thumbnailInline = FindDocumentInlineThumbnail(data);
const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data);
const auto thumbnailSize = FindDocumentThumbnail(data);
const auto thumbnail = Images::Create(data, thumbnailSize);
documentApplyFields(
@ -2527,7 +2528,7 @@ void Session::documentApplyFields(
data.vdate().v,
data.vattributes().v,
qs(data.vmime_type()),
Images::Create(data, thumbnailInline),
inlineThumbnailBytes,
thumbnail,
data.vdc_id().v,
data.vsize().v,
@ -2541,7 +2542,7 @@ void Session::documentApplyFields(
TimeId date,
const QVector<MTPDocumentAttribute> &attributes,
const QString &mime,
const ImagePtr &thumbnailInline,
const QByteArray &inlineThumbnailBytes,
const ImagePtr &thumbnail,
int32 dc,
int32 size,
@ -2551,7 +2552,7 @@ void Session::documentApplyFields(
}
document->date = date;
document->setMimeString(mime);
document->updateThumbnails(thumbnailInline, thumbnail);
document->updateThumbnails(inlineThumbnailBytes, thumbnail);
document->size = size;
document->setattributes(attributes);

View File

@ -494,7 +494,7 @@ public:
TimeId date,
const QVector<MTPDocumentAttribute> &attributes,
const QString &mime,
const ImagePtr &thumbnailInline,
const QByteArray &inlineThumbnailBytes,
const ImagePtr &thumbnail,
int32 dc,
int32 size,
@ -749,7 +749,7 @@ private:
TimeId date,
const QVector<MTPDocumentAttribute> &attributes,
const QString &mime,
const ImagePtr &thumbnailInline,
const QByteArray &inlineThumbnailBytes,
const ImagePtr &thumbnail,
int32 dc,
int32 size,

View File

@ -8,9 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_types.h"
#include "data/data_document.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "ui/image/image_source.h"
#include "ui/widgets/input_fields.h"
#include "storage/cache/storage_cache_types.h"
#include "base/openssl_help.h"
@ -34,20 +32,6 @@ constexpr auto kGeoPointCacheMask = 0x000000FFFFFFFFFFULL;
} // namespace
struct ReplyPreview::Data {
Data(std::unique_ptr<Images::Source> &&source, bool good);
Image image;
bool good = false;
};
ReplyPreview::Data::Data(
std::unique_ptr<Images::Source> &&source,
bool good)
: image(std::move(source))
, good(good) {
}
Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) {
return Storage::Cache::Key{
Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask),
@ -109,63 +93,6 @@ Storage::Cache::Key GeoPointCacheKey(const GeoPointLocation &location) {
};
}
ReplyPreview::ReplyPreview() = default;
ReplyPreview::ReplyPreview(ReplyPreview &&other) = default;
ReplyPreview &ReplyPreview::operator=(ReplyPreview &&other) = default;
ReplyPreview::~ReplyPreview() = default;
void ReplyPreview::prepare(
not_null<Image*> image,
FileOrigin origin,
Images::Options options) {
int w = image->width(), h = image->height();
if (w <= 0) w = 1;
if (h <= 0) h = 1;
auto thumbSize = (w > h)
? QSize(
w * st::msgReplyBarSize.height() / h,
st::msgReplyBarSize.height())
: QSize(
st::msgReplyBarSize.height(),
h * st::msgReplyBarSize.height() / w);
thumbSize *= cIntRetinaFactor();
const auto prepareOptions = Images::Option::Smooth
| Images::Option::TransparentBackground
| options;
auto outerSize = st::msgReplyBarSize.height();
auto bitmap = image->pixNoCache(
origin,
thumbSize.width(),
thumbSize.height(),
prepareOptions,
outerSize,
outerSize);
_data = std::make_unique<ReplyPreview::Data>(
std::make_unique<Images::ImageSource>(
bitmap.toImage(),
"PNG"),
((options & Images::Option::Blurred) == 0));
}
void ReplyPreview::clear() {
_data = nullptr;
}
Image *ReplyPreview::image() const {
return _data ? &_data->image : nullptr;
}
bool ReplyPreview::good() const {
return !empty() && _data->good;
}
bool ReplyPreview::empty() const {
return !_data;
}
} // namespace Data
uint32 AudioMsgId::CreateExternalPlayId() {

View File

@ -56,33 +56,6 @@ constexpr auto kAnimationCacheTag = uint8(0x05);
struct FileOrigin;
class ReplyPreview {
public:
ReplyPreview();
ReplyPreview(ReplyPreview &&other);
ReplyPreview &operator=(ReplyPreview &&other);
~ReplyPreview();
void prepare(
not_null<Image*> image,
FileOrigin origin,
Images::Options options);
void clear();
[[nodiscard]] Image *image() const;
[[nodiscard]] bool good() const;
[[nodiscard]] bool empty() const;
[[nodiscard]] explicit operator bool() const {
return !empty();
}
private:
struct Data;
std::unique_ptr<Data> _data;
};
} // namespace Data
struct MessageGroupId {

View File

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "data/data_session.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_media_types.h"
#include "data/data_file_origin.h"
#include "app.h"
@ -262,6 +263,8 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
int nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0;
if (auto thumbed = Get<HistoryDocumentThumbed>()) {
ensureDataMediaCreated();
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::msgFileThumbNameTop - topMinus;
nameright = st::msgFileThumbPadding.left();
@ -278,7 +281,7 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
} else {
_data->loadThumbnail(_realParent->fullId());
if (const auto blurred = _data->thumbnailInline()) {
if (const auto blurred = _dataMedia->thumbnailInline()) {
thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
}
}
@ -491,6 +494,24 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
}
}
void Document::checkHeavyPart() {
if (!_dataMedia) {
history()->owner().unregisterHeavyViewPart(_parent);
}
}
void Document::unloadHeavyPart() {
_dataMedia = nullptr;
}
void Document::ensureDataMediaCreated() const {
if (_dataMedia) {
return;
}
_dataMedia = _data->createMediaView();
history()->owner().registerHeavyViewPart(_parent);
}
bool Document::downloadInCorner() const {
return _data->isAudioFile()
&& _data->canBeStreamed()

View File

@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
struct HistoryDocumentNamed;
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Ui {
namespace Text {
class String;
@ -63,6 +67,9 @@ public:
void refreshParentId(not_null<HistoryItem*> realParent) override;
void parentTextUpdated() override;
void checkHeavyPart() override;
void unloadHeavyPart() override;
protected:
float64 dataProgress() const override;
bool dataFinished() const override;
@ -75,6 +82,8 @@ private:
int realDuration = 0;
};
void ensureDataMediaCreated() const;
[[nodiscard]] Ui::Text::String createCaption();
QSize countOptimalSize() override;
@ -93,6 +102,7 @@ private:
StateRequest request) const;
not_null<DocumentData*> _data;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
};

View File

@ -425,7 +425,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
}
} else {
_data->loadThumbnail(_realParent->fullId());
if (const auto blurred = _data->thumbnailInline()) {
if (const auto blurred = _dataMedia->thumbnailInline()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
} else if (!isRound) {
const auto roundTop = (roundCorners & RectPart::TopLeft);
@ -1140,7 +1140,7 @@ void Gif::validateGroupedCache(
? good
: useThumb
? thumb
: _data->thumbnailInline();
: _dataMedia->thumbnailInline();
const auto blur = !useGood
&& (!useThumb
|| (thumb->width() < kUseNonBlurredThreshold

View File

@ -207,8 +207,8 @@ void ThemeDocument::validateThumbnail() const {
}
if (_data->thumbnail()->loaded()) {
prepareThumbnailFrom(_data->thumbnail(), 0);
} else if (const auto blurred = _data->thumbnailInline()) {
if (_thumbnail.isNull()) {
} else if (_thumbnail.isNull()) {
if (const auto blurred = _dataMedia->thumbnailInline()) {
prepareThumbnailFrom(blurred, -1);
}
}

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_document_media.h"
#include "styles/style_overview.h"
#include "styles/style_history.h"
#include "styles/style_chat_helpers.h"
@ -325,13 +326,21 @@ 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(document->thumbnailInline(), size, frame, false);
validateThumbnail(_dataMedia->thumbnailInline(), size, frame, false);
} else {
validateThumbnail(getResultThumb(), size, frame, true);
}
}
void Gif::ensureDataMediaCreated(not_null<DocumentData*> document) const {
if (_dataMedia) {
return;
}
_dataMedia = document->createMediaView();
}
void Gif::ensureAnimation() const {
if (!_animation) {
_animation = std::make_unique<AnimationData>([=](crl::time now) {
@ -367,9 +376,14 @@ void Gif::radialAnimationCallback(crl::time now) const {
}
}
void Gif::unloadHeavyPart() {
unloadAnimation();
getShownDocument()->unload();
_dataMedia = nullptr;
}
void Gif::unloadAnimation() {
_gif.reset();
getShownDocument()->unload();
}
void Gif::clipCallback(Media::Clip::Notification notification) {
@ -1380,11 +1394,19 @@ void Game::prepareThumbnail(QSize size) const {
validateThumbnail(photo->thumbnail(), size, true);
validateThumbnail(photo->thumbnailInline(), size, false);
} else if (const auto document = getResultDocument()) {
ensureDataMediaCreated(document);
validateThumbnail(document->thumbnail(), size, true);
validateThumbnail(document->thumbnailInline(), size, false);
validateThumbnail(_dataMedia->thumbnailInline(), size, false);
}
}
void Game::ensureDataMediaCreated(not_null<DocumentData*> document) const {
if (_dataMedia) {
return;
}
_dataMedia = document->createMediaView();
}
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
if (!image || (_thumbGood && !good)) {
return;
@ -1450,9 +1472,14 @@ void Game::radialAnimationCallback(crl::time now) const {
}
}
void Game::unloadHeavyPart() {
unloadAnimation();
getResultDocument()->unload();
_dataMedia = nullptr;
}
void Game::unloadAnimation() {
_gif.reset();
getResultDocument()->unload();
}
void Game::clipCallback(Media::Clip::Notification notification) {
@ -1464,7 +1491,20 @@ void Game::clipCallback(Media::Clip::Notification notification) {
_gif.setBad();
getResultDocument()->unload();
} else if (_gif->ready() && !_gif->started()) {
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, RectPart::None);
if (_gif->width() * _gif->height() > kMaxInlineArea) {
getResultDocument()->dimensions = QSize(
_gif->width(),
_gif->height());
unloadAnimation();
} else {
_gif->start(
_frameSize.width(),
_frameSize.height(),
st::inlineThumbSize,
st::inlineThumbSize,
ImageRoundRadius::None,
RectPart::None);
}
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
unloadAnimation();
}

View File

@ -18,6 +18,10 @@ namespace Lottie {
class SinglePlayer;
} // namespace Lottie
namespace Data {
class DocumentMedia;
} // namespace Data
namespace InlineBots {
namespace Layout {
namespace internal {
@ -75,23 +79,30 @@ public:
int resizeGetHeight(int width) override;
void unloadAnimation() override;
void unloadHeavyPart() override;
private:
QSize countFrameSize() const;
enum class StateFlag {
Over = (1 << 0),
Over = (1 << 0),
DeleteOver = (1 << 1),
};
using StateFlags = base::flags<StateFlag>;
friend inline constexpr auto is_flag_type(StateFlag) { return true; };
StateFlags _state;
Media::Clip::ReaderPointer _gif;
ClickHandlerPtr _delete;
mutable QPixmap _thumb;
mutable bool _thumbGood = false;
struct AnimationData {
template <typename Callback>
AnimationData(Callback &&callback)
: radial(std::forward<Callback>(callback)) {
}
bool over = false;
Ui::Animations::Simple _a_over;
Ui::RadialAnimation radial;
};
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void unloadAnimation();
QSize countFrameSize() const;
void validateThumbnail(
Image *image,
QSize size,
@ -105,15 +116,15 @@ private:
void clipCallback(Media::Clip::Notification notification);
struct AnimationData {
template <typename Callback>
AnimationData(Callback &&callback)
: radial(std::forward<Callback>(callback)) {
}
bool over = false;
Ui::Animations::Simple _a_over;
Ui::RadialAnimation radial;
};
StateFlags _state;
Media::Clip::ReaderPointer _gif;
ClickHandlerPtr _delete;
mutable QPixmap _thumb;
mutable bool _thumbGood = false;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
mutable std::unique_ptr<AnimationData> _animation;
mutable Ui::Animations::Simple _a_deleteOver;
@ -372,9 +383,11 @@ public:
QPoint point,
StateRequest request) const override;
void unloadAnimation() override;
void unloadHeavyPart() override;
private:
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void unloadAnimation();
void countFrameSize();
void prepareThumbnail(QSize size) const;
@ -386,6 +399,7 @@ private:
void clipCallback(Media::Clip::Notification notification);
Media::Clip::ReaderPointer _gif;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
mutable QPixmap _thumb;
mutable bool _thumbGood = false;
mutable std::unique_ptr<Ui::RadialAnimation> _radial;

View File

@ -80,7 +80,7 @@ public:
PhotoData *getPreviewPhoto() const;
virtual void preload() const;
virtual void unloadAnimation() {
virtual void unloadHeavyPart() {
}
void update() const;

View File

@ -304,7 +304,7 @@ void Inner::hideFinish(bool completely) {
if (const auto result = item->getResult()) {
result->unload();
}
item->unloadAnimation();
item->unloadHeavyPart();
};
clearInlineRows(false);
for (const auto &[result, layout] : _inlineLayouts) {

View File

@ -2183,7 +2183,10 @@ void OverlayWidget::initStreamingThumbnail() {
const auto useGood = (good && good->loaded());
const auto thumb = _doc->thumbnail();
const auto useThumb = (thumb && thumb->loaded());
const auto blurred = _doc->thumbnailInline();
// #TODO optimize
const auto blurred = media ? media->thumbnailInline() : nullptr;
if (good && !useGood) {
good->load({});
} else if (thumb && !useThumb) {

View File

@ -1376,7 +1376,10 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
const auto useGood = (good && good->loaded());
const auto thumb = _data->thumbnail();
const auto useThumb = (thumb && thumb->loaded());
const auto blurred = _data->thumbnailInline();
// #TODO optimize always use when available
const auto blurred = media ? media->thumbnailInline() : nullptr;
const auto state = !cover.isNull()
? ThumbState::Cover
: useGood

View File

@ -437,7 +437,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
ensureDataMediaCreated();
const auto selected = (selection == FullSelection);
const auto blurred = _data->thumbnailInline();
const auto blurred = _dataMedia->thumbnailInline();
const auto thumbLoaded = _data->hasThumbnail()
&& _data->thumbnail()->loaded();
const auto goodLoaded = _dataMedia->goodThumbnail()
@ -672,10 +672,15 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
_st.songThumbSize,
_width);
if (clip.intersects(inner)) {
if (_data->hasThumbnail()) {
ensureDataMediaCreated();
}
p.setPen(Qt::NoPen);
const auto thumbLoaded = _data->hasThumbnail()
&& _data->thumbnail()->loaded();
const auto blurred = _data->thumbnailInline();
const auto blurred = _dataMedia
? _dataMedia->thumbnailInline()
: nullptr;
if (thumbLoaded || blurred) {
const auto thumb = thumbLoaded
? _data->thumbnail()->pixCircled(
@ -826,6 +831,13 @@ TextState Voice::getState(
return result;
}
void Voice::ensureDataMediaCreated() const {
if (_dataMedia) {
return;
}
_dataMedia = _data->createMediaView();
}
float64 Voice::dataProgress() const {
return _data->progress();
}
@ -1023,8 +1035,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
QRect rthumb(style::rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width));
if (clip.intersects(rthumb)) {
if (wthumb) {
ensureDataMediaCreated();
const auto thumbLoaded = _data->thumbnail()->loaded();
const auto blurred = _data->thumbnailInline();
const auto blurred = _dataMedia->thumbnailInline();
if (thumbLoaded || blurred) {
if (_thumb.isNull() || (thumbLoaded && !_thumbLoaded)) {
_thumbLoaded = thumbLoaded;
@ -1279,6 +1292,13 @@ const style::RoundCheckbox &Document::checkboxStyle() const {
return st::overviewSmallCheck;
}
void Document::ensureDataMediaCreated() const {
if (_dataMedia) {
return;
}
_dataMedia = _data->createMediaView();
}
float64 Document::dataProgress() const {
return _data->progress();
}

View File

@ -255,7 +255,7 @@ private:
};
class Voice : public RadialProgressItem {
class Voice final : public RadialProgressItem {
public:
Voice(
not_null<HistoryItem*> parent,
@ -276,9 +276,11 @@ protected:
const style::RoundCheckbox &checkboxStyle() const override;
private:
void ensureDataMediaCreated() const;
int duration() const;
not_null<DocumentData*> _data;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
StatusText _status;
ClickHandlerPtr _namel;
@ -292,7 +294,7 @@ private:
};
class Document : public RadialProgressItem {
class Document final : public RadialProgressItem {
public:
Document(
not_null<HistoryItem*> parent,
@ -305,7 +307,7 @@ public:
QPoint point,
StateRequest request) const override;
virtual DocumentData *getDocument() const override {
DocumentData *getDocument() const override {
return _data;
}
@ -323,7 +325,10 @@ private:
QPoint point,
StateRequest request) const;
void ensureDataMediaCreated() const;
not_null<DocumentData*> _data;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
StatusText _status;
ClickHandlerPtr _msgl, _namel;
@ -342,7 +347,7 @@ private:
};
class Link : public ItemBase {
class Link final : public ItemBase {
public:
Link(
not_null<HistoryItem*> parent,

View File

@ -3942,7 +3942,7 @@ void importOldRecentStickers() {
date,
attributes,
mime,
ImagePtr(),
QByteArray(),
ImagePtr(),
dc,
size,

View File

@ -146,7 +146,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
date,
attributes,
mime,
ImagePtr(),
QByteArray(),
Images::Create(*thumb),
dc,
size,

View File

@ -61,6 +61,56 @@ uint64 SinglePixKey(Options options) {
} // namespace
QImage FromInlineBytes(const QByteArray &bytes) {
if (bytes.size() < 3 || bytes[0] != '\x01') {
return QImage();
}
const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49"
"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c"
"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37"
"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3"
"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff"
"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35"
"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00"
"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01"
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05"
"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06"
"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52"
"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28"
"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53"
"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75"
"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96"
"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6"
"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6"
"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05"
"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41"
"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33"
"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26"
"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a"
"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74"
"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94"
"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4"
"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4"
"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00"
"\x3f\x00";
const char footer[] = "\xff\xd9";
auto real = QByteArray(header, sizeof(header) - 1);
real[164] = bytes[1];
real[166] = bytes[2];
const auto ready = real
+ bytes.mid(3)
+ QByteArray::fromRawData(footer, sizeof(footer) - 1);
return App::readImage(ready);
}
void ClearRemote() {
base::take(StorageImages);
base::take(WebUrlImages);
@ -251,54 +301,7 @@ ImagePtr CreateFromPhotoSize(
data.vh().v),
bytes);
}, [&](const MTPDphotoStrippedSize &data) {
const auto bytes = qba(data.vbytes());
if (bytes.size() < 3 || bytes[0] != '\x01') {
return ImagePtr();
}
const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49"
"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c"
"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37"
"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3"
"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff"
"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35"
"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00"
"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01"
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05"
"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06"
"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52"
"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28"
"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53"
"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75"
"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96"
"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6"
"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6"
"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05"
"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41"
"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33"
"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26"
"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a"
"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74"
"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94"
"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4"
"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4"
"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4"
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00"
"\x3f\x00";
const char footer[] = "\xff\xd9";
auto real = QByteArray(header, sizeof(header) - 1);
real[164] = bytes[1];
real[166] = bytes[2];
const auto ready = real
+ bytes.mid(3)
+ QByteArray::fromRawData(footer, sizeof(footer) - 1);
auto image = App::readImage(ready);
auto image = FromInlineBytes(qba(data.vbytes()));
return !image.isNull()
? Images::Create(std::move(image), "JPG")
: ImagePtr();

View File

@ -13,6 +13,8 @@ class HistoryItem;
namespace Images {
[[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes);
void ClearRemote();
void ClearAll();

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "ui/image/image.h"
#include "ui/emoji_config.h"
#include "lottie/lottie_single_player.h"
@ -114,6 +115,7 @@ void MediaPreviewWidget::showPreview(
_origin = origin;
_photo = nullptr;
_document = document;
_documentMedia = _document->createMediaView();
fillEmojiString();
resetGifAndCache();
}
@ -125,6 +127,7 @@ void MediaPreviewWidget::showPreview(
_origin = origin;
_photo = photo;
_document = nullptr;
_documentMedia = nullptr;
fillEmojiString();
resetGifAndCache();
}
@ -137,7 +140,7 @@ void MediaPreviewWidget::startShow() {
_controller->enableGifPauseReason(Window::GifPauseReason::MediaPreview);
}
_hiding = false;
_a_shown.start([this] { update(); }, 0., 1., st::stickerPreviewDuration);
_a_shown.start([=] { update(); }, 0., 1., st::stickerPreviewDuration);
} else {
update();
}
@ -149,9 +152,10 @@ void MediaPreviewWidget::hidePreview() {
}
if (_gif) _cache = currentImage();
_hiding = true;
_a_shown.start([this] { update(); }, 1., 0., st::stickerPreviewDuration);
_a_shown.start([=] { update(); }, 1., 0., st::stickerPreviewDuration);
_photo = nullptr;
_document = nullptr;
_documentMedia = nullptr;
resetGifAndCache();
}
@ -279,7 +283,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
if (_document->thumbnail()->loaded()) {
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
} else if (const auto blurred = _document->thumbnailInline()) {
} else if (const auto blurred = _documentMedia->thumbnailInline()) {
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
_cacheStatus = CacheThumbLoaded;
} else {

View File

@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h"
#include "ui/rp_widget.h"
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Lottie {
class SinglePlayer;
} // namespace Lottie
@ -55,6 +59,7 @@ private:
bool _hiding = false;
Data::FileOrigin _origin;
DocumentData *_document = nullptr;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
PhotoData *_photo = nullptr;
Media::Clip::ReaderPointer _gif;
std::unique_ptr<Lottie::SinglePlayer> _lottie;