mirror of https://github.com/procxx/kepka.git
Extract some Lottie::Animation code to Lottie::Player.
This commit is contained in:
parent
4a7b5a8e01
commit
cbffeca8d5
|
@ -21,7 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -65,7 +65,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
struct Element {
|
struct Element {
|
||||||
not_null<DocumentData*> document;
|
not_null<DocumentData*> document;
|
||||||
std::unique_ptr<Lottie::Animation> animated;
|
std::unique_ptr<Lottie::SinglePlayer> animated;
|
||||||
Ui::Animations::Simple overAnimation;
|
Ui::Animations::Simple overAnimation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ void StickerSetBox::Inner::setupLottie(int index) {
|
||||||
auto &element = _elements[index];
|
auto &element = _elements[index];
|
||||||
const auto document = element.document;
|
const auto document = element.document;
|
||||||
|
|
||||||
element.animated = Stickers::LottieFromDocument(
|
element.animated = Stickers::LottiePlayerFromDocument(
|
||||||
document,
|
document,
|
||||||
Stickers::LottieSize::StickerSet,
|
Stickers::LottieSize::StickerSet,
|
||||||
boundingBoxSize() * cIntRetinaFactor());
|
boundingBoxSize() * cIntRetinaFactor());
|
||||||
|
@ -566,9 +566,10 @@ void StickerSetBox::Inner::paintSticker(
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
element.animated->markFrameShown();
|
element.animated->markFrameShown();
|
||||||
}
|
}
|
||||||
|
const auto frame = element.animated->frame(request);
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(ppos, QSize(w, h)),
|
QRect(ppos, frame.size() / cIntRetinaFactor()),
|
||||||
element.animated->frame(request));
|
frame);
|
||||||
} else if (const auto image = document->getStickerSmall()) {
|
} else if (const auto image = document->getStickerSmall()) {
|
||||||
p.drawPixmapLeft(
|
p.drawPixmapLeft(
|
||||||
ppos,
|
ppos,
|
||||||
|
|
|
@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
|
||||||
namespace Stickers {
|
namespace Stickers {
|
||||||
|
@ -1092,7 +1092,7 @@ RecentStickerPack &GetRecentPack() {
|
||||||
return cRefRecentStickers();
|
return cRefRecentStickers();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Lottie::Animation> LottieFromDocument(
|
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
LottieSize sizeTag,
|
LottieSize sizeTag,
|
||||||
QSize box) {
|
QSize box) {
|
||||||
|
@ -1100,9 +1100,8 @@ std::unique_ptr<Lottie::Animation> LottieFromDocument(
|
||||||
const auto filepath = document->filepath();
|
const auto filepath = document->filepath();
|
||||||
if (box.width() & box.height() > kDontCacheLottieAfterArea) {
|
if (box.width() & box.height() > kDontCacheLottieAfterArea) {
|
||||||
// Don't use frame caching for large stickers.
|
// Don't use frame caching for large stickers.
|
||||||
return Lottie::FromContent(
|
return std::make_unique<Lottie::SinglePlayer>(
|
||||||
data,
|
Lottie::ReadContent(data, filepath),
|
||||||
filepath,
|
|
||||||
Lottie::FrameRequest{ box });
|
Lottie::FrameRequest{ box });
|
||||||
}
|
}
|
||||||
if (const auto baseKey = document->bigFileBaseCacheKey()) {
|
if (const auto baseKey = document->bigFileBaseCacheKey()) {
|
||||||
|
@ -1121,14 +1120,15 @@ std::unique_ptr<Lottie::Animation> LottieFromDocument(
|
||||||
weak->data().cacheBigFile().put(key, std::move(data));
|
weak->data().cacheBigFile().put(key, std::move(data));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return Lottie::FromCached(
|
return std::make_unique<Lottie::SinglePlayer>(
|
||||||
get,
|
get,
|
||||||
put,
|
put,
|
||||||
data,
|
Lottie::ReadContent(data, filepath),
|
||||||
filepath,
|
|
||||||
Lottie::FrameRequest{ box });
|
Lottie::FrameRequest{ box });
|
||||||
}
|
}
|
||||||
return Lottie::FromContent(data, filepath, Lottie::FrameRequest{ box });
|
return std::make_unique<Lottie::SinglePlayer>(
|
||||||
|
Lottie::ReadContent(data, filepath),
|
||||||
|
Lottie::FrameRequest{ box });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Stickers
|
} // namespace Stickers
|
||||||
|
|
|
@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
class DocumentData;
|
class DocumentData;
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class Animation;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
namespace Stickers {
|
namespace Stickers {
|
||||||
|
@ -113,11 +113,9 @@ enum class LottieSize : uchar {
|
||||||
MessageHistory,
|
MessageHistory,
|
||||||
StickerSet,
|
StickerSet,
|
||||||
StickersPanel,
|
StickersPanel,
|
||||||
StickersColumn,
|
|
||||||
MediaPreview,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Lottie::Animation> LottieFromDocument(
|
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
LottieSize sizeTag,
|
LottieSize sizeTag,
|
||||||
QSize box);
|
QSize box);
|
||||||
|
|
|
@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "boxes/stickers_box.h"
|
#include "boxes/stickers_box.h"
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
|
@ -1368,9 +1368,9 @@ void StickersListWidget::setupLottie(Set &set, int section, int index) {
|
||||||
auto &sticker = set.stickers[index];
|
auto &sticker = set.stickers[index];
|
||||||
const auto document = sticker.document;
|
const auto document = sticker.document;
|
||||||
|
|
||||||
sticker.animated = Stickers::LottieFromDocument(
|
sticker.animated = Stickers::LottiePlayerFromDocument(
|
||||||
document,
|
document,
|
||||||
Stickers::LottieSize::StickersColumn, // #TODO stickers
|
Stickers::LottieSize::StickersPanel,
|
||||||
boundingBoxSize() * cIntRetinaFactor());
|
boundingBoxSize() * cIntRetinaFactor());
|
||||||
const auto animation = sticker.animated.get();
|
const auto animation = sticker.animated.get();
|
||||||
|
|
||||||
|
@ -1424,9 +1424,10 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
sticker.animated->markFrameShown();
|
sticker.animated->markFrameShown();
|
||||||
}
|
}
|
||||||
|
const auto frame = sticker.animated->frame(request);
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(ppos, QSize(w, h)),
|
QRect(ppos, frame.size() / cIntRetinaFactor()),
|
||||||
sticker.animated->frame(request));
|
frame);
|
||||||
} else if (const auto image = document->getStickerSmall()) {
|
} else if (const auto image = document->getStickerSmall()) {
|
||||||
if (image->loaded()) {
|
if (image->loaded()) {
|
||||||
p.drawPixmapLeft(
|
p.drawPixmapLeft(
|
||||||
|
|
|
@ -22,7 +22,7 @@ class RippleAnimation;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class Animation;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
@ -98,20 +98,22 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OverSticker {
|
struct OverSticker {
|
||||||
int section;
|
int section = 0;
|
||||||
int index;
|
int index = 0;
|
||||||
bool overDelete;
|
bool overDelete = false;
|
||||||
};
|
};
|
||||||
struct OverSet {
|
struct OverSet {
|
||||||
int section;
|
int section = 0;
|
||||||
};
|
};
|
||||||
struct OverButton {
|
struct OverButton {
|
||||||
int section;
|
int section = 0;
|
||||||
};
|
};
|
||||||
struct OverGroupAdd {
|
struct OverGroupAdd {
|
||||||
};
|
};
|
||||||
friend inline bool operator==(OverSticker a, OverSticker b) {
|
friend inline bool operator==(OverSticker a, OverSticker b) {
|
||||||
return (a.section == b.section) && (a.index == b.index) && (a.overDelete == b.overDelete);
|
return (a.section == b.section)
|
||||||
|
&& (a.index == b.index)
|
||||||
|
&& (a.overDelete == b.overDelete);
|
||||||
}
|
}
|
||||||
friend inline bool operator==(OverSet a, OverSet b) {
|
friend inline bool operator==(OverSet a, OverSet b) {
|
||||||
return (a.section == b.section);
|
return (a.section == b.section);
|
||||||
|
@ -122,7 +124,11 @@ private:
|
||||||
friend inline bool operator==(OverGroupAdd a, OverGroupAdd b) {
|
friend inline bool operator==(OverGroupAdd a, OverGroupAdd b) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
using OverState = base::optional_variant<OverSticker, OverSet, OverButton, OverGroupAdd>;
|
using OverState = base::optional_variant<
|
||||||
|
OverSticker,
|
||||||
|
OverSet,
|
||||||
|
OverButton,
|
||||||
|
OverGroupAdd>;
|
||||||
|
|
||||||
struct SectionInfo {
|
struct SectionInfo {
|
||||||
int section = 0;
|
int section = 0;
|
||||||
|
@ -135,7 +141,7 @@ private:
|
||||||
|
|
||||||
struct Sticker {
|
struct Sticker {
|
||||||
not_null<DocumentData*> document;
|
not_null<DocumentData*> document;
|
||||||
std::unique_ptr<Lottie::Animation> animated;
|
std::unique_ptr<Lottie::SinglePlayer> animated;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Set {
|
struct Set {
|
||||||
|
|
|
@ -45,14 +45,16 @@ TabbedPanel::TabbedPanel(
|
||||||
, _maxContentHeight(st::emojiPanMaxHeight) {
|
, _maxContentHeight(st::emojiPanMaxHeight) {
|
||||||
_selector->setParent(this);
|
_selector->setParent(this);
|
||||||
_selector->setRoundRadius(st::buttonRadius);
|
_selector->setRoundRadius(st::buttonRadius);
|
||||||
_selector->setAfterShownCallback([this](SelectorTab tab) {
|
_selector->setAfterShownCallback([=](SelectorTab tab) {
|
||||||
if (tab == SelectorTab::Gifs) {
|
if (tab == SelectorTab::Gifs || tab == SelectorTab::Stickers) {
|
||||||
_controller->enableGifPauseReason(Window::GifPauseReason::SavedGifs);
|
_controller->enableGifPauseReason(
|
||||||
|
Window::GifPauseReason::SavedGifs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_selector->setBeforeHidingCallback([this](SelectorTab tab) {
|
_selector->setBeforeHidingCallback([=](SelectorTab tab) {
|
||||||
if (tab == SelectorTab::Gifs) {
|
if (tab == SelectorTab::Gifs || tab == SelectorTab::Stickers) {
|
||||||
_controller->disableGifPauseReason(Window::GifPauseReason::SavedGifs);
|
_controller->disableGifPauseReason(
|
||||||
|
Window::GifPauseReason::SavedGifs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_selector->showRequests(
|
_selector->showRequests(
|
||||||
|
|
|
@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "window/window_session_controller.h" // isGifPausedAtLeastFor.
|
#include "window/window_session_controller.h" // isGifPausedAtLeastFor.
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -97,7 +97,7 @@ QSize HistorySticker::countCurrentSize(int newWidth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistorySticker::setupLottie() {
|
void HistorySticker::setupLottie() {
|
||||||
_lottie = Stickers::LottieFromDocument(
|
_lottie = Stickers::LottiePlayerFromDocument(
|
||||||
_data,
|
_data,
|
||||||
Stickers::LottieSize::MessageHistory,
|
Stickers::LottieSize::MessageHistory,
|
||||||
QSize(st::maxStickerSize, st::maxStickerSize) * cIntRetinaFactor());
|
QSize(st::maxStickerSize, st::maxStickerSize) * cIntRetinaFactor());
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct HistoryMessageReply;
|
||||||
struct HistoryMessageForwarded;
|
struct HistoryMessageForwarded;
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class Animation;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
class HistorySticker : public HistoryMedia {
|
class HistorySticker : public HistoryMedia {
|
||||||
|
@ -75,7 +75,7 @@ private:
|
||||||
ClickHandlerPtr _packLink;
|
ClickHandlerPtr _packLink;
|
||||||
not_null<DocumentData*> _data;
|
not_null<DocumentData*> _data;
|
||||||
QString _emoji;
|
QString _emoji;
|
||||||
std::unique_ptr<Lottie::Animation> _lottie;
|
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -932,7 +932,8 @@ Widget::~Widget() = default;
|
||||||
|
|
||||||
void Widget::hideFinished() {
|
void Widget::hideFinished() {
|
||||||
hide();
|
hide();
|
||||||
_controller->disableGifPauseReason(Window::GifPauseReason::InlineResults);
|
_controller->disableGifPauseReason(
|
||||||
|
Window::GifPauseReason::InlineResults);
|
||||||
|
|
||||||
_inner->hideFinish(true);
|
_inner->hideFinish(true);
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
|
@ -953,7 +954,8 @@ void Widget::showStarted() {
|
||||||
recountContentMaxHeight();
|
recountContentMaxHeight();
|
||||||
_inner->preloadImages();
|
_inner->preloadImages();
|
||||||
show();
|
show();
|
||||||
_controller->enableGifPauseReason(Window::GifPauseReason::InlineResults);
|
_controller->enableGifPauseReason(
|
||||||
|
Window::GifPauseReason::InlineResults);
|
||||||
startShowAnimation();
|
startShowAnimation();
|
||||||
} else if (_hiding) {
|
} else if (_hiding) {
|
||||||
startOpacityAnimation(false);
|
startOpacityAnimation(false);
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "lottie/lottie_frame_renderer.h"
|
#include "lottie/lottie_frame_renderer.h"
|
||||||
#include "lottie/lottie_cache.h"
|
#include "lottie/lottie_cache.h"
|
||||||
|
#include "lottie/lottie_player.h"
|
||||||
#include "base/algorithm.h"
|
#include "base/algorithm.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include "logs.h"
|
#include "logs.h"
|
||||||
|
@ -56,17 +57,6 @@ std::string UnpackGzip(const QByteArray &bytes) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ReadFile(const QString &filepath) {
|
|
||||||
auto f = QFile(filepath);
|
|
||||||
return (f.size() <= kMaxFileSize && f.open(QIODevice::ReadOnly))
|
|
||||||
? f.readAll()
|
|
||||||
: QByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray ReadContent(const QByteArray &data, const QString &filepath) {
|
|
||||||
return data.isEmpty() ? ReadFile(filepath) : base::duplicate(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Error> ContentError(const QByteArray &content) {
|
std::optional<Error> ContentError(const QByteArray &content) {
|
||||||
if (content.size() > kMaxFileSize) {
|
if (content.size() > kMaxFileSize) {
|
||||||
qWarning() << "Lottie Error: Too large file: " << content.size();
|
qWarning() << "Lottie Error: Too large file: " << content.size();
|
||||||
|
@ -140,26 +130,6 @@ std::unique_ptr<rlottie::Animation> CreateFromContent(
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
std::unique_ptr<Animation> FromContent(
|
|
||||||
const QByteArray &data,
|
|
||||||
const QString &filepath,
|
|
||||||
const FrameRequest &request) {
|
|
||||||
return std::make_unique<Animation>(ReadContent(data, filepath), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Animation> FromCached(
|
|
||||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
|
||||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
|
||||||
const QByteArray &data,
|
|
||||||
const QString &filepath,
|
|
||||||
const FrameRequest &request) {
|
|
||||||
return std::make_unique<Animation>(
|
|
||||||
std::move(get),
|
|
||||||
std::move(put),
|
|
||||||
ReadContent(data, filepath),
|
|
||||||
request);
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage ReadThumbnail(const QByteArray &content) {
|
QImage ReadThumbnail(const QByteArray &content) {
|
||||||
return Init(content, FrameRequest()).match([](
|
return Init(content, FrameRequest()).match([](
|
||||||
const std::unique_ptr<SharedState> &state) {
|
const std::unique_ptr<SharedState> &state) {
|
||||||
|
@ -169,8 +139,11 @@ QImage ReadThumbnail(const QByteArray &content) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::Animation(const QByteArray &content, const FrameRequest &request)
|
Animation::Animation(
|
||||||
: _timer([=] { checkNextFrameRender(); }) {
|
not_null<Player*> player,
|
||||||
|
const QByteArray &content,
|
||||||
|
const FrameRequest &request)
|
||||||
|
: _player(player) {
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
crl::async([=] {
|
crl::async([=] {
|
||||||
crl::on_main(weak, [=, data = Init(content, request)]() mutable {
|
crl::on_main(weak, [=, data = Init(content, request)]() mutable {
|
||||||
|
@ -180,11 +153,12 @@ Animation::Animation(const QByteArray &content, const FrameRequest &request)
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::Animation(
|
Animation::Animation(
|
||||||
|
not_null<Player*> player,
|
||||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
const FrameRequest &request)
|
const FrameRequest &request)
|
||||||
: _timer([=] { checkNextFrameRender(); }) {
|
: _player(player) {
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
get([=, put = std::move(put)](QByteArray &&cached) mutable {
|
get([=, put = std::move(put)](QByteArray &&cached) mutable {
|
||||||
crl::async([=, put = std::move(put)]() mutable {
|
crl::async([=, put = std::move(put)]() mutable {
|
||||||
|
@ -196,11 +170,8 @@ Animation::Animation(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::~Animation() {
|
bool Animation::ready() const {
|
||||||
if (_renderer) {
|
return (_state != nullptr);
|
||||||
Assert(_state != nullptr);
|
|
||||||
_renderer->remove(_state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::initDone(details::InitData &&data) {
|
void Animation::initDone(details::InitData &&data) {
|
||||||
|
@ -214,97 +185,24 @@ void Animation::initDone(details::InitData &&data) {
|
||||||
void Animation::parseDone(std::unique_ptr<SharedState> state) {
|
void Animation::parseDone(std::unique_ptr<SharedState> state) {
|
||||||
Expects(state != nullptr);
|
Expects(state != nullptr);
|
||||||
|
|
||||||
auto information = state->information();
|
|
||||||
_state = state.get();
|
_state = state.get();
|
||||||
_state->start(this, crl::now());
|
_player->start(this, std::move(state));
|
||||||
_renderer = FrameRenderer::Instance();
|
|
||||||
_renderer->append(std::move(state));
|
|
||||||
_updates.fire({ std::move(information) });
|
|
||||||
|
|
||||||
crl::on_main_update_requests(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
checkStep();
|
|
||||||
}, _lifetime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::parseFailed(Error error) {
|
void Animation::parseFailed(Error error) {
|
||||||
_updates.fire_error(std::move(error));
|
_player->failed(this, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Animation::frame(const FrameRequest &request) const {
|
QImage Animation::frame(const FrameRequest &request) const {
|
||||||
Expects(_renderer != nullptr);
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
const auto frame = _state->frameForPaint();
|
const auto frame = _state->frameForPaint();
|
||||||
const auto changed = (frame->request != request);
|
const auto changed = (frame->request != request);
|
||||||
if (changed) {
|
if (changed) {
|
||||||
frame->request = request;
|
frame->request = request;
|
||||||
_renderer->updateFrameRequest(_state, request);
|
_player->updateFrameRequest(this, request);
|
||||||
}
|
}
|
||||||
return PrepareFrameByRequest(frame, !changed);
|
return PrepareFrameByRequest(frame, !changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<Update, Error> Animation::updates() const {
|
|
||||||
return _updates.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Animation::ready() const {
|
|
||||||
return (_renderer != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
crl::time Animation::markFrameDisplayed(crl::time now) {
|
|
||||||
Expects(_renderer != nullptr);
|
|
||||||
|
|
||||||
const auto result = _state->markFrameDisplayed(now);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
crl::time Animation::markFrameShown() {
|
|
||||||
Expects(_renderer != nullptr);
|
|
||||||
|
|
||||||
const auto result = _state->markFrameShown();
|
|
||||||
_renderer->frameShown(_state);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Animation::checkStep() {
|
|
||||||
if (_nextFrameTime != kTimeUnknown) {
|
|
||||||
checkNextFrameRender();
|
|
||||||
} else {
|
|
||||||
checkNextFrameAvailability();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Animation::checkNextFrameAvailability() {
|
|
||||||
Expects(_renderer != nullptr);
|
|
||||||
|
|
||||||
_nextFrameTime = _state->nextFrameDisplayTime();
|
|
||||||
if (_nextFrameTime != kTimeUnknown) {
|
|
||||||
checkStep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Animation::checkNextFrameRender() {
|
|
||||||
Expects(_nextFrameTime != kTimeUnknown);
|
|
||||||
|
|
||||||
const auto now = crl::now();
|
|
||||||
if (now < _nextFrameTime) {
|
|
||||||
if (!_timer.isActive()) {
|
|
||||||
_timer.callOnce(_nextFrameTime - now);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_timer.cancel();
|
|
||||||
|
|
||||||
_nextFrameTime = kTimeUnknown;
|
|
||||||
const auto position = markFrameDisplayed(now);
|
|
||||||
_updates.fire({ DisplayFrameRequest{ position } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//void Animation::play(const PlaybackOptions &options) {
|
|
||||||
// _options = options;
|
|
||||||
// _started = crl::now();
|
|
||||||
//}
|
|
||||||
|
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
|
@ -7,11 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/basic_types.h"
|
|
||||||
#include "base/flat_map.h"
|
|
||||||
#include "base/weak_ptr.h"
|
|
||||||
#include "base/timer.h"
|
|
||||||
#include "lottie/lottie_common.h"
|
#include "lottie/lottie_common.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
|
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <crl/crl_time.h>
|
#include <crl/crl_time.h>
|
||||||
|
@ -29,23 +26,10 @@ class Animation;
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
|
|
||||||
inline constexpr auto kMaxFileSize = 1024 * 1024;
|
class Player;
|
||||||
|
|
||||||
class SharedState;
|
class SharedState;
|
||||||
class Animation;
|
|
||||||
class FrameRenderer;
|
class FrameRenderer;
|
||||||
|
|
||||||
std::unique_ptr<Animation> FromContent(
|
|
||||||
const QByteArray &data,
|
|
||||||
const QString &filepath,
|
|
||||||
const FrameRequest &request);
|
|
||||||
std::unique_ptr<Animation> FromCached(
|
|
||||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
|
||||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
|
||||||
const QByteArray &data,
|
|
||||||
const QString &filepath,
|
|
||||||
const FrameRequest &request);
|
|
||||||
|
|
||||||
QImage ReadThumbnail(const QByteArray &content);
|
QImage ReadThumbnail(const QByteArray &content);
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
@ -59,47 +43,27 @@ std::unique_ptr<rlottie::Animation> CreateFromContent(
|
||||||
|
|
||||||
class Animation final : public base::has_weak_ptr {
|
class Animation final : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
explicit Animation(
|
Animation(
|
||||||
|
not_null<Player*> player,
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
const FrameRequest &request);
|
const FrameRequest &request);
|
||||||
Animation(
|
Animation(
|
||||||
|
not_null<Player*> player,
|
||||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
const FrameRequest &request);
|
const FrameRequest &request);
|
||||||
~Animation();
|
|
||||||
|
|
||||||
//void play(const PlaybackOptions &options);
|
|
||||||
|
|
||||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Update, Error> updates() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool ready() const;
|
[[nodiscard]] bool ready() const;
|
||||||
|
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||||
// Returns frame position, if any frame was marked as displayed.
|
|
||||||
crl::time markFrameDisplayed(crl::time now);
|
|
||||||
crl::time markFrameShown();
|
|
||||||
|
|
||||||
void checkStep();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initDone(details::InitData &&data);
|
void initDone(details::InitData &&data);
|
||||||
void parseDone(std::unique_ptr<SharedState> state);
|
void parseDone(std::unique_ptr<SharedState> state);
|
||||||
void parseFailed(Error error);
|
void parseFailed(Error error);
|
||||||
|
|
||||||
void checkNextFrameAvailability();
|
not_null<Player*> _player;
|
||||||
void checkNextFrameRender();
|
|
||||||
|
|
||||||
//crl::time _started = 0;
|
|
||||||
//PlaybackOptions _options;
|
|
||||||
|
|
||||||
base::Timer _timer;
|
|
||||||
crl::time _nextFrameTime = kTimeUnknown;
|
|
||||||
SharedState *_state = nullptr;
|
SharedState *_state = nullptr;
|
||||||
std::shared_ptr<FrameRenderer> _renderer;
|
|
||||||
rpl::event_stream<Update, Error> _updates;
|
|
||||||
rpl::lifetime _lifetime;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
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 "lottie/lottie_common.h"
|
||||||
|
|
||||||
|
#include "base/algorithm.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QByteArray ReadFile(const QString &filepath) {
|
||||||
|
auto f = QFile(filepath);
|
||||||
|
return (f.size() <= kMaxFileSize && f.open(QIODevice::ReadOnly))
|
||||||
|
? f.readAll()
|
||||||
|
: QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QByteArray ReadContent(const QByteArray &data, const QString &filepath) {
|
||||||
|
return data.isEmpty() ? ReadFile(filepath) : base::duplicate(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Lottie
|
|
@ -16,15 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
|
|
||||||
constexpr auto kTimeUnknown = std::numeric_limits<crl::time>::min();
|
inline constexpr auto kTimeUnknown = std::numeric_limits<crl::time>::min();
|
||||||
|
inline constexpr auto kMaxFileSize = 1024 * 1024;
|
||||||
|
|
||||||
class Animation;
|
class Animation;
|
||||||
|
|
||||||
struct PlaybackOptions {
|
|
||||||
float64 speed = 1.;
|
|
||||||
bool loop = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
int frameRate = 0;
|
int frameRate = 0;
|
||||||
int framesCount = 0;
|
int framesCount = 0;
|
||||||
|
@ -73,4 +69,6 @@ struct FrameRequest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QByteArray ReadContent(const QByteArray &data, const QString &filepath);
|
||||||
|
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "lottie/lottie_frame_renderer.h"
|
#include "lottie/lottie_frame_renderer.h"
|
||||||
|
|
||||||
|
#include "lottie/lottie_player.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_animation.h"
|
||||||
#include "lottie/lottie_cache.h"
|
#include "lottie/lottie_cache.h"
|
||||||
#include "logs.h"
|
#include "logs.h"
|
||||||
|
@ -290,7 +291,7 @@ void SharedState::init(QImage cover, const FrameRequest &request) {
|
||||||
_counter.store(0, std::memory_order_release);
|
_counter.store(0, std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedState::start(not_null<Animation*> owner, crl::time now) {
|
void SharedState::start(not_null<Player*> owner, crl::time now) {
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_started = now;
|
_started = now;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ inline constexpr auto kMaxFrameRate = 120;
|
||||||
inline constexpr auto kMaxSize = 3096;
|
inline constexpr auto kMaxSize = 3096;
|
||||||
inline constexpr auto kMaxFramesCount = 600;
|
inline constexpr auto kMaxFramesCount = 600;
|
||||||
|
|
||||||
class Animation;
|
class Player;
|
||||||
class Cache;
|
class Cache;
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
|
@ -55,7 +55,7 @@ public:
|
||||||
std::unique_ptr<Cache> cache,
|
std::unique_ptr<Cache> cache,
|
||||||
const FrameRequest &request);
|
const FrameRequest &request);
|
||||||
|
|
||||||
void start(not_null<Animation*> owner, crl::time now);
|
void start(not_null<Player*> owner, crl::time now);
|
||||||
|
|
||||||
[[nodiscard]] Information information() const;
|
[[nodiscard]] Information information() const;
|
||||||
[[nodiscard]] bool initialized() const;
|
[[nodiscard]] bool initialized() const;
|
||||||
|
@ -91,7 +91,7 @@ private:
|
||||||
static constexpr auto kFramesCount = 4;
|
static constexpr auto kFramesCount = 4;
|
||||||
std::array<Frame, kFramesCount> _frames;
|
std::array<Frame, kFramesCount> _frames;
|
||||||
|
|
||||||
base::weak_ptr<Animation> _owner;
|
base::weak_ptr<Player> _owner;
|
||||||
crl::time _started = kTimeUnknown;
|
crl::time _started = kTimeUnknown;
|
||||||
crl::time _duration = kTimeUnknown;
|
crl::time _duration = kTimeUnknown;
|
||||||
int _frameIndex = 0;
|
int _frameIndex = 0;
|
||||||
|
@ -111,6 +111,7 @@ public:
|
||||||
static std::shared_ptr<FrameRenderer> Instance();
|
static std::shared_ptr<FrameRenderer> Instance();
|
||||||
|
|
||||||
void append(std::unique_ptr<SharedState> entry);
|
void append(std::unique_ptr<SharedState> entry);
|
||||||
|
|
||||||
void updateFrameRequest(
|
void updateFrameRequest(
|
||||||
not_null<SharedState*> entry,
|
not_null<SharedState*> entry,
|
||||||
const FrameRequest &request);
|
const FrameRequest &request);
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
#include "lottie/lottie_common.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
|
|
||||||
|
#include <rpl/producer.h>
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
|
||||||
|
class SharedState;
|
||||||
|
|
||||||
|
class Player : public base::has_weak_ptr {
|
||||||
|
public:
|
||||||
|
virtual void start(
|
||||||
|
not_null<Animation*> animation,
|
||||||
|
std::unique_ptr<SharedState> state) = 0;
|
||||||
|
virtual void failed(not_null<Animation*> animation, Error error) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual rpl::producer<Update, Error> updates() = 0;
|
||||||
|
|
||||||
|
virtual void updateFrameRequest(
|
||||||
|
not_null<const Animation*> animation,
|
||||||
|
const FrameRequest &request) = 0;
|
||||||
|
|
||||||
|
// Returns frame position, if any frame was marked as displayed.
|
||||||
|
virtual crl::time markFrameDisplayed(crl::time now) = 0;
|
||||||
|
virtual crl::time markFrameShown() = 0;
|
||||||
|
|
||||||
|
virtual void checkStep() = 0;
|
||||||
|
|
||||||
|
virtual ~Player() = default;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Lottie
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
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 "lottie/lottie_single_player.h"
|
||||||
|
|
||||||
|
#include "lottie/lottie_frame_renderer.h"
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SinglePlayer::SinglePlayer(
|
||||||
|
const QByteArray &content,
|
||||||
|
const FrameRequest &request)
|
||||||
|
: _animation(this, content, request)
|
||||||
|
, _timer([=] { checkNextFrameRender(); })
|
||||||
|
, _renderer(FrameRenderer::Instance()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SinglePlayer::SinglePlayer(
|
||||||
|
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||||
|
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||||
|
const QByteArray &content,
|
||||||
|
const FrameRequest &request)
|
||||||
|
: _animation(this, std::move(get), std::move(put), content, request)
|
||||||
|
, _timer([=] { checkNextFrameRender(); })
|
||||||
|
, _renderer(FrameRenderer::Instance()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::start(
|
||||||
|
not_null<Animation*> animation,
|
||||||
|
std::unique_ptr<SharedState> state) {
|
||||||
|
Expects(animation == &_animation);
|
||||||
|
|
||||||
|
_state = state.get();
|
||||||
|
auto information = state->information();
|
||||||
|
state->start(this, crl::now());
|
||||||
|
_renderer = FrameRenderer::Instance();
|
||||||
|
_renderer->append(std::move(state));
|
||||||
|
_updates.fire({ std::move(information) });
|
||||||
|
|
||||||
|
crl::on_main_update_requests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
checkStep();
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::failed(not_null<Animation*> animation, Error error) {
|
||||||
|
Expects(animation == &_animation);
|
||||||
|
|
||||||
|
_updates.fire_error(std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
SinglePlayer::~SinglePlayer() {
|
||||||
|
if (_state) {
|
||||||
|
_renderer->remove(_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<Update, Error> SinglePlayer::updates() {
|
||||||
|
return _updates.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SinglePlayer::ready() const {
|
||||||
|
return _animation.ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage SinglePlayer::frame(const FrameRequest &request) const {
|
||||||
|
return _animation.frame(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::checkStep() {
|
||||||
|
if (_nextFrameTime != kTimeUnknown) {
|
||||||
|
checkNextFrameRender();
|
||||||
|
} else {
|
||||||
|
checkNextFrameAvailability();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::checkNextFrameAvailability() {
|
||||||
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
|
_nextFrameTime = _state->nextFrameDisplayTime();
|
||||||
|
if (_nextFrameTime != kTimeUnknown) {
|
||||||
|
checkStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::checkNextFrameRender() {
|
||||||
|
Expects(_nextFrameTime != kTimeUnknown);
|
||||||
|
|
||||||
|
const auto now = crl::now();
|
||||||
|
if (now < _nextFrameTime) {
|
||||||
|
if (!_timer.isActive()) {
|
||||||
|
_timer.callOnce(_nextFrameTime - now);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_timer.cancel();
|
||||||
|
|
||||||
|
_nextFrameTime = kTimeUnknown;
|
||||||
|
const auto position = markFrameDisplayed(now);
|
||||||
|
_updates.fire({ DisplayFrameRequest{ position } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer::updateFrameRequest(
|
||||||
|
not_null<const Animation*> animation,
|
||||||
|
const FrameRequest &request) {
|
||||||
|
Expects(animation == &_animation);
|
||||||
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
|
_renderer->updateFrameRequest(_state, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
crl::time SinglePlayer::markFrameDisplayed(crl::time now) {
|
||||||
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
|
return _state->markFrameDisplayed(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
crl::time SinglePlayer::markFrameShown() {
|
||||||
|
Expects(_renderer != nullptr);
|
||||||
|
|
||||||
|
const auto result = _state->markFrameShown();
|
||||||
|
_renderer->frameShown(_state);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Lottie
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
#include "lottie/lottie_player.h"
|
||||||
|
#include "lottie/lottie_animation.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
|
||||||
|
class SinglePlayer final : public Player {
|
||||||
|
public:
|
||||||
|
SinglePlayer(
|
||||||
|
const QByteArray &content,
|
||||||
|
const FrameRequest &request);
|
||||||
|
SinglePlayer(
|
||||||
|
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||||
|
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||||
|
const QByteArray &content,
|
||||||
|
const FrameRequest &request);
|
||||||
|
~SinglePlayer();
|
||||||
|
|
||||||
|
void start(
|
||||||
|
not_null<Animation*> animation,
|
||||||
|
std::unique_ptr<SharedState> state) override;
|
||||||
|
void failed(not_null<Animation*> animation, Error error) override;
|
||||||
|
|
||||||
|
rpl::producer<Update, Error> updates() override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool ready() const;
|
||||||
|
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||||
|
|
||||||
|
void updateFrameRequest(
|
||||||
|
not_null<const Animation*> animation,
|
||||||
|
const FrameRequest &request) override;
|
||||||
|
|
||||||
|
// Returns frame position, if any frame was marked as displayed.
|
||||||
|
crl::time markFrameDisplayed(crl::time now) override;
|
||||||
|
crl::time markFrameShown() override;
|
||||||
|
|
||||||
|
void checkStep() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkNextFrameAvailability();
|
||||||
|
void checkNextFrameRender();
|
||||||
|
|
||||||
|
Animation _animation;
|
||||||
|
base::Timer _timer;
|
||||||
|
std::shared_ptr<FrameRenderer> _renderer;
|
||||||
|
SharedState *_state = nullptr;
|
||||||
|
crl::time _nextFrameTime = kTimeUnknown;
|
||||||
|
rpl::event_stream<Update, Error> _updates;
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Lottie
|
|
@ -27,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/streaming/media_streaming_player.h"
|
#include "media/streaming/media_streaming_player.h"
|
||||||
#include "media/streaming/media_streaming_reader.h"
|
#include "media/streaming/media_streaming_reader.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "lottie/lottie_animation.h"
|
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_message.h"
|
#include "history/history_message.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
@ -43,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "storage/file_download.h"
|
#include "storage/file_download.h"
|
||||||
#include "lottie/lottie_animation.h"
|
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -195,12 +193,6 @@ struct OverlayWidget::Streamed {
|
||||||
bool resumeOnCallEnd = false;
|
bool resumeOnCallEnd = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OverlayWidget::LottieFile {
|
|
||||||
LottieFile(std::unique_ptr<Lottie::Animation> data);
|
|
||||||
|
|
||||||
std::unique_ptr<Lottie::Animation> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Callback>
|
template <typename Callback>
|
||||||
OverlayWidget::Streamed::Streamed(
|
OverlayWidget::Streamed::Streamed(
|
||||||
not_null<Data::Session*> owner,
|
not_null<Data::Session*> owner,
|
||||||
|
@ -215,11 +207,6 @@ OverlayWidget::Streamed::Streamed(
|
||||||
st::mediaviewStreamingRadial) {
|
st::mediaviewStreamingRadial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayWidget::LottieFile::LottieFile(
|
|
||||||
std::unique_ptr<Lottie::Animation> data)
|
|
||||||
: data(std::move(data)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
OverlayWidget::OverlayWidget()
|
OverlayWidget::OverlayWidget()
|
||||||
: OverlayParent(nullptr)
|
: OverlayParent(nullptr)
|
||||||
, _transparentBrush(style::transparentPlaceholderBrush())
|
, _transparentBrush(style::transparentPlaceholderBrush())
|
||||||
|
@ -438,7 +425,6 @@ bool OverlayWidget::documentBubbleShown() const {
|
||||||
|| (_doc
|
|| (_doc
|
||||||
&& !_themePreviewShown
|
&& !_themePreviewShown
|
||||||
&& !_streamed
|
&& !_streamed
|
||||||
&& !_lottie
|
|
||||||
&& _current.isNull());
|
&& _current.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,10 +433,6 @@ void OverlayWidget::clearStreaming() {
|
||||||
_streamed = nullptr;
|
_streamed = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::clearLottie() {
|
|
||||||
_lottie = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWidget::documentUpdated(DocumentData *doc) {
|
void OverlayWidget::documentUpdated(DocumentData *doc) {
|
||||||
if (_doc && _doc == doc) {
|
if (_doc && _doc == doc) {
|
||||||
if (documentBubbleShown()) {
|
if (documentBubbleShown()) {
|
||||||
|
@ -980,7 +962,6 @@ void OverlayWidget::clearData() {
|
||||||
_animationOpacities.clear();
|
_animationOpacities.clear();
|
||||||
}
|
}
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
clearLottie();
|
|
||||||
delete _menu;
|
delete _menu;
|
||||||
_menu = nullptr;
|
_menu = nullptr;
|
||||||
setContext(std::nullopt);
|
setContext(std::nullopt);
|
||||||
|
@ -1776,7 +1757,6 @@ void OverlayWidget::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item)
|
||||||
}
|
}
|
||||||
|
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
clearLottie();
|
|
||||||
destroyThemePreview();
|
destroyThemePreview();
|
||||||
_doc = nullptr;
|
_doc = nullptr;
|
||||||
_fullScreenVideo = false;
|
_fullScreenVideo = false;
|
||||||
|
@ -1828,7 +1808,6 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) {
|
||||||
_fullScreenVideo = false;
|
_fullScreenVideo = false;
|
||||||
_current = QPixmap();
|
_current = QPixmap();
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
clearLottie();
|
|
||||||
destroyThemePreview();
|
destroyThemePreview();
|
||||||
_doc = doc;
|
_doc = doc;
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
|
@ -1861,13 +1840,6 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) {
|
||||||
const auto &path = location.name();
|
const auto &path = location.name();
|
||||||
if (QImageReader(path).canRead()) {
|
if (QImageReader(path).canRead()) {
|
||||||
_current = PrepareStaticImage(path);
|
_current = PrepareStaticImage(path);
|
||||||
//} else if (auto lottie = Lottie::FromFile(path)) {
|
|
||||||
// _lottie = std::make_unique<LottieFile>(
|
|
||||||
// std::move(lottie));
|
|
||||||
// _lottie->data->updates(
|
|
||||||
// ) | rpl::start_with_next([=] {
|
|
||||||
// update();
|
|
||||||
// }, lifetime());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
location.accessDisable();
|
location.accessDisable();
|
||||||
|
@ -2561,8 +2533,6 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
} else if (_themePreviewShown) {
|
} else if (_themePreviewShown) {
|
||||||
paintThemePreview(p, r);
|
paintThemePreview(p, r);
|
||||||
} else if (_lottie) {
|
|
||||||
paintLottieFrame(p, r);
|
|
||||||
} else if (documentBubbleShown()) {
|
} else if (documentBubbleShown()) {
|
||||||
if (_docRect.intersects(r)) {
|
if (_docRect.intersects(r)) {
|
||||||
p.fillRect(_docRect, st::mediaviewFileBg);
|
p.fillRect(_docRect, st::mediaviewFileBg);
|
||||||
|
@ -2929,20 +2899,6 @@ void OverlayWidget::paintThemePreview(Painter &p, QRect clip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::paintLottieFrame(Painter &p, QRect clip) {
|
|
||||||
Expects(_lottie != nullptr);
|
|
||||||
|
|
||||||
if (_lottie->data->ready()) {
|
|
||||||
_lottie->data->markFrameShown();
|
|
||||||
const auto frame = _lottie->data->frame(Lottie::FrameRequest());
|
|
||||||
const auto x = (width() - frame.width()) / 2;
|
|
||||||
const auto y = (height() - frame.height()) / 2;
|
|
||||||
const auto background = _lottieDark ? Qt::black : Qt::white;
|
|
||||||
p.fillRect(x, y, frame.width(), frame.height(), background);
|
|
||||||
p.drawImage(x, y, frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWidget::keyPressEvent(QKeyEvent *e) {
|
void OverlayWidget::keyPressEvent(QKeyEvent *e) {
|
||||||
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
|
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
|
||||||
if (_streamed) {
|
if (_streamed) {
|
||||||
|
@ -2996,7 +2952,6 @@ void OverlayWidget::keyPressEvent(QKeyEvent *e) {
|
||||||
} else if (e->key() == Qt::Key_0) {
|
} else if (e->key() == Qt::Key_0) {
|
||||||
zoomReset();
|
zoomReset();
|
||||||
} else if (e->key() == Qt::Key_I) {
|
} else if (e->key() == Qt::Key_I) {
|
||||||
_lottieDark = !_lottieDark;
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3191,7 +3146,6 @@ bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) {
|
||||||
setContext(std::nullopt);
|
setContext(std::nullopt);
|
||||||
}
|
}
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
clearLottie();
|
|
||||||
_streamingStartPaused = false;
|
_streamingStartPaused = false;
|
||||||
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
|
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
|
||||||
displayPhoto(*photo, entity.item);
|
displayPhoto(*photo, entity.item);
|
||||||
|
@ -3686,7 +3640,6 @@ void OverlayWidget::setVisibleHook(bool visible) {
|
||||||
QCoreApplication::instance()->removeEventFilter(this);
|
QCoreApplication::instance()->removeEventFilter(this);
|
||||||
|
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
clearLottie();
|
|
||||||
destroyThemePreview();
|
destroyThemePreview();
|
||||||
_radial.stop();
|
_radial.stop();
|
||||||
_current = QPixmap();
|
_current = QPixmap();
|
||||||
|
|
|
@ -120,7 +120,6 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Streamed;
|
struct Streamed;
|
||||||
struct LottieFile;
|
|
||||||
|
|
||||||
enum OverState {
|
enum OverState {
|
||||||
OverNone,
|
OverNone,
|
||||||
|
@ -313,9 +312,6 @@ private:
|
||||||
void paintTransformedVideoFrame(Painter &p);
|
void paintTransformedVideoFrame(Painter &p);
|
||||||
void clearStreaming();
|
void clearStreaming();
|
||||||
|
|
||||||
void paintLottieFrame(Painter &p, QRect clip);
|
|
||||||
void clearLottie();
|
|
||||||
|
|
||||||
QBrush _transparentBrush;
|
QBrush _transparentBrush;
|
||||||
|
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
|
@ -364,8 +360,6 @@ private:
|
||||||
bool _blurred = true;
|
bool _blurred = true;
|
||||||
|
|
||||||
std::unique_ptr<Streamed> _streamed;
|
std::unique_ptr<Streamed> _streamed;
|
||||||
std::unique_ptr<LottieFile> _lottie;
|
|
||||||
bool _lottieDark = false;
|
|
||||||
|
|
||||||
const style::icon *_docIcon = nullptr;
|
const style::icon *_docIcon = nullptr;
|
||||||
style::color _docIconColor;
|
style::color _docIconColor;
|
||||||
|
|
|
@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "window/window_main_menu.h"
|
#include "window/window_main_menu.h"
|
||||||
#include "lottie/lottie_animation.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -1049,9 +1049,8 @@ QSize MediaPreviewWidget::currentDimensions() const {
|
||||||
void MediaPreviewWidget::setupLottie() {
|
void MediaPreviewWidget::setupLottie() {
|
||||||
Expects(_document != nullptr);
|
Expects(_document != nullptr);
|
||||||
|
|
||||||
_lottie = Lottie::FromContent(
|
_lottie = std::make_unique<Lottie::SinglePlayer>(
|
||||||
_document->data(),
|
Lottie::ReadContent(_document->data(), _document->filepath()),
|
||||||
_document->filepath(),
|
|
||||||
Lottie::FrameRequest{ currentDimensions() * cIntRetinaFactor() });
|
Lottie::FrameRequest{ currentDimensions() * cIntRetinaFactor() });
|
||||||
|
|
||||||
_lottie->updates(
|
_lottie->updates(
|
||||||
|
|
|
@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class Animation;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -236,7 +236,7 @@ private:
|
||||||
DocumentData *_document = nullptr;
|
DocumentData *_document = nullptr;
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
Media::Clip::ReaderPointer _gif;
|
Media::Clip::ReaderPointer _gif;
|
||||||
std::unique_ptr<Lottie::Animation> _lottie;
|
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||||
|
|
||||||
int _emojiSize;
|
int _emojiSize;
|
||||||
std::vector<not_null<EmojiPtr>> _emojiList;
|
std::vector<not_null<EmojiPtr>> _emojiList;
|
||||||
|
|
|
@ -60,9 +60,13 @@
|
||||||
'<(src_loc)/lottie/lottie_animation.h',
|
'<(src_loc)/lottie/lottie_animation.h',
|
||||||
'<(src_loc)/lottie/lottie_cache.cpp',
|
'<(src_loc)/lottie/lottie_cache.cpp',
|
||||||
'<(src_loc)/lottie/lottie_cache.h',
|
'<(src_loc)/lottie/lottie_cache.h',
|
||||||
|
'<(src_loc)/lottie/lottie_common.cpp',
|
||||||
'<(src_loc)/lottie/lottie_common.h',
|
'<(src_loc)/lottie/lottie_common.h',
|
||||||
'<(src_loc)/lottie/lottie_frame_renderer.cpp',
|
'<(src_loc)/lottie/lottie_frame_renderer.cpp',
|
||||||
'<(src_loc)/lottie/lottie_frame_renderer.h',
|
'<(src_loc)/lottie/lottie_frame_renderer.h',
|
||||||
|
'<(src_loc)/lottie/lottie_player.h',
|
||||||
|
'<(src_loc)/lottie/lottie_single_player.cpp',
|
||||||
|
'<(src_loc)/lottie/lottie_single_player.h',
|
||||||
],
|
],
|
||||||
'conditions': [[ 'build_macold', {
|
'conditions': [[ 'build_macold', {
|
||||||
'xcode_settings': {
|
'xcode_settings': {
|
||||||
|
|
Loading…
Reference in New Issue