Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
172 lines
4.5 KiB
C++
172 lines
4.5 KiB
C++
// This file is part of Desktop App Toolkit,
|
|
// a set of libraries for developing nice desktop applications.
|
|
//
|
|
// For license and copyright information please follow this link:
|
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
|
//
|
|
#include "lottie/details/lottie_frame_provider_direct.h"
|
|
|
|
#include "lottie/lottie_wrap.h"
|
|
#include "lottie/details/lottie_frame_renderer.h"
|
|
#include "ui/image/image_prepare.h"
|
|
|
|
#include <rlottie.h>
|
|
|
|
namespace Lottie {
|
|
namespace {
|
|
|
|
int GetLottieFrameRate(not_null<rlottie::Animation*> animation, Quality quality) {
|
|
const auto rate = int(qRound(animation->frameRate()));
|
|
return (quality == Quality::Default && rate == 60) ? (rate / 2) : rate;
|
|
}
|
|
|
|
int GetLottieFramesCount(not_null<rlottie::Animation*> animation, Quality quality) {
|
|
const auto rate = int(qRound(animation->frameRate()));
|
|
const auto count = int(animation->totalFrame());
|
|
return (quality == Quality::Default && rate == 60)
|
|
? ((count + 1) / 2)
|
|
: count;
|
|
}
|
|
|
|
int GetLottieFrameIndex(not_null<rlottie::Animation*> animation, Quality quality, int index) {
|
|
const auto rate = int(qRound(animation->frameRate()));
|
|
return (quality == Quality::Default && rate == 60) ? (index * 2) : index;
|
|
}
|
|
|
|
[[nodiscard]] rlottie::FitzModifier MapModifier(SkinModifier modifier) {
|
|
using Result = rlottie::FitzModifier;
|
|
switch (modifier) {
|
|
case SkinModifier::None: return Result::None;
|
|
case SkinModifier::Color1: return Result::Type12;
|
|
case SkinModifier::Color2: return Result::Type3;
|
|
case SkinModifier::Color3: return Result::Type4;
|
|
case SkinModifier::Color4: return Result::Type5;
|
|
case SkinModifier::Color5: return Result::Type6;
|
|
}
|
|
Unexpected("Unexpected modifier in MapModifier.");
|
|
}
|
|
|
|
} // namespace
|
|
|
|
FrameProviderDirect::FrameProviderDirect(Quality quality)
|
|
: _quality(quality) {
|
|
}
|
|
|
|
FrameProviderDirect::~FrameProviderDirect() = default;
|
|
|
|
bool FrameProviderDirect::load(
|
|
const QByteArray &content,
|
|
const ColorReplacements *replacements) {
|
|
_information = Information();
|
|
|
|
const auto string = ReadUtf8(Images::UnpackGzip(content));
|
|
if (string.size() > kMaxFileSize) {
|
|
return false;
|
|
}
|
|
|
|
_animation = LoadAnimationFromData(
|
|
string,
|
|
std::string(),
|
|
std::string(),
|
|
false,
|
|
(replacements
|
|
? replacements->replacements
|
|
: std::vector<std::pair<std::uint32_t, std::uint32_t>>()),
|
|
(replacements
|
|
? MapModifier(replacements->modifier)
|
|
: rlottie::FitzModifier::None));
|
|
if (!_animation) {
|
|
return false;
|
|
}
|
|
auto width = size_t(0);
|
|
auto height = size_t(0);
|
|
_animation->size(width, height);
|
|
const auto rate = GetLottieFrameRate(_animation.get(), _quality);
|
|
const auto count = GetLottieFramesCount(_animation.get(), _quality);
|
|
return setInformation({
|
|
.size = QSize(int(width), int(height)),
|
|
.frameRate = int(rate),
|
|
.framesCount = int(count),
|
|
});
|
|
}
|
|
|
|
bool FrameProviderDirect::loaded() const {
|
|
return (_animation != nullptr);
|
|
}
|
|
|
|
void FrameProviderDirect::unload() {
|
|
_animation = nullptr;
|
|
}
|
|
|
|
bool FrameProviderDirect::setInformation(Information information) {
|
|
if (information.size.isEmpty()
|
|
|| information.size.width() > kMaxSize
|
|
|| information.size.height() > kMaxSize
|
|
|| !information.frameRate
|
|
|| information.frameRate > kMaxFrameRate
|
|
|| !information.framesCount
|
|
|| information.framesCount > kMaxFramesCount) {
|
|
return false;
|
|
}
|
|
_information = information;
|
|
return true;
|
|
}
|
|
|
|
const Information &FrameProviderDirect::information() {
|
|
return _information;
|
|
}
|
|
|
|
bool FrameProviderDirect::valid() {
|
|
return _information.framesCount > 0;
|
|
}
|
|
|
|
QImage FrameProviderDirect::construct(
|
|
std::unique_ptr<FrameProviderToken> &token,
|
|
const FrameRequest &request) {
|
|
auto cover = QImage();
|
|
render(token, cover, request, 0);
|
|
return cover;
|
|
}
|
|
|
|
int FrameProviderDirect::sizeRounding() {
|
|
return 2;
|
|
}
|
|
|
|
bool FrameProviderDirect::render(
|
|
const std::unique_ptr<FrameProviderToken> &token,
|
|
QImage &to,
|
|
const FrameRequest &request,
|
|
int index) {
|
|
if (token && !token->exclusive) {
|
|
token->result = FrameRenderResult::NotReady;
|
|
return false;
|
|
} else if (!valid()) {
|
|
return false;
|
|
}
|
|
const auto original = information().size;
|
|
const auto size = request.box.isEmpty()
|
|
? original
|
|
: request.size(original, sizeRounding());
|
|
if (!GoodStorageForFrame(to, size)) {
|
|
to = CreateFrameStorage(size);
|
|
}
|
|
renderToPrepared(to, index);
|
|
return true;
|
|
}
|
|
|
|
void FrameProviderDirect::renderToPrepared(
|
|
QImage &to,
|
|
int index) const {
|
|
to.fill(Qt::transparent);
|
|
auto surface = rlottie::Surface(
|
|
reinterpret_cast<uint32_t*>(to.bits()),
|
|
to.width(),
|
|
to.height(),
|
|
to.bytesPerLine());
|
|
_animation->renderSync(
|
|
GetLottieFrameIndex(_animation.get(), _quality, index),
|
|
surface);
|
|
}
|
|
|
|
} // namespace Lottie
|