Support webm stickers in bot inline results.

This commit is contained in:
John Preston 2022-01-25 12:27:33 +03:00
parent 91c84d63de
commit 827ce46d3c
2 changed files with 74 additions and 18 deletions

View file

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/media/history_view_document.h" // DrawThumbnailAsSongCover
#include "history/view/media/history_view_media_common.h"
#include "ui/image/image.h"
#include "ui/text/format_values.h"
#include "ui/cached_round_corners.h"
@ -461,6 +462,7 @@ void Sticker::unloadHeavyPart() {
_dataMedia = nullptr;
_lifetime.destroy();
_lottie = nullptr;
_webm = nullptr;
}
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
@ -476,7 +478,6 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
prepareThumbnail();
if (_lottie && _lottie->ready()) {
const auto frame = _lottie->frame();
_lottie->markFrameShown();
const auto size = frame.size() / cIntRetinaFactor();
const auto pos = QPoint(
(st::stickerPanSize.width() - size.width()) / 2,
@ -484,6 +485,19 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
p.drawImage(
QRect(pos, size),
frame);
if (!context->paused) {
_lottie->markFrameShown();
}
} else if (_webm && _webm->started()) {
const auto size = getThumbSize();
const auto frame = _webm->current({
.frame = size,
.keepAlpha = true,
}, context->paused ? 0 : context->ms);
p.drawPixmap(
(st::stickerPanSize.width() - size.width()) / 2,
(st::stickerPanSize.height() - size.width()) / 2,
frame);
} else if (!_thumb.isNull()) {
int w = _thumb.width() / cIntRetinaFactor(), h = _thumb.height() / cIntRetinaFactor();
QPoint pos = QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
@ -527,13 +541,15 @@ void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
ItemBase::clickHandlerActiveChanged(p, active);
}
QSize Sticker::boundingBox() const {
const auto size = st::stickerPanSize.width() - st::roundRadiusSmall * 2;
return { size, size };
}
QSize Sticker::getThumbSize() const {
int width = qMax(content_width(), 1), height = qMax(content_height(), 1);
float64 coefw = (st::stickerPanSize.width() - st::roundRadiusSmall * 2) / float64(width);
float64 coefh = (st::stickerPanSize.height() - st::roundRadiusSmall * 2) / float64(height);
float64 coef = qMin(qMin(coefw, coefh), 1.);
int w = qRound(coef * content_width()), h = qRound(coef * content_height());
return QSize(qMax(w, 1), qMax(h, 1));
const auto width = qMax(content_width(), 1);
const auto height = qMax(content_height(), 1);
return HistoryView::DownscaledSize({ width, height }, boundingBox());
}
void Sticker::setupLottie() const {
@ -542,10 +558,7 @@ void Sticker::setupLottie() const {
_lottie = ChatHelpers::LottiePlayerFromDocument(
_dataMedia.get(),
ChatHelpers::StickerLottieSize::InlineResults,
QSize(
st::stickerPanSize.width() - st::roundRadiusSmall * 2,
st::stickerPanSize.height() - st::roundRadiusSmall * 2
) * cIntRetinaFactor());
boundingBox() * cIntRetinaFactor());
_lottie->updates(
) | rpl::start_with_next([=] {
@ -553,27 +566,66 @@ void Sticker::setupLottie() const {
}, _lifetime);
}
void Sticker::setupWebm() const {
Expects(_dataMedia != nullptr);
const auto that = const_cast<Sticker*>(this);
auto callback = [=](Media::Clip::Notification notification) {
that->clipCallback(notification);
};
that->_webm = Media::Clip::MakeReader(
_dataMedia->owner()->location(),
_dataMedia->bytes(),
std::move(callback));
}
void Sticker::prepareThumbnail() const {
const auto document = getShownDocument();
Assert(document != nullptr);
ensureDataMediaCreated(document);
if (!_lottie
&& document->sticker()
&& document->sticker()->isLottie()
&& _dataMedia->loaded()) {
setupLottie();
const auto sticker = document->sticker();
if (sticker && _dataMedia->loaded()) {
if (!_lottie && sticker->isLottie()) {
setupLottie();
} else if (!_webm && sticker->isWebm()) {
setupWebm();
}
}
_dataMedia->checkStickerSmall();
if (const auto sticker = _dataMedia->getStickerSmall()) {
if (const auto image = _dataMedia->getStickerSmall()) {
if (!_lottie && !_thumbLoaded) {
const auto thumbSize = getThumbSize();
_thumb = sticker->pix(thumbSize);
_thumb = image->pix(thumbSize);
_thumbLoaded = true;
}
}
}
void Sticker::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case Notification::Reinit: {
if (!_webm) {
break;
} else if (_webm->state() == State::Error) {
_webm.setBad();
} else if (_webm->ready() && !_webm->started()) {
_webm->start({
.frame = getThumbSize(),
.keepAlpha = true,
});
} else if (_webm->autoPausedGif()
&& !context()->inlineItemVisible(this)) {
unloadHeavyPart();
}
} break;
case Notification::Repaint: break;
}
update();
}
Photo::Photo(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result) {
Expects(getShownPhoto() != nullptr);

View file

@ -204,8 +204,11 @@ public:
private:
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
void setupLottie() const;
void setupWebm() const;
QSize getThumbSize() const;
QSize boundingBox() const;
void prepareThumbnail() const;
void clipCallback(Media::Clip::Notification notification);
mutable Ui::Animations::Simple _a_over;
mutable bool _active = false;
@ -214,6 +217,7 @@ private:
mutable bool _thumbLoaded = false;
mutable std::unique_ptr<Lottie::SinglePlayer> _lottie;
Media::Clip::ReaderPointer _webm;
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
mutable rpl::lifetime _lifetime;