Revision control
Copy as Markdown
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qlottietrimpath_p.h"
#include <QtGlobal>
#include <private/qpainterpath_p.h>
#include <private/qbezier_p.h>
#include "qlottieconstants_p.h"
QLottieTrimPath::QLottieTrimPath(QLottieBase *parent)
{
m_appliedTrim.reset(this, OwnsAppliedTrim::No);
setParent(parent);
}
QLottieTrimPath::QLottieTrimPath(const QLottieTrimPath &other)
: QLottieShape(other)
{
m_start = other.m_start;
m_end = other.m_end;
m_offset = other.m_offset;
m_isParallel = other.m_isParallel;
}
QLottieBase *QLottieTrimPath::clone() const
{
return new QLottieTrimPath(*this);
}
int QLottieTrimPath::parse(const QJsonObject &definition)
{
QLottieBase::parse(definition);
if (m_hidden)
return 0;
qCDebug(lcLottieQtLottieParser) << "QLottieTrimPath::parse():" << m_name;
if (!checkRequiredKeys(definition, "Trim path"_L1, { "o"_L1, "s"_L1, "e"_L1 }, m_name))
return -1;
QJsonObject start = definition.value("s"_L1).toObject();
start = resolveExpression(start);
m_start.construct(start);
QJsonObject end = definition.value("e"_L1).toObject();
end = resolveExpression(end);
m_end.construct(end);
// Simplify: a constant 100% trim is a noop, just skip it
if (!m_start.isAnimated() && !m_end.isAnimated()
&& m_start.value() == 0 && m_end.value() == 100) {
return -2;
}
QJsonObject offset = definition.value("o"_L1).toObject();
offset = resolveExpression(offset);
m_offset.construct(offset);
const int multiMode = definition.value("m"_L1).toInt();
m_isParallel = (multiMode != 2);
if (strcmp(qgetenv("QLOTTIE_FORCE_TRIM_MODE"), "sequential") == 0) {
qCDebug(lcLottieQtLottieRender) << "Forcing trim mode to Sequential";
m_isParallel = true;
} else if (strcmp(qgetenv("QLOTTIE_FORCE_TRIM_MODE"), "parallel") == 0) {
qCDebug(lcLottieQtLottieRender) << "Forcing trim mode to Parallel";
m_isParallel = false;
}
return 0;
}
void QLottieTrimPath::updateProperties(int frame)
{
m_start.update(frame);
m_end.update(frame);
m_offset.update(frame);
qCDebug(lcLottieQtLottieUpdate) << name() << frame << m_start.value()
<< m_end.value() << m_offset.value();
QLottieShape::updateProperties(frame);
}
void QLottieTrimPath::render(QLottieRenderer &renderer) const
{
if (QLottieTrimPath *appliedTrim = m_appliedTrim.data()) {
if (appliedTrim->isParallel())
renderer.setTrimmingState(QLottieRenderer::Parallel);
else
renderer.setTrimmingState(QLottieRenderer::Sequential);
} else
renderer.setTrimmingState(QLottieRenderer::Off);
renderer.render(*this);
}
bool QLottieTrimPath::acceptsTrim() const
{
return true;
}
void QLottieTrimPath::applyTrim(const QLottieTrimPath &other)
{
qCDebug(lcLottieQtLottieUpdate) << "Join trim paths:"
<< other.name() << "into:" << name();
m_name = m_name + QStringLiteral(" & ") + other.name();
qreal newStart = other.start() + (m_start.value() / 100.0) *
(other.end() - other.start());
qreal newEnd = other.start() + (m_end.value() / 100.0) *
(other.end() - other.start());
m_start.setValue(newStart);
m_end.setValue(newEnd);
m_offset.setValue(m_offset.value() + other.offset());
}
qreal QLottieTrimPath::start() const
{
return m_start.value();
}
qreal QLottieTrimPath::end() const
{
return m_end.value();
}
qreal QLottieTrimPath::offset() const
{
return m_offset.value();
}
bool QLottieTrimPath::isParallel() const
{
return m_isParallel;
}
QPainterPath QLottieTrimPath::trim(const QPainterPath &path) const
{
if (isStructureDumping())
return path;
qreal offset = m_offset.value() / 360.0;
qreal start = m_start.value() / 100.0;
qreal end = m_end.value() / 100.0;
return path.trimmed(start, end, offset);
}