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