Move sticker image to DocumentMedia.

This commit is contained in:
John Preston 2020-04-09 12:15:47 +04:00
parent bdd3c51ab8
commit 70c79eb6bd
14 changed files with 156 additions and 122 deletions

View file

@ -10,6 +10,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 "lang/lang_keys.h"
#include "chat_helpers/stickers.h"
#include "boxes/confirm_box.h"
@ -72,6 +73,7 @@ protected:
private:
struct Element {
not_null<DocumentData*> document;
std::shared_ptr<Data::DocumentMedia> documentMedia;
Lottie::Animation *animated = nullptr;
Ui::Animations::Simple overAnimation;
};
@ -267,7 +269,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
continue;
}
_pack.push_back(document);
_elements.push_back({ document });
_elements.push_back({ document, document->createMediaView() });
}
for (const auto &pack : data.vpacks().v) {
pack.match([&](const MTPDstickerPack &pack) {
@ -621,7 +623,8 @@ void StickerSetBox::Inner::paintSticker(
const auto &element = _elements[index];
const auto document = element.document;
document->checkStickerSmall();
const auto &media = element.documentMedia;
media->checkStickerSmall();
if (document->sticker()->animated
&& !element.animated
@ -650,7 +653,7 @@ void StickerSetBox::Inner::paintSticker(
frame);
_lottiePlayer->unpause(element.animated);
} else if (const auto image = document->getStickerSmall()) {
} else if (const auto image = media->getStickerSmall()) {
p.drawPixmapLeft(
ppos,
width(),

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/field_autocomplete.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@ -177,7 +178,10 @@ internal::StickerRows FieldAutocomplete::getStickerSuggestions() {
auto result = ranges::view::all(
list
) | ranges::view::transform([](not_null<DocumentData*> sticker) {
return internal::StickerSuggestion{ sticker };
return internal::StickerSuggestion{
sticker,
sticker->createMediaView()
};
}) | ranges::to_vector;
for (auto &suggestion : _srows) {
if (!suggestion.animated) {
@ -634,6 +638,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
auto &sticker = (*_srows)[index];
const auto document = sticker.document;
const auto &media = sticker.documentMedia;
if (!document->sticker()) continue;
if (document->sticker()->animated
@ -649,7 +654,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
App::roundRect(p, QRect(tl, st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
}
document->checkStickerSmall();
media->checkStickerSmall();
auto w = 1;
auto h = 1;
if (sticker.animated && !document->dimensions.isEmpty()) {
@ -680,7 +685,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
if (!paused) {
sticker.animated->markFrameShown();
}
} else if (const auto image = document->getStickerSmall()) {
} else if (const auto image = media->getStickerSmall()) {
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h));
}

View file

@ -26,10 +26,15 @@ namespace Window {
class SessionController;
} // namespace Window
namespace Data {
class DocumentMedia;
} // namespace Data
namespace internal {
struct StickerSuggestion {
not_null<DocumentData*> document;
std::shared_ptr<Data::DocumentMedia> documentMedia;
std::unique_ptr<Lottie::SinglePlayer> animated;
};

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers_list_widget.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_file_origin.h"
@ -184,7 +185,7 @@ auto StickersListWidget::PrepareStickers(const Stickers::Pack &pack)
return ranges::view::all(
pack
) | ranges::view::transform([](DocumentData *document) {
return Sticker{ document };
return Sticker{ document, document->createMediaView() };
}) | ranges::to_vector;
}
@ -1708,6 +1709,7 @@ QSize StickersListWidget::boundingBoxSize() const {
void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section, int index, bool selected, bool deleteSelected) {
auto &sticker = set.stickers[index];
const auto document = sticker.document;
const auto &media = sticker.documentMedia;
if (!document->sticker()) {
return;
}
@ -1727,7 +1729,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
}
document->checkStickerSmall();
media->checkStickerSmall();
auto w = 1;
auto h = 1;
@ -1752,7 +1754,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
frame);
set.lottiePlayer->unpause(sticker.animated);
} else if (const auto image = document->getStickerSmall()) {
} else if (const auto image = media->getStickerSmall()) {
if (image->loaded()) {
p.drawPixmapLeft(
ppos,
@ -2301,9 +2303,10 @@ void StickersListWidget::preloadImages() {
if (++k > _columnCount * (_columnCount + 1)) break;
const auto document = sets[i].stickers[j].document;
const auto &media = sets[i].stickers[j].documentMedia;
if (!document || !document->sticker()) continue;
document->checkStickerSmall();
media->checkStickerSmall();
}
if (k > _columnCount * (_columnCount + 1)) break;
}
@ -2395,7 +2398,10 @@ auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> {
_custom[index] = true;
}
} else if (!_favedStickersMap.contains(document)) {
result.push_back(Sticker{ document });
result.push_back(Sticker{
document,
document->createMediaView()
});
_custom.push_back(custom);
}
};

View file

@ -32,6 +32,10 @@ class MultiPlayer;
class FrameRenderer;
} // namespace Lottie
namespace Data {
class DocumentMedia;
} // namespace Data
namespace ChatHelpers {
struct StickerIcon;
@ -151,6 +155,7 @@ private:
struct Sticker {
not_null<DocumentData*> document;
std::shared_ptr<Data::DocumentMedia> documentMedia;
Lottie::Animation *animated = nullptr;
};

View file

@ -58,12 +58,6 @@ Core::MediaActiveCache<DocumentData> &ActiveCache() {
return Instance;
}
int64 ComputeUsage(StickerData *sticker) {
return (sticker != nullptr && sticker->image != nullptr)
? sticker->image->width() * sticker->image->height() * 4
: 0;
}
QString JoinStringList(const QStringList &list, const QString &separator) {
const auto count = list.size();
if (!count) {
@ -713,7 +707,7 @@ std::shared_ptr<Data::DocumentMedia> DocumentData::createMediaView() {
return result;
}
std::shared_ptr<Data::DocumentMedia> DocumentData::activeMediaView() {
std::shared_ptr<Data::DocumentMedia> DocumentData::activeMediaView() const {
return _media.lock();
}
@ -755,12 +749,6 @@ void DocumentData::unload() {
// from the destructor, because they're already destroyed.
//
//_thumbnail->unload();
if (sticker()) {
if (sticker()->image) {
ActiveCache().decrement(ComputeUsage(sticker()));
sticker()->image = nullptr;
}
}
_replyPreview = nullptr;
if (!_data.isEmpty()) {
ActiveCache().decrement(_data.size());
@ -824,23 +812,14 @@ bool DocumentData::loaded(FilePathResolve resolve) const {
that->_data = _loader->bytes();
ActiveCache().increment(that->_data.size());
if (that->sticker()
&& !that->sticker()->image
&& !_loader->imageData().isNull()) {
that->sticker()->image = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
_data,
_loader->imageFormat(),
_loader->imageData()));
ActiveCache().increment(ComputeUsage(that->sticker()));
}
that->setGoodThumbnailDataReady();
Data::DocumentMedia::CheckGoodThumbnail(that);
if (const auto media = activeMediaView()) {
media->checkStickerLarge(_loader.get());
}
destroyLoader();
if (!that->_data.isEmpty() || that->getStickerLarge()) {
if (!that->_data.isEmpty()) {
ActiveCache().up(that);
}
}
@ -1207,66 +1186,6 @@ StickerData *DocumentData::sticker() const {
: nullptr;
}
void DocumentData::checkStickerLarge() {
const auto data = sticker();
if (!data) return;
automaticLoad(stickerSetOrigin(), nullptr);
if (!data->image && !data->animated && loaded()) {
if (_data.isEmpty()) {
const auto &loc = location(true);
if (loc.accessEnable()) {
data->image = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(loc.name()));
loc.accessDisable();
}
} else {
auto format = QByteArray();
auto image = App::readImage(_data, &format, false);
data->image = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
_data,
format,
std::move(image)));
}
if (const auto usage = ComputeUsage(data)) {
ActiveCache().increment(usage);
ActiveCache().up(this);
}
}
}
void DocumentData::checkStickerSmall() {
const auto data = sticker();
if ((data && data->animated) || thumbnailEnoughForSticker()) {
_thumbnail->load(stickerSetOrigin());
if (data && data->animated) {
automaticLoad(stickerSetOrigin(), nullptr);
}
} else {
checkStickerLarge();
}
}
Image *DocumentData::getStickerLarge() {
checkStickerLarge();
if (const auto data = sticker()) {
return data->image.get();
}
return nullptr;
}
Image *DocumentData::getStickerSmall() {
const auto data = sticker();
if ((data && data->animated) || thumbnailEnoughForSticker()) {
return _thumbnail->isNull() ? nullptr : _thumbnail.get();
} else if (data) {
return data->image.get();
}
return nullptr;
}
Data::FileOrigin DocumentData::stickerSetOrigin() const {
if (const auto data = sticker()) {
if (const auto result = data->setOrigin()) {

View file

@ -58,7 +58,6 @@ struct DocumentAdditionalData {
struct StickerData : public DocumentAdditionalData {
Data::FileOrigin setOrigin() const;
std::unique_ptr<Image> image;
bool animated = false;
QString alt;
MTPInputStickerSet set = MTP_inputStickerSetEmpty();
@ -141,13 +140,10 @@ public:
[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
[[nodiscard]] StickerData *sticker() const;
void checkStickerLarge();
void checkStickerSmall();
[[nodiscard]] Image *getStickerSmall();
[[nodiscard]] Image *getStickerLarge();
[[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();
@ -195,7 +191,8 @@ public:
void setGoodThumbnailChecked(bool hasData);
[[nodiscard]] std::shared_ptr<Data::DocumentMedia> createMediaView();
[[nodiscard]] std::shared_ptr<Data::DocumentMedia> activeMediaView();
[[nodiscard]] auto activeMediaView() const
-> std::shared_ptr<Data::DocumentMedia>;
void setGoodThumbnailPhoto(not_null<PhotoData*> photo);
[[nodiscard]] PhotoData *goodThumbnailPhoto() const;
@ -302,7 +299,6 @@ private:
void destroyLoader() const;
[[nodiscard]] bool useStreamingLoader() const;
[[nodiscard]] bool thumbnailEnoughForSticker() const;
// Two types of location: from MTProto by dc+access or from web by url
int32 _dc = 0;

View file

@ -11,10 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_good_thumbnail.h"
#include "data/data_session.h"
#include "data/data_cloud_themes.h"
#include "data/data_file_origin.h"
#include "media/clip/media_clip_reader.h"
#include "main/main_session.h"
#include "lottie/lottie_animation.h"
#include "window/themes/window_theme_preview.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
#include "app.h"
@ -121,6 +123,78 @@ Image *DocumentMedia::thumbnailInline() const {
return _inlineThumbnail.get();
}
void DocumentMedia::checkStickerLarge() {
if (_sticker) {
return;
}
const auto data = _owner->sticker();
if (!data) {
return;
}
_owner->automaticLoad(_owner->stickerSetOrigin(), nullptr);
if (data->animated || !_owner->loaded()) {
return;
}
const auto bytes = _owner->data();
if (bytes.isEmpty()) {
const auto &loc = _owner->location(true);
if (loc.accessEnable()) {
_sticker = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(loc.name()));
loc.accessDisable();
}
} else {
auto format = QByteArray();
auto image = App::readImage(bytes, &format, false);
_sticker = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
bytes,
format,
std::move(image)));
}
}
void DocumentMedia::checkStickerSmall() {
const auto data = _owner->sticker();
if ((data && data->animated) || _owner->thumbnailEnoughForSticker()) {
_owner->loadThumbnail(_owner->stickerSetOrigin());
if (data && data->animated) {
_owner->automaticLoad(_owner->stickerSetOrigin(), nullptr);
}
} else {
checkStickerLarge();
}
}
Image *DocumentMedia::getStickerLarge() {
checkStickerLarge();
return _sticker.get();
}
Image *DocumentMedia::getStickerSmall() {
const auto data = _owner->sticker();
if ((data && data->animated) || _owner->thumbnailEnoughForSticker()) {
return _owner->thumbnail();
}
return _sticker.get();
}
void DocumentMedia::checkStickerLarge(not_null<FileLoader*> loader) {
if (_owner->sticker()
&& !_sticker
&& !loader->imageData().isNull()
&& !_owner->data().isEmpty()) {
_sticker = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
_owner->data(),
loader->imageFormat(),
loader->imageData()));
}
}
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
const auto data = document->data();
const auto type = document->isWallPaper()

View file

@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flags.h"
class FileLoader;
namespace Data {
class DocumentMedia final {
@ -22,6 +24,12 @@ public:
[[nodiscard]] Image *thumbnailInline() const;
void checkStickerLarge();
void checkStickerSmall();
[[nodiscard]] Image *getStickerSmall();
[[nodiscard]] Image *getStickerLarge();
void checkStickerLarge(not_null<FileLoader*> loader);
// For DocumentData.
static void CheckGoodThumbnail(not_null<DocumentData*> document);
@ -38,6 +46,7 @@ private:
const not_null<DocumentData*> _owner;
std::unique_ptr<Image> _goodThumbnail;
mutable std::unique_ptr<Image> _inlineThumbnail;
std::unique_ptr<Image> _sticker;
Flags _flags;
};

View file

@ -100,7 +100,8 @@ bool Sticker::readyToDrawLottie() {
return false;
}
_data->checkStickerLarge();
ensureDataMediaCreated();
_dataMedia->checkStickerLarge();
const auto loaded = _data->loaded();
if (sticker->animated && !_lottie && loaded) {
setupLottie();
@ -124,6 +125,7 @@ QSize Sticker::GetAnimatedEmojiSize(
}
void Sticker::draw(Painter &p, const QRect &r, bool selected) {
ensureDataMediaCreated();
if (readyToDrawLottie()) {
paintLottie(p, r, selected);
} else if (_data->sticker()
@ -200,8 +202,6 @@ void Sticker::paintPixmap(Painter &p, const QRect &r, bool selected) {
}
QPixmap Sticker::paintedPixmap(bool selected) const {
ensureDataMediaCreated();
const auto o = _parent->data()->fullId();
const auto w = _size.width();
const auto h = _size.height();
@ -210,7 +210,7 @@ QPixmap Sticker::paintedPixmap(bool selected) const {
if (good && !good->loaded()) {
good->load({});
}
if (const auto image = _data->getStickerLarge()) {
if (const auto image = _dataMedia->getStickerLarge()) {
return selected
? image->pixColored(o, c, w, h)
: image->pix(o, w, h);

View file

@ -434,12 +434,20 @@ void Sticker::initDimensions() {
void Sticker::preload() const {
if (const auto document = getShownDocument()) {
document->checkStickerSmall();
ensureDataMediaCreated(document);
_dataMedia->checkStickerSmall();
} else if (const auto thumb = getResultThumb()) {
thumb->load(fileOrigin());
}
}
void Sticker::ensureDataMediaCreated(not_null<DocumentData*> document) const {
if (_dataMedia) {
return;
}
_dataMedia = document->createMediaView();
}
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
bool loaded = getShownDocument()->loaded();
@ -517,14 +525,15 @@ void Sticker::setupLottie(not_null<DocumentData*> document) const {
void Sticker::prepareThumbnail() const {
if (const auto document = getShownDocument()) {
ensureDataMediaCreated(document);
if (!_lottie
&& document->sticker()
&& document->sticker()->animated
&& document->loaded()) {
setupLottie(document);
}
document->checkStickerSmall();
if (const auto sticker = document->getStickerSmall()) {
_dataMedia->checkStickerSmall();
if (const auto sticker = _dataMedia->getStickerSmall()) {
if (!_lottie && !_thumbLoaded && sticker->loaded()) {
const auto thumbSize = getThumbSize();
_thumb = sticker->pix(

View file

@ -192,6 +192,7 @@ public:
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
private:
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void setupLottie(not_null<DocumentData*> document) const;
QSize getThumbSize() const;
void prepareThumbnail() const;
@ -203,6 +204,7 @@ private:
mutable bool _thumbLoaded = false;
mutable std::unique_ptr<Lottie::SinglePlayer> _lottie;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
mutable rpl::lifetime _lifetime;
};

View file

@ -1093,6 +1093,7 @@ void OverlayWidget::clearData() {
_fromName = QString();
_photo = nullptr;
_doc = nullptr;
_docMedia = nullptr;
_pip = nullptr;
_fullScreenVideo = false;
_caption.clear();
@ -1913,6 +1914,7 @@ void OverlayWidget::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item)
clearStreaming();
destroyThemePreview();
_doc = nullptr;
_docMedia = nullptr;
_fullScreenVideo = false;
_photo = photo;
_rotation = _photo->owner().mediaRotation().get(_photo);
@ -1972,6 +1974,9 @@ void OverlayWidget::displayDocument(
clearStreaming(_doc != doc);
destroyThemePreview();
_doc = doc;
if (_doc) {
_docMedia = _doc->createMediaView();
}
_rotation = _doc ? _doc->owner().mediaRotation().get(_doc) : 0;
_themeCloudData = cloud;
_photo = nullptr;
@ -1980,7 +1985,7 @@ void OverlayWidget::displayDocument(
refreshMediaViewer();
if (_doc) {
if (_doc->sticker()) {
if (const auto image = _doc->getStickerLarge()) {
if (const auto image = _docMedia->getStickerLarge()) {
_staticContent = image->pix(fileOrigin());
} else if (_doc->hasThumbnail()) {
_staticContent = _doc->thumbnail()->pixBlurred(
@ -3019,7 +3024,7 @@ void OverlayWidget::paintTransformedStaticContent(Painter &p) {
const auto rect = contentRect();
PainterHighQualityEnabler hq(p);
if ((!_doc || !_doc->getStickerLarge())
if ((!_doc || !_docMedia->getStickerLarge())
&& (_staticContent.isNull()
|| _staticContent.hasAlpha())) {
p.fillRect(rect, _transparentBrush);
@ -3482,13 +3487,9 @@ void OverlayWidget::preloadData(int delta) {
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
(*photo)->download(fileOrigin());
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
if (const auto image = (*document)->getStickerLarge()) {
image->load(fileOrigin());
} else {
(*document)->loadThumbnail(fileOrigin());
if (!(*document)->canBePlayed()) {
(*document)->automaticLoad(fileOrigin(), entity.item);
}
(*document)->loadThumbnail(fileOrigin());
if (!(*document)->canBePlayed()) {
(*document)->automaticLoad(fileOrigin(), entity.item);
}
}
}

View file

@ -249,7 +249,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
}
if (_lottie && _lottie->ready()) {
return QPixmap();
} else if (const auto image = _document->getStickerLarge()) {
} else if (const auto image = _documentMedia->getStickerLarge()) {
QSize s = currentDimensions();
_cache = image->pix(_origin, s.width(), s.height());
_cacheStatus = CacheLoaded;