summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf4
-rw-r--r--src/bodymovin/beziereasing.cpp2
-rw-r--r--src/bodymovin/bmbase.cpp22
-rw-r--r--src/bodymovin/bmbase_p.h14
-rw-r--r--src/bodymovin/bmconstants_p.h14
-rw-r--r--src/bodymovin/bmgroup.cpp10
-rw-r--r--src/bodymovin/bmlayer.cpp8
-rw-r--r--src/bodymovin/bmproperty_p.h2
-rw-r--r--src/bodymovin/bmshape.cpp70
-rw-r--r--src/bodymovin/bmshape_p.h8
-rw-r--r--src/bodymovin/bmshapelayer.cpp6
-rw-r--r--src/bodymovin/trimpath.cpp6
-rw-r--r--src/imports/imports.pro6
-rw-r--r--src/imports/lottieanimation.cpp256
-rw-r--r--src/imports/lottieanimation.h39
-rw-r--r--src/imports/qmldir3
-rw-r--r--src/imports/rasterrenderer/batchrenderer.cpp138
-rw-r--r--src/imports/rasterrenderer/batchrenderer.h21
-rw-r--r--src/imports/rasterrenderer/lottierasterrenderer.cpp1
-rw-r--r--tests/auto/bodymovin/shape/shapetransform/tst_bmshapetransform.cpp11
-rw-r--r--tests/auto/imports/tst_main.qml2
21 files changed, 309 insertions, 334 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 16ea641..3e66c5a 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,4 +1,6 @@
load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.13.1
+DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST
+
+MODULE_VERSION = 5.14.0
diff --git a/src/bodymovin/beziereasing.cpp b/src/bodymovin/beziereasing.cpp
index 5a76531..a14db8a 100644
--- a/src/bodymovin/beziereasing.cpp
+++ b/src/bodymovin/beziereasing.cpp
@@ -39,7 +39,7 @@ void BezierEasing::addCubicBezierSegment(const QPointF &c1, const QPointF &c2, c
qreal BezierEasing::valueForProgress(qreal progress) const
{
qreal res = mBezier.pointAt(tForX(progress)).y();
- return qBound(0.0, res, 1.0);
+ return qBound(qreal(0.0), res, qreal(1.0));
}
qreal BezierEasing::tForX(qreal x) const
diff --git a/src/bodymovin/bmbase.cpp b/src/bodymovin/bmbase.cpp
index 859137b..c86e38a 100644
--- a/src/bodymovin/bmbase.cpp
+++ b/src/bodymovin/bmbase.cpp
@@ -46,10 +46,10 @@ BMBase::BMBase(const BMBase &other)
m_hidden = other.m_hidden;
m_name = other.m_name;
m_autoOrient = other.m_autoOrient;
- for (BMBase *child : qAsConst(other.m_children)) {
+ for (BMBase *child : other.m_children) {
BMBase *clone = child->clone();
clone->setParent(this);
- addChild(clone);
+ appendChild(clone);
}
}
@@ -93,17 +93,14 @@ void BMBase::setType(int type)
m_type = type;
}
-void BMBase::addChild(BMBase *child, bool priority)
+void BMBase::prependChild(BMBase *child)
{
- if (priority)
- m_children.push_front(child);
- else
- m_children.push_back(child);
+ m_children.push_front(child);
}
-QList<BMBase *> &BMBase::children()
+void BMBase::appendChild(BMBase *child)
{
- return m_children;
+ m_children.push_back(child);
}
BMBase *BMBase::findChild(const QString &childName)
@@ -192,11 +189,6 @@ bool BMBase::hidden() const
return m_hidden;
}
-BMBase *BMBase::parent() const
-{
- return m_parent;
-}
-
void BMBase::setParent(BMBase *parent)
{
m_parent = parent;
@@ -234,6 +226,8 @@ const QJsonObject BMBase::resolveExpression(const QJsonObject &definition)
"to a group that has"
"many children. The"
"first is be picked";
+ } else {
+ qCWarning(lcLottieQtBodymovinParser) << "Failed to find specified effect" << effect;
}
// Let users of the json know that it is originated from expression,
diff --git a/src/bodymovin/bmbase_p.h b/src/bodymovin/bmbase_p.h
index efbd4c0..90818dc 100644
--- a/src/bodymovin/bmbase_p.h
+++ b/src/bodymovin/bmbase_p.h
@@ -74,10 +74,13 @@ public:
virtual bool active(int frame) const;
bool hidden() const;
- BMBase *parent() const;
+ inline BMBase *parent() const { return m_parent; }
void setParent(BMBase *parent);
- void addChild(BMBase *child, bool priority = false);
- QList<BMBase *>& children();
+
+ const QList<BMBase *> &children() const { return m_children; }
+ void prependChild(BMBase *child);
+ void appendChild(BMBase *child);
+
virtual BMBase *findChild(const QString &childName);
virtual void updateProperties(int frame);
@@ -95,13 +98,14 @@ protected:
QString m_name;
QString m_matchName;
bool m_autoOrient = false;
- BMBase *m_parent = nullptr;
- QList<BMBase *> m_children;
friend class BMRasterRenderer;
friend class BMRenderer;
private:
+ BMBase *m_parent = nullptr;
+ QList<BMBase *> m_children;
+
// Handle to the topmost element on which this element resides
// Will be resolved when traversing effects
BMBase *m_topRoot = nullptr;
diff --git a/src/bodymovin/bmconstants_p.h b/src/bodymovin/bmconstants_p.h
index 046e633..a88b49d 100644
--- a/src/bodymovin/bmconstants_p.h
+++ b/src/bodymovin/bmconstants_p.h
@@ -55,20 +55,6 @@
#define BM_EFFECT_FILL 0x20000
-#define BM_SHAPE_ELLIPSE_STR "el"
-#define BM_SHAPE_FILL_STR "fl"
-#define BM_SHAPE_GFILL_STR "gf"
-#define BM_SHAPE_GSTROKE_STR "gs"
-#define BM_SHAPE_GROUP_STR "gr"
-#define BM_SHAPE_RECT_STR "rc"
-#define BM_SHAPE_ROUND_STR "rd"
-#define BM_SHAPE_SHAPE_STR "sh"
-#define BM_SHAPE_STAR_STR "sr"
-#define BM_SHAPE_STROKE_STR "st"
-#define BM_SHAPE_TRIM_STR "tm"
-#define BM_SHAPE_TRANSFORM_STR "tr"
-#define BM_SHAPE_REPEATER_STR "rp"
-
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcLottieQtBodymovinParser);
diff --git a/src/bodymovin/bmgroup.cpp b/src/bodymovin/bmgroup.cpp
index 126a181..ed13f8c 100644
--- a/src/bodymovin/bmgroup.cpp
+++ b/src/bodymovin/bmgroup.cpp
@@ -68,9 +68,9 @@ void BMGroup::construct(const QJsonObject &definition)
// Transform affects how group contents are drawn.
// It must be traversed first when drawing
if (shape->type() == BM_SHAPE_TRANS_IX)
- addChild(shape, true);
+ prependChild(shape);
else
- addChild(shape);
+ appendChild(shape);
}
}
}
@@ -79,7 +79,7 @@ void BMGroup::updateProperties(int frame)
{
BMShape::updateProperties(frame);
- for (BMBase *child : qAsConst(m_children)) {
+ for (BMBase *child : children()) {
if (child->hidden())
continue;
@@ -109,7 +109,7 @@ void BMGroup::render(LottieRenderer &renderer) const
} else
renderer.setTrimmingState(LottieRenderer::Off);
- for (BMBase *child : qAsConst(m_children)) {
+ for (BMBase *child : children()) {
if (child->hidden())
continue;
child->render(renderer);
@@ -135,7 +135,7 @@ void BMGroup::applyTrim(const BMTrimPath &trimmer)
// Setting a friendly name helps in testing
m_appliedTrim->setName(QStringLiteral("Inherited from") + trimmer.name());
- for (BMBase *child : qAsConst(m_children)) {
+ for (BMBase *child : children()) {
BMShape *shape = static_cast<BMShape*>(child);
if (shape->acceptsTrim())
shape->applyTrim(*m_appliedTrim);
diff --git a/src/bodymovin/bmlayer.cpp b/src/bodymovin/bmlayer.cpp
index 5cf781c..57a88ff 100644
--- a/src/bodymovin/bmlayer.cpp
+++ b/src/bodymovin/bmlayer.cpp
@@ -56,7 +56,7 @@ BMLayer::BMLayer(const BMLayer &other)
if (other.m_effects) {
m_effects = new BMBase;
for (BMBase *effect : other.m_effects->children())
- m_effects->addChild(effect->clone());
+ m_effects->appendChild(effect->clone());
}
//m_transformAtFirstFrame = other.m_transformAtFirstFrame;
}
@@ -249,7 +249,7 @@ void BMLayer::parseEffects(const QJsonArray &definition, BMBase *effectRoot)
{
BMBase *slider = new BMBase;
slider->parse(effect);
- effectRoot->addChild(slider);
+ effectRoot->appendChild(slider);
break;
}
case 5:
@@ -257,7 +257,7 @@ void BMLayer::parseEffects(const QJsonArray &definition, BMBase *effectRoot)
if (effect.value(QLatin1String("en")).toInt()) {
BMBase *group = new BMBase;
group->parse(effect);
- effectRoot->addChild(group);
+ effectRoot->appendChild(group);
parseEffects(effect.value(QLatin1String("ef")).toArray(), group);
}
break;
@@ -266,7 +266,7 @@ void BMLayer::parseEffects(const QJsonArray &definition, BMBase *effectRoot)
{
BMFillEffect *fill = new BMFillEffect;
fill->construct(effect);
- effectRoot->addChild(fill);
+ effectRoot->appendChild(fill);
break;
}
default:
diff --git a/src/bodymovin/bmproperty_p.h b/src/bodymovin/bmproperty_p.h
index 6f00468..5ab4a7a 100644
--- a/src/bodymovin/bmproperty_p.h
+++ b/src/bodymovin/bmproperty_p.h
@@ -366,7 +366,7 @@ public:
qreal easedValue = easing->easing.valueForProgress(progress);
// For the time being, 4D vectors are used only for colors, and
// the value must be restricted to between [0, 1]
- easedValue = qBound(0.0, easedValue, 1.0);
+ easedValue = qBound(qreal(0.0), easedValue, qreal(1.0));
T sv = easing->startValue;
T ev = easing->endValue;
qreal x = sv.x() + easedValue * (ev.x() - sv.x());
diff --git a/src/bodymovin/bmshape.cpp b/src/bodymovin/bmshape.cpp
index 098787c..dd80b45 100644
--- a/src/bodymovin/bmshape.cpp
+++ b/src/bodymovin/bmshape.cpp
@@ -48,10 +48,6 @@
QT_BEGIN_NAMESPACE
-const QMap<QLatin1String, int> BMShape::m_shapeMap =
- BMShape::setShapeMap();
-
-
BMShape::BMShape(const BMShape &other)
: BMBase(other)
{
@@ -65,119 +61,111 @@ BMBase *BMShape::clone() const
return new BMShape(*this);
}
-QMap<QLatin1String, int> BMShape::setShapeMap()
-{
- QMap<QLatin1String, int> shapeMap;
- shapeMap.insert(QLatin1String(BM_SHAPE_ELLIPSE_STR), BM_SHAPE_ELLIPSE_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_FILL_STR), BM_SHAPE_FILL_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_GFILL_STR), BM_SHAPE_GFILL_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_GSTROKE_STR), BM_SHAPE_GSTROKE_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_GROUP_STR), BM_SHAPE_GROUP_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_RECT_STR), BM_SHAPE_RECT_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_ROUND_STR), BM_SHAPE_ROUND_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_SHAPE_STR), BM_SHAPE_SHAPE_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_STAR_STR), BM_SHAPE_STAR_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_STROKE_STR), BM_SHAPE_STROKE_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_TRIM_STR), BM_SHAPE_TRIM_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_TRANSFORM_STR), BM_SHAPE_TRANS_IX);
- shapeMap.insert(QLatin1String(BM_SHAPE_REPEATER_STR), BM_SHAPE_REPEATER_IX);
- return shapeMap;
-}
-
-BMShape *BMShape::construct(QJsonObject definition, BMBase *parent, int constructAs)
+BMShape *BMShape::construct(QJsonObject definition, BMBase *parent)
{
qCDebug(lcLottieQtBodymovinParser) << "BMShape::construct()";
BMShape *shape = nullptr;
- QByteArray type = definition.value(QLatin1String("ty")).toVariant().toByteArray();
+ const QByteArray type = definition.value(QLatin1String("ty")).toString().toLatin1();
+
+ if (Q_UNLIKELY(type.size() != 2)) {
+ qCWarning(lcLottieQtBodymovinParser) << "Unsupported shape type:"
+ << type;
+ return shape;
+ }
- int typeToBuild = m_shapeMap.value(QLatin1String(type.data()), -1);
+#define BM_SHAPE_TAG(c1, c2) int((quint32(c1)<<8) | quint32(c2))
- if (constructAs != BM_SHAPE_ANY_TYPE_IX)
- typeToBuild = constructAs;
+ int typeToBuild = BM_SHAPE_TAG(type[0], type[1]);
switch (typeToBuild) {
- case BM_SHAPE_GROUP_IX:
+ case BM_SHAPE_TAG('g', 'r'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse group";
shape = new BMGroup(definition, parent);
shape->setType(BM_SHAPE_GROUP_IX);
break;
}
- case BM_SHAPE_RECT_IX:
+ case BM_SHAPE_TAG('r', 'c'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse m_rect";
shape = new BMRect(definition, parent);
shape->setType(BM_SHAPE_RECT_IX);
break;
}
- case BM_SHAPE_FILL_IX:
+ case BM_SHAPE_TAG('f', 'l'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse fill";
shape = new BMFill(definition, parent);
shape->setType(BM_SHAPE_FILL_IX);
break;
}
- case BM_SHAPE_GFILL_IX:
+ case BM_SHAPE_TAG('g', 'f'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse group fill";
shape = new BMGFill(definition, parent);
shape->setType(BM_SHAPE_GFILL_IX);
break;
}
- case BM_SHAPE_STROKE_IX:
+ case BM_SHAPE_TAG('s', 't'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse stroke";
shape = new BMStroke(definition, parent);
shape->setType(BM_SHAPE_STROKE_IX);
break;
}
- case BM_SHAPE_TRANS_IX:
+ case BM_SHAPE_TAG('t', 'r'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse shape transform";
shape = new BMShapeTransform(definition, parent);
shape->setType(BM_SHAPE_TRANS_IX);
break;
}
- case BM_SHAPE_ELLIPSE_IX:
+ case BM_SHAPE_TAG('e', 'l'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse ellipse";
- shape = new BMEllipse(definition);
+ shape = new BMEllipse(definition, parent);
shape->setType(BM_SHAPE_ELLIPSE_IX);
break;
}
- case BM_SHAPE_ROUND_IX:
+ case BM_SHAPE_TAG('r', 'd'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse round";
shape = new BMRound(definition, parent);
- shape->setType(BM_SHAPE_ELLIPSE_IX);
+ shape->setType(BM_SHAPE_ROUND_IX);
break;
}
- case BM_SHAPE_SHAPE_IX:
+ case BM_SHAPE_TAG('s', 'h'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse shape";
shape = new BMFreeFormShape(definition, parent);
shape->setType(BM_SHAPE_SHAPE_IX);
break;
}
- case BM_SHAPE_TRIM_IX:
+ case BM_SHAPE_TAG('t', 'm'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse trim path";
shape = new BMTrimPath(definition, parent);
shape->setType(BM_SHAPE_TRIM_IX);
break;
}
- case BM_SHAPE_REPEATER_IX:
+ case BM_SHAPE_TAG('r', 'p'):
{
qCDebug(lcLottieQtBodymovinParser) << "Parse trim path";
shape = new BMRepeater(definition, parent);
shape->setType(BM_SHAPE_REPEATER_IX);
break;
}
+ case BM_SHAPE_TAG('g', 's'): // ### BM_SHAPE_GSTROKE_IX
+ case BM_SHAPE_TAG('s', 'r'): // ### BM_SHAPE_STAR_IX
+ // fall through
default:
qCWarning(lcLottieQtBodymovinParser) << "Unsupported shape type:"
<< type;
}
+
+#undef BM_SHAPE_TAG
+
return shape;
}
diff --git a/src/bodymovin/bmshape_p.h b/src/bodymovin/bmshape_p.h
index 43ca20c..97caad6 100644
--- a/src/bodymovin/bmshape_p.h
+++ b/src/bodymovin/bmshape_p.h
@@ -41,7 +41,6 @@
// We mean it.
//
-#include <QLatin1String>
#include <QPainterPath>
#include <QtBodymovin/private/bmbase_p.h>
@@ -76,7 +75,7 @@ public:
BMBase *clone() const override;
- static BMShape *construct(QJsonObject definition, BMBase *parent = nullptr, int constructAs = BM_SHAPE_ANY_TYPE_IX);
+ static BMShape *construct(QJsonObject definition, BMBase *parent = nullptr);
virtual const QPainterPath &path() const;
virtual bool acceptsTrim() const;
@@ -88,11 +87,6 @@ protected:
QPainterPath m_path;
BMTrimPath *m_appliedTrim = nullptr;
int m_direction = 0;
-
-private:
- static QMap<QLatin1String, int> setShapeMap();
-
- static const QMap<QLatin1String, int> m_shapeMap;
};
QT_END_NAMESPACE
diff --git a/src/bodymovin/bmshapelayer.cpp b/src/bodymovin/bmshapelayer.cpp
index 4d50fd2..164f100 100644
--- a/src/bodymovin/bmshapelayer.cpp
+++ b/src/bodymovin/bmshapelayer.cpp
@@ -78,7 +78,7 @@ BMShapeLayer::BMShapeLayer(const QJsonObject &definition)
itemIt--;
BMShape *shape = BMShape::construct((*itemIt).toObject(), this);
if (shape)
- addChild(shape);
+ appendChild(shape);
}
if (m_maskProperties.length())
@@ -104,7 +104,7 @@ void BMShapeLayer::updateProperties(int frame)
m_layerTransform->updateProperties(frame);
- for (BMBase *child : qAsConst(m_children)) {
+ for (BMBase *child : children()) {
if (child->hidden())
continue;
@@ -141,7 +141,7 @@ void BMShapeLayer::render(LottieRenderer &renderer) const
m_layerTransform->render(renderer);
- for (BMBase *child :qAsConst(m_children)) {
+ for (BMBase *child : children()) {
if (child->hidden())
continue;
child->render(renderer);
diff --git a/src/bodymovin/trimpath.cpp b/src/bodymovin/trimpath.cpp
index 1cd124b..d02b52c 100644
--- a/src/bodymovin/trimpath.cpp
+++ b/src/bodymovin/trimpath.cpp
@@ -44,8 +44,8 @@ QPainterPath TrimPath::trimmed(qreal f1, qreal f2, qreal offset) const
if (mPath.isEmpty() || !mPath.elementAt(0).isMoveTo())
return res;
- f1 = qBound(0.0, f1, 1.0);
- f2 = qBound(0.0, f2, 1.0);
+ f1 = qBound(qreal(0.0), f1, qreal(1.0));
+ f2 = qBound(qreal(0.0), f2, qreal(1.0));
if (qFuzzyCompare(f1, f2))
return res;
if (f1 > f2)
@@ -54,7 +54,7 @@ QPainterPath TrimPath::trimmed(qreal f1, qreal f2, qreal offset) const
return mPath;
qreal dummy;
- offset = modf(offset, &dummy); // Use only the fractional part of offset, range <-1, 1>
+ offset = std::modf(offset, &dummy); // Use only the fractional part of offset, range <-1, 1>
qreal of1 = f1 + offset;
qreal of2 = f2 + offset;
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 72ad546..6297272 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,10 +1,9 @@
CXX_MODULE = qtlottie
-TARGET = lottieqt
+TARGET = lottieqtplugin
TARGETPATH = Qt/labs/lottieqt
IMPORT_VERSION = 1.0
QT += qml quick gui-private bodymovin-private
-CONFIG += plugin c++11
QMAKE_DOCS = $$PWD/doc/qtlottieanimation.qdocconf
@@ -21,4 +20,7 @@ HEADERS += \
rasterrenderer/lottierasterrenderer.h \
rasterrenderer/batchrenderer.h
+OTHER_FILES += \
+ qmldir
+
load(qml_plugin)
diff --git a/src/imports/lottieanimation.cpp b/src/imports/lottieanimation.cpp
index 5a489f3..6d72151 100644
--- a/src/imports/lottieanimation.cpp
+++ b/src/imports/lottieanimation.cpp
@@ -42,6 +42,7 @@
#include <QMetaObject>
#include <QLoggingCategory>
#include <QThread>
+#include <QQmlFile>
#include <math.h>
#include <QtBodymovin/private/bmbase_p.h>
@@ -87,7 +88,7 @@ Q_LOGGING_CATEGORY(lcLottieQtBodymovinParser, "qt.lottieqt.bodymovin.parser");
LottieAnimation {
loops: 2
quality: LottieAnimation.MediumQuality
- source: ":/animation.json"
+ source: "animation.json"
autoPlay: false
onStatusChanged: {
if (status === LottieAnimation.Ready) {
@@ -130,39 +131,6 @@ Q_LOGGING_CATEGORY(lcLottieQtBodymovinParser, "qt.lottieqt.bodymovin.parser");
*/
/*!
- \qmlproperty enumeration LottieAnimation::status
-
- This property holds the current status of the LottieAnimation element.
-
- \value LottieAnimation.Null
- An initial value that is used when the status is not defined
- (Default)
-
- \value LottieAnimation.Loading
- The player is loading a Bodymovin file
-
- \value LottieAnimation.Ready
- Loading has finished successfully and the player is ready to play
- the animation
-
- \value LottieAnimation.Error
- An error occurred while loading the animation
-
- For example, you could implement \c onStatusChanged signal
- handler to monitor progress of loading an animation as follows:
-
- \qml
- LottieAnimation {
- source: ":/animation.json"
- autoPlay: false
- onStatusChanged: {
- if (status === LottieAnimation.Ready)
- start();
- }
- \endqml
-*/
-
-/*!
\qmlproperty bool LottieAnimation::autoPlay
Defines whether the player will start playing animation automatically after
@@ -192,17 +160,12 @@ LottieAnimation::LottieAnimation(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
m_frameAdvance = new QTimer(this);
+ m_frameAdvance->setInterval(1000 / m_frameRate);
m_frameAdvance->setSingleShot(false);
connect (m_frameAdvance, &QTimer::timeout, this, &LottieAnimation::renderNextFrame);
m_frameRenderThread = BatchRenderer::instance();
- QByteArray cacheStr = qgetenv("QLOTTIE_RENDER_CACHE_SIZE");
- bool ok = false;
- int cacheSize = cacheStr.toInt(&ok);
- if (ok)
- m_frameRenderThread->setCacheSize(cacheSize);
-
qRegisterMetaType<LottieAnimation*>();
}
@@ -213,22 +176,14 @@ LottieAnimation::~LottieAnimation()
void LottieAnimation::componentComplete()
{
- QQuickItem::componentComplete();
+ QQuickPaintedItem::componentComplete();
- m_initialized = true;
- if (m_source.length())
- loadSource(m_source);
+ if (m_source.isValid())
+ load();
}
void LottieAnimation::paint(QPainter *painter)
{
- // TODO: Check does this have effect on output quality (or performance)
- if (m_quality != LowQuality)
- painter->setRenderHints(QPainter::Antialiasing);
- if (m_quality == HighQuality)
- painter->setRenderHints(QPainter::SmoothPixmapTransform);
-
- LottieRasterRenderer renderer(painter);
BMBase* bmTree = m_frameRenderThread->getFrame(this, m_currentFrame);
if (!bmTree) {
@@ -237,6 +192,8 @@ void LottieAnimation::paint(QPainter *painter)
return;
}
+ LottieRasterRenderer renderer(painter);
+
qCDebug(lcLottieQtBodymovinRender) << static_cast<void*>(this) << "Start to paint frame" << m_currentFrame;
for (BMBase *elem : bmTree->children()) {
@@ -261,26 +218,75 @@ void LottieAnimation::paint(QPainter *painter)
}
/*!
- \qmlproperty string LottieAnimation::source
+ \qmlproperty enumeration LottieAnimation::status
+
+ This property holds the current status of the LottieAnimation element.
+
+ \value LottieAnimation.Null
+ An initial value that is used when the source is not defined
+ (Default)
+
+ \value LottieAnimation.Loading
+ The player is loading a Bodymovin file
+
+ \value LottieAnimation.Ready
+ Loading has finished successfully and the player is ready to play
+ the animation
+
+ \value LottieAnimation.Error
+ An error occurred while loading the animation
+
+ For example, you could implement \c onStatusChanged signal
+ handler to monitor progress of loading an animation as follows:
+
+ \qml
+ LottieAnimation {
+ source: "animation.json"
+ autoPlay: false
+ onStatusChanged: {
+ if (status === LottieAnimation.Ready)
+ start();
+ }
+ \endqml
+*/
+LottieAnimation::Status LottieAnimation::status() const
+{
+ return m_status;
+}
+
+void LottieAnimation::setStatus(LottieAnimation::Status status)
+{
+ if (Q_UNLIKELY(m_status == status))
+ return;
+
+ m_status = status;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty url LottieAnimation::source
- The path of the Bodymovin asset that LottieAnimation plays.
+ The source of the Bodymovin asset that LottieAnimation plays.
+
+ LottieAnimation can handle any URL scheme supported by Qt.
+ The URL may be absolute, or relative to the URL of the component.
Setting the source property starts loading the animation asynchronously.
To monitor progress of loading, connect to the \l status change signal.
*/
-QString LottieAnimation::source() const
+QUrl LottieAnimation::source() const
{
return m_source;
}
-void LottieAnimation::setSource(const QString &source)
+void LottieAnimation::setSource(const QUrl &source)
{
if (m_source != source) {
m_source = source;
emit sourceChanged();
- if (m_initialized)
- loadSource(source);
+ if (isComponentComplete())
+ load();
}
}
@@ -297,6 +303,15 @@ int LottieAnimation::startFrame() const
return m_startFrame;
}
+void LottieAnimation::setStartFrame(int startFrame)
+{
+ if (Q_UNLIKELY(m_startFrame == startFrame))
+ return;
+
+ m_startFrame = startFrame;
+ emit startFrameChanged();
+}
+
/*!
\qmlproperty int LottieAnimation::endFrame
\readonly
@@ -310,6 +325,15 @@ int LottieAnimation::endFrame() const
return m_endFrame;
}
+void LottieAnimation::setEndFrame(int endFrame)
+{
+ if (Q_UNLIKELY(m_endFrame == endFrame))
+ return;
+
+ m_endFrame = endFrame;
+ emit endFrameChanged();
+}
+
int LottieAnimation::currentFrame() const
{
return m_currentFrame;
@@ -326,7 +350,7 @@ int LottieAnimation::currentFrame() const
\qml
LottieAnimation {
- source: ":/animation.json"
+ source: "animation.json"
onStatusChanged: {
if (status === LottieAnimation.Ready)
frameRate = 60;
@@ -340,10 +364,20 @@ int LottieAnimation::frameRate() const
void LottieAnimation::setFrameRate(int frameRate)
{
+ if (Q_UNLIKELY(m_frameRate == frameRate || frameRate <= 0))
+ return;
+
m_frameRate = frameRate;
+ emit frameRateChanged();
+
m_frameAdvance->setInterval(1000 / m_frameRate);
}
+void LottieAnimation::resetFrameRate()
+{
+ setFrameRate(m_animFrameRate);
+}
+
/*!
\qmlproperty enumeration LottieAnimation::quality
@@ -357,7 +391,7 @@ void LottieAnimation::setFrameRate(int frameRate)
used
\value LottieAnimation.MediumQuality
- Antialiasing is used but no smooth pixmap transformation algorithm
+ Smooth pixmap transformation algorithm is used but no antialiasing
(Default)
\value LottieAnimation.HighQuality
@@ -377,6 +411,8 @@ void LottieAnimation::setQuality(LottieAnimation::Quality quality)
setRenderTarget(QQuickPaintedItem::FramebufferObject);
else
setRenderTarget(QQuickPaintedItem::Image);
+ setSmooth(quality != LowQuality);
+ setAntialiasing(quality == HighQuality);
emit qualityChanged();
}
}
@@ -488,6 +524,7 @@ bool LottieAnimation::gotoAndPlay(const QString &frameMarker)
void LottieAnimation::gotoAndStop(int frame)
{
gotoFrame(frame);
+ m_frameAdvance->stop();
renderNextFrame();
}
@@ -541,62 +578,56 @@ double LottieAnimation::getDuration(bool inFrames)
*/
LottieAnimation::Direction LottieAnimation::direction() const
{
- if (m_direction < 0)
- return Reverse;
- else if (m_direction > 0)
- return Forward;
- else {
- Q_UNREACHABLE();
- return Forward;
- }
+ return static_cast<Direction>(m_direction);
}
-void LottieAnimation::setDirection(Direction direction)
+void LottieAnimation::setDirection(LottieAnimation::Direction direction)
{
- if (direction == Forward) {
- m_direction = 1;
- emit directionChanged();
- } else if (direction == Reverse) {
- m_direction = -1;
- emit directionChanged();
- }
+ if (Q_UNLIKELY(static_cast<Direction>(m_direction) == direction))
+ return;
+
+ m_direction = direction;
+ emit directionChanged();
+
+ m_frameRenderThread->gotoFrame(this, m_currentFrame);
}
-bool LottieAnimation::loadSource(QString filename)
+void LottieAnimation::load()
{
- QFile sourceFile(filename);
- if (!sourceFile.open(QIODevice::ReadOnly)) {
- m_status = Error;
- emit statusChanged();
- return false;
- }
+ setStatus(Loading);
- m_status = Loading;
- emit statusChanged();
+ m_file.reset(new QQmlFile(qmlEngine(this), m_source));
+ if (m_file->isLoading())
+ m_file->connectFinished(this, SLOT(loadFinished()));
+ else
+ loadFinished();
+}
- QByteArray json = sourceFile.readAll();
- parse(json);
+void LottieAnimation::loadFinished()
+{
+ if (Q_UNLIKELY(m_file->isError())) {
+ m_file.reset();
+ setStatus(Error);
+ return;
+ }
- setWidth(m_animWidth);
- emit widthChanged();
- setHeight(m_animHeight);
- emit heightChanged();
+ Q_ASSERT(m_file->isReady());
+ const QByteArray json = m_file->dataByteArray();
+ m_file.reset();
- sourceFile.close();
+ if (Q_UNLIKELY(parse(json) == -1)) {
+ setStatus(Error);
+ return;
+ }
QMetaObject::invokeMethod(m_frameRenderThread, "registerAnimator", Q_ARG(LottieAnimation*, this));
- m_frameAdvance->setInterval(1000 / m_frameRate);
-
if (m_autoPlay)
start();
m_frameRenderThread->start();
- m_status = Ready;
- emit statusChanged();
-
- return true;
+ setStatus(Ready);
}
QByteArray LottieAnimation::jsonSource() const
@@ -633,23 +664,24 @@ int LottieAnimation::parse(QByteArray jsonSource)
{
m_jsonSource = jsonSource;
- QJsonDocument doc = QJsonDocument::fromJson(jsonSource);
- QJsonObject rootObj = doc.object();
-
- if (rootObj.empty()) {
- m_status = Error;
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(m_jsonSource, &error);
+ if (Q_UNLIKELY(error.error != QJsonParseError::NoError)) {
+ qCWarning(lcLottieQtBodymovinParser)
+ << "JSON parse error:" << error.errorString();
return -1;
}
- m_startFrame = rootObj.value(QLatin1String("ip")).toVariant().toInt();
- m_endFrame = rootObj.value(QLatin1String("op")).toVariant().toInt();
- m_frameRate = rootObj.value(QLatin1String("fr")).toVariant().toInt();
+ QJsonObject rootObj = doc.object();
+ if (Q_UNLIKELY(rootObj.empty()))
+ return -1;
+
+ int startFrame = rootObj.value(QLatin1String("ip")).toVariant().toInt();
+ int endFrame = rootObj.value(QLatin1String("op")).toVariant().toInt();
+ m_animFrameRate = rootObj.value(QLatin1String("fr")).toVariant().toInt();
m_animWidth = rootObj.value(QLatin1String("w")).toVariant().toReal();
m_animHeight = rootObj.value(QLatin1String("h")).toVariant().toReal();
- setWidth(m_animWidth);
- setHeight(m_animHeight);
-
QJsonArray markerArr = rootObj.value(QLatin1String("markers")).toArray();
QJsonArray::const_iterator markerIt = markerArr.constBegin();
while (markerIt != markerArr.constEnd()) {
@@ -669,9 +701,11 @@ int LottieAnimation::parse(QByteArray jsonSource)
if (rootObj.value(QLatin1String("chars")).toArray().count())
qCWarning(lcLottieQtBodymovinParser) << "chars not supported";
- emit frameRateChanged();
- emit startFrameChanged();
- emit endFrameChanged();
+ setWidth(m_animWidth);
+ setHeight(m_animHeight);
+ setStartFrame(startFrame);
+ setEndFrame(endFrame);
+ setFrameRate(m_animFrameRate);
return 0;
}
diff --git a/src/imports/lottieanimation.h b/src/imports/lottieanimation.h
index a1cc41d..b08ed40 100644
--- a/src/imports/lottieanimation.h
+++ b/src/imports/lottieanimation.h
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
+class QQmlFile;
+
class BMBase;
class BMLayer;
class BatchRenderer;
@@ -48,11 +50,11 @@ class BatchRenderer;
class LottieAnimation : public QQuickPaintedItem
{
Q_OBJECT
- Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
- Q_PROPERTY(int frameRate READ frameRate WRITE setFrameRate NOTIFY frameRateChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(int frameRate READ frameRate WRITE setFrameRate RESET resetFrameRate NOTIFY frameRateChanged)
Q_PROPERTY(int startFrame READ startFrame NOTIFY startFrameChanged)
Q_PROPERTY(int endFrame READ endFrame NOTIFY endFrameChanged)
- Q_PROPERTY(Status status MEMBER m_status NOTIFY statusChanged)
+ Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged)
Q_PROPERTY(Quality quality READ quality WRITE setQuality NOTIFY qualityChanged)
Q_PROPERTY(bool autoPlay MEMBER m_autoPlay NOTIFY autoPlayChanged)
Q_PROPERTY(int loops MEMBER m_loops NOTIFY loopsChanged)
@@ -65,7 +67,7 @@ public:
enum Quality{LowQuality, MediumQuality, HighQuality};
Q_ENUM(Quality)
- enum Direction{Forward = 1, Reverse};
+ enum Direction{Forward = 1, Reverse = -1};
Q_ENUM(Direction)
enum LoopCount{Infinite = -1};
@@ -74,15 +76,16 @@ public:
explicit LottieAnimation(QQuickItem *parent = nullptr);
~LottieAnimation() override;
- void componentComplete() override;
-
void paint(QPainter *painter) override;
- QString source() const;
- void setSource(const QString &source);
+ Status status() const;
+
+ QUrl source() const;
+ void setSource(const QUrl &source);
int frameRate() const;
void setFrameRate(int frameRate);
+ void resetFrameRate();
Quality quality() const;
void setQuality(Quality quality);
@@ -121,10 +124,19 @@ signals:
void endFrameChanged();
protected slots:
+ void loadFinished();
+
void renderNextFrame();
protected:
- bool loadSource(QString filename);
+ void componentComplete() override;
+
+ void setStatus(Status status);
+
+ void setStartFrame(int startFrame);
+ void setEndFrame(int endFrame);
+
+ void load();
virtual int parse(QByteArray jsonSource);
@@ -135,24 +147,25 @@ protected:
Status m_status = Null;
int m_startFrame = 0;
int m_endFrame = 0;
- int m_frameRate = 30;
int m_currentFrame = 0;
+ int m_frameRate = 30;
+ int m_animFrameRate = 30;
qreal m_animWidth = 0;
qreal m_animHeight = 0;
QHash<QString, int> m_markers;
- QString m_source;
+ QUrl m_source;
+ QScopedPointer<QQmlFile> m_file;
QTimer *m_frameAdvance = nullptr;
void gotoFrame(int frame);
void reset();
private:
- bool m_initialized = false;
Quality m_quality = MediumQuality;
bool m_autoPlay = true;
int m_loops = 1;
int m_currentLoop = 0;
- int m_direction = 1;
+ int m_direction = Forward;
QByteArray m_jsonSource;
};
diff --git a/src/imports/qmldir b/src/imports/qmldir
index 8ad0994..a1beae5 100644
--- a/src/imports/qmldir
+++ b/src/imports/qmldir
@@ -1,2 +1,3 @@
module Qt.labs.lottieqt
-plugin lottieqt
+plugin lottieqtplugin
+classname BodymovinPlugin
diff --git a/src/imports/rasterrenderer/batchrenderer.cpp b/src/imports/rasterrenderer/batchrenderer.cpp
index ca7b00e..84e5a2f 100644
--- a/src/imports/rasterrenderer/batchrenderer.cpp
+++ b/src/imports/rasterrenderer/batchrenderer.cpp
@@ -52,10 +52,22 @@ Q_LOGGING_CATEGORY(lcLottieQtBodymovinRenderThread, "qt.lottieqt.bodymovin.rende
BatchRenderer *BatchRenderer::m_rendererInstance = nullptr;
+BatchRenderer::BatchRenderer()
+ : QThread()
+{
+ const QByteArray cacheStr = qgetenv("QLOTTIE_RENDER_CACHE_SIZE");
+ int cacheSize = cacheStr.toInt();
+ if (cacheSize > 0) {
+ qCDebug(lcLottieQtBodymovinRenderThread) << "Setting frame cache size to" << cacheSize;
+ m_cacheSize = cacheSize;
+ }
+}
+
BatchRenderer::~BatchRenderer()
{
+ QMutexLocker mlocker(&m_mutex);
+
qDeleteAll(m_animData);
- qDeleteAll(m_frameCache);
}
BatchRenderer *BatchRenderer::instance()
@@ -79,17 +91,16 @@ void BatchRenderer::registerAnimator(LottieAnimation *animator)
qCDebug(lcLottieQtBodymovinRenderThread) << "Register Animator:"
<< static_cast<void*>(animator);
- Entry *entry = new Entry;
+ Entry *&entry = m_animData[animator];
+ Q_ASSERT(entry == nullptr);
+ entry = new Entry;
entry->animator = animator;
entry->startFrame = animator->startFrame();
entry->endFrame = animator->endFrame();
entry->currentFrame = animator->startFrame();
- if (animator->direction() == LottieAnimation::Reverse)
- entry->animDir = -1;
- // animDir == 1 by default
+ entry->animDir = animator->direction();
entry->bmTreeBlueprint = new BMBase;
parse(entry->bmTreeBlueprint, animator->jsonSource());
- m_animData.insert(animator, entry);
m_waitCondition.wakeAll();
}
@@ -100,24 +111,25 @@ void BatchRenderer::deregisterAnimator(LottieAnimation *animator)
qCDebug(lcLottieQtBodymovinRenderThread) << "Deregister Animator:"
<< static_cast<void*>(animator);
- Entry *entry = m_animData.value(animator, nullptr);
+ Entry *entry = m_animData.take(animator);
if (entry) {
qDeleteAll(entry->frameCache);
delete entry->bmTreeBlueprint;
delete entry;
- m_animData.remove(animator);
}
}
bool BatchRenderer::gotoFrame(LottieAnimation *animator, int frame)
{
+ QMutexLocker mlocker(&m_mutex);
+
Entry *entry = m_animData.value(animator, nullptr);
if (entry) {
- QMutexLocker mlocker(&m_mutex);
qCDebug(lcLottieQtBodymovinRenderThread) << "Animator:"
<< static_cast<void*>(animator)
<< "Goto frame:" << frame;
entry->currentFrame = frame;
+ entry->animDir = animator->direction();
pruneFrameCache(entry);
m_waitCondition.wakeAll();
return true;
@@ -128,11 +140,13 @@ bool BatchRenderer::gotoFrame(LottieAnimation *animator, int frame)
void BatchRenderer::pruneFrameCache(Entry* e)
{
QHash<int, BMBase*>::iterator it = e->frameCache.begin();
-
while (it != e->frameCache.end()) {
- if (it.key() == e->currentFrame) {
+ int frame = it.key();
+ if ((frame - e->currentFrame) * e->animDir >= 0) { // same frame or same direction
++it;
} else {
+ qCDebug(lcLottieQtBodymovinRenderThread) << "Animator:" << static_cast<void*>(e->animator)
+ << "Remove frame from cache" << frame;
delete it.value();
it = e->frameCache.erase(it);
}
@@ -150,47 +164,24 @@ BMBase *BatchRenderer::getFrame(LottieAnimation *animator, int frameNumber)
return nullptr;
}
-void BatchRenderer::setCacheSize(int size)
-{
- if (size < 1 || isRunning())
- return;
-
- qCDebug(lcLottieQtBodymovinRenderThread) << "Setting frame cache size to" << size;
- m_cacheSize = size;
-}
-
void BatchRenderer::prerender(Entry *animEntry)
{
- LottieAnimation *animator = animEntry->animator;
-
- if (animEntry->frameCache.count() == m_cacheSize) {
- qCDebug(lcLottieQtBodymovinRenderThread) << "Animator:" << static_cast<void*>(animEntry->animator)
- << "Cache full, cannot render more";
- return;
- }
-
while (animEntry->frameCache.count() < m_cacheSize) {
- // It may be that the animator has deregistered itself while
- // te mutex was locked. In that case we cannot render here anymore
- if (!animEntry->bmTreeBlueprint)
- break;
-
- if (!animEntry->frameCache.contains(animEntry->currentFrame)) {
- BMBase *bmTree = new BMBase(*animEntry->bmTreeBlueprint);
+ BMBase *&bmTree = animEntry->frameCache[animEntry->currentFrame];
+ if (bmTree == nullptr) {
+ bmTree = new BMBase(*animEntry->bmTreeBlueprint);
for (BMBase *elem : bmTree->children()) {
if (elem->active(animEntry->currentFrame))
elem->updateProperties( animEntry->currentFrame);
}
-
- animEntry->frameCache.insert( animEntry->currentFrame, bmTree);
}
qCDebug(lcLottieQtBodymovinRenderThread) << "Animator:"
<< static_cast<void*>(animEntry->animator)
<< "Frame drawn to cache. FN:"
<< animEntry->currentFrame;
- emit frameReady(animator, animEntry->currentFrame);
+ emit frameReady(animEntry->animator, animEntry->currentFrame);
animEntry->currentFrame += animEntry->animDir;
@@ -202,42 +193,20 @@ void BatchRenderer::prerender(Entry *animEntry)
}
}
-void BatchRenderer::prerender()
+void BatchRenderer::frameRendered(LottieAnimation *animator, int frameNumber)
{
QMutexLocker mlocker(&m_mutex);
- bool wait = true;
- foreach (Entry *e, m_animData) {
- if (e->frameCache.size() < m_cacheSize) {
- wait = false;
- break;
- }
- }
-
- if (wait)
- m_waitCondition.wait(&m_mutex);
-
- QHash<LottieAnimation*, Entry*>::iterator it = m_animData.begin();
- while (it != m_animData.end()) {
- Entry *e = *it;
- if (e && e->frameCache.size() < m_cacheSize)
- prerender(e);
- ++it;
- }
-}
-
-void BatchRenderer::frameRendered(LottieAnimation *animator, int frameNumber)
-{
Entry *entry = m_animData.value(animator, nullptr);
if (entry) {
qCDebug(lcLottieQtBodymovinRenderThread) << "Animator:" << static_cast<void*>(animator)
<< "Remove frame from cache" << frameNumber;
- QMutexLocker mlocker(&m_mutex);
- BMBase *root = entry->frameCache.value(frameNumber, nullptr);
- delete root;
- entry->frameCache.remove(frameNumber);
- m_waitCondition.wakeAll();
+ BMBase *root = entry->frameCache.take(frameNumber);
+ if (root != nullptr) {
+ delete root;
+ m_waitCondition.wakeAll();
+ }
}
}
@@ -245,15 +214,17 @@ void BatchRenderer::run()
{
qCDebug(lcLottieQtBodymovinRenderThread) << "rendering thread" << QThread::currentThread();
- while (-1) {
- if (QThread::currentThread()->isInterruptionRequested())
- return;
+ while (!isInterruptionRequested()) {
+ QMutexLocker mlocker(&m_mutex);
+
+ for (Entry *e : qAsConst(m_animData))
+ prerender(e);
- prerender();
+ m_waitCondition.wait(&m_mutex);
}
}
-int BatchRenderer::parse(BMBase* rootElement, QByteArray jsonSource)
+int BatchRenderer::parse(BMBase *rootElement, const QByteArray &jsonSource) const
{
QJsonDocument doc = QJsonDocument::fromJson(jsonSource);
QJsonObject rootObj = doc.object();
@@ -269,24 +240,13 @@ int BatchRenderer::parse(BMBase* rootElement, QByteArray jsonSource)
BMLayer *layer = BMLayer::construct(jsonLayer);
if (layer) {
layer->setParent(rootElement);
- rootElement->addChild(layer);
- }
- }
-
- // Mask layers must be rendered before the layers they affect to
- // although they appear before in layer hierarchy. For this reason
- // move a mask after the affected layers, so it will be rendered first
- QList<BMBase *> &layers = rootElement->children();
- int moveTo = -1;
- for (int i = 0; i < layers.count(); i++) {
- BMLayer *layer = static_cast<BMLayer*>(layers.at(i));
- if (layer->isClippedLayer())
- moveTo = i;
- if (layer->isMaskLayer()) {
- qCDebug(lcLottieQtBodymovinParser()) << "Move mask layer"
- << layers.at(i)->name()
- << "before" << layers.at(moveTo)->name();
- layers.move(i, moveTo);
+ // Mask layers must be rendered before the layers they affect to
+ // although they appear before in layer hierarchy. For this reason
+ // move a mask after the affected layers, so it will be rendered first
+ if (layer->isMaskLayer())
+ rootElement->prependChild(layer);
+ else
+ rootElement->appendChild(layer);
}
}
diff --git a/src/imports/rasterrenderer/batchrenderer.h b/src/imports/rasterrenderer/batchrenderer.h
index b5f0985..7e5830e 100644
--- a/src/imports/rasterrenderer/batchrenderer.h
+++ b/src/imports/rasterrenderer/batchrenderer.h
@@ -57,7 +57,7 @@ class BatchRenderer : public QThread
};
public:
- virtual ~BatchRenderer();
+ ~BatchRenderer() override;
BatchRenderer(BatchRenderer const &) = delete;
void operator=(BatchRenderer const&) = delete;
@@ -77,26 +77,16 @@ public slots:
bool gotoFrame(LottieAnimation *animator, int frame);
void frameRendered(LottieAnimation *animator, int frameNumber);
- void setCacheSize(int size);
protected:
- virtual void run();
+ void run() override;
- int parse(BMBase* rootElement, QByteArray jsonSource);
+ int parse(BMBase *rootElement, const QByteArray &jsonSource) const;
- void prerender();
void prerender(Entry *animEntry);
-protected:
- QHash<LottieAnimation*, Entry*> m_animData;
- int m_cacheSize = 2;
- int m_currentFrame = 0;
-
- LottieAnimation *m_animation = nullptr;
- QHash<int, QImage*> m_frameCache;
-
private:
- BatchRenderer() = default;
+ BatchRenderer();
void pruneFrameCache(Entry* e);
@@ -105,6 +95,9 @@ private:
QMutex m_mutex;
QWaitCondition m_waitCondition;
+
+ int m_cacheSize = 2;
+ QHash<LottieAnimation *, Entry *> m_animData;
};
QT_END_NAMESPACE
diff --git a/src/imports/rasterrenderer/lottierasterrenderer.cpp b/src/imports/rasterrenderer/lottierasterrenderer.cpp
index 0d7ff3d..4224027 100644
--- a/src/imports/rasterrenderer/lottierasterrenderer.cpp
+++ b/src/imports/rasterrenderer/lottierasterrenderer.cpp
@@ -35,7 +35,6 @@
#include <QTransform>
#include <QGradient>
#include <QPointer>
-#include <QVectorIterator>
#include <QtBodymovin/private/bmshape_p.h>
#include <QtBodymovin/private/bmfill_p.h>
diff --git a/tests/auto/bodymovin/shape/shapetransform/tst_bmshapetransform.cpp b/tests/auto/bodymovin/shape/shapetransform/tst_bmshapetransform.cpp
index 4a5e78a..bd4ebb5 100644
--- a/tests/auto/bodymovin/shape/shapetransform/tst_bmshapetransform.cpp
+++ b/tests/auto/bodymovin/shape/shapetransform/tst_bmshapetransform.cpp
@@ -489,11 +489,16 @@ void tst_BMShapeTransform::loadTestData(const QByteArray &filename)
BMGroup* group = nullptr;
while (shapesIt != shapes.end()) {
QJsonObject childObj = (*shapesIt).toObject();
- QByteArray type = childObj.value(QLatin1String("ty")).toVariant().toByteArray();
- if (QLatin1String(type.data()) == QLatin1String(BM_SHAPE_GROUP_STR))
- group = new BMGroup(childObj);
+ BMShape *shape = BMShape::construct(childObj);
+ QVERIFY(shape != nullptr);
+ if (shape->type() == BM_SHAPE_GROUP_IX) {
+ group = static_cast<BMGroup *>(shape);
+ break;
+ }
shapesIt++;
}
+ QVERIFY(group != nullptr);
+
m_transform = static_cast<BMShapeTransform*>(group->findChild("Transform"));
QVERIFY(m_transform != nullptr);
diff --git a/tests/auto/imports/tst_main.qml b/tests/auto/imports/tst_main.qml
index 788d385..6e59da9 100644
--- a/tests/auto/imports/tst_main.qml
+++ b/tests/auto/imports/tst_main.qml
@@ -43,7 +43,7 @@ Item {
x: 0
y: 0
quality: LottieAnimation.HighQuality
- source: ":/rec_pos_col_opa.json"
+ source: "rec_pos_col_opa.json"
onFinished: {
bmAnim.start();