| 1 | // Copyright (C) 2018 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only | 
| 3 |  | 
| 4 | #include "bmtrimpath_p.h" | 
| 5 |  | 
| 6 | #include <QtGlobal> | 
| 7 | #include <private/qpainterpath_p.h> | 
| 8 | #include <private/qbezier_p.h> | 
| 9 |  | 
| 10 | #include "bmconstants_p.h" | 
| 11 | #include "trimpath_p.h" | 
| 12 |  | 
| 13 | BMTrimPath::BMTrimPath() | 
| 14 | { | 
| 15 |     m_appliedTrim = this; | 
| 16 | } | 
| 17 |  | 
| 18 | BMTrimPath::BMTrimPath(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) | 
| 19 | { | 
| 20 |     m_appliedTrim = this; | 
| 21 |  | 
| 22 |     setParent(parent); | 
| 23 |     construct(definition, version); | 
| 24 | } | 
| 25 |  | 
| 26 | BMTrimPath::BMTrimPath(const BMTrimPath &other) | 
| 27 |     : BMShape(other) | 
| 28 | { | 
| 29 |     m_start = other.m_start; | 
| 30 |     m_end = other.m_end; | 
| 31 |     m_offset = other.m_offset; | 
| 32 |     m_simultaneous = other.m_simultaneous; | 
| 33 | } | 
| 34 |  | 
| 35 | BMBase *BMTrimPath::clone() const | 
| 36 | { | 
| 37 |     return new BMTrimPath(*this); | 
| 38 | } | 
| 39 |  | 
| 40 | void BMTrimPath::construct(const QJsonObject &definition, const QVersionNumber &version) | 
| 41 | { | 
| 42 |     BMBase::parse(definition); | 
| 43 |     if (m_hidden) | 
| 44 |         return; | 
| 45 |  | 
| 46 |     qCDebug(lcLottieQtBodymovinParser) << "BMTrimPath::construct():"  << m_name; | 
| 47 |  | 
| 48 |     QJsonObject start = definition.value(key: QLatin1String("s" )).toObject(); | 
| 49 |     start = resolveExpression(definition: start); | 
| 50 |     m_start.construct(definition: start, version); | 
| 51 |  | 
| 52 |     QJsonObject end = definition.value(key: QLatin1String("e" )).toObject(); | 
| 53 |     end = resolveExpression(definition: end); | 
| 54 |     m_end.construct(definition: end, version); | 
| 55 |  | 
| 56 |     QJsonObject offset = definition.value(key: QLatin1String("o" )).toObject(); | 
| 57 |     offset = resolveExpression(definition: offset); | 
| 58 |     m_offset.construct(definition: offset, version); | 
| 59 |  | 
| 60 |     int simultaneous = true; | 
| 61 |     if (definition.contains(key: QLatin1String("m" ))) { | 
| 62 |         simultaneous = definition.value(key: QLatin1String("m" )).toInt(); | 
| 63 |     } | 
| 64 |     m_simultaneous = (simultaneous == 1); | 
| 65 |  | 
| 66 |     if (strcmp(s1: qgetenv(varName: "QLOTTIE_FORCE_TRIM_MODE" ), s2: "simultaneous" ) == 0) { | 
| 67 |         qCDebug(lcLottieQtBodymovinRender) << "Forcing trim mode to Simultaneous" ; | 
| 68 |         m_simultaneous = true; | 
| 69 |     } else if (strcmp(s1: qgetenv(varName: "QLOTTIE_FORCE_TRIM_MODE" ), s2: "individual" ) == 0) { | 
| 70 |         qCDebug(lcLottieQtBodymovinRender) << "Forcing trim mode to Individual" ; | 
| 71 |         m_simultaneous = false; | 
| 72 |     } | 
| 73 | } | 
| 74 |  | 
| 75 | void BMTrimPath::updateProperties(int frame) | 
| 76 | { | 
| 77 |     m_start.update(frame); | 
| 78 |     m_end.update(frame); | 
| 79 |     m_offset.update(frame); | 
| 80 |  | 
| 81 |     qCDebug(lcLottieQtBodymovinUpdate) << name() << frame << m_start.value() | 
| 82 |                                        << m_end.value() << m_offset.value(); | 
| 83 |  | 
| 84 |     BMShape::updateProperties(frame); | 
| 85 | } | 
| 86 |  | 
| 87 | void BMTrimPath::render(LottieRenderer &renderer) const | 
| 88 | { | 
| 89 |     if (m_appliedTrim) { | 
| 90 |         if (m_appliedTrim->simultaneous()) | 
| 91 |             renderer.setTrimmingState(LottieRenderer::Simultaneous); | 
| 92 |         else | 
| 93 |             renderer.setTrimmingState(LottieRenderer::Individual); | 
| 94 |     } else | 
| 95 |         renderer.setTrimmingState(LottieRenderer::Off); | 
| 96 |  | 
| 97 |     renderer.render(trans: *this); | 
| 98 | } | 
| 99 |  | 
| 100 | bool BMTrimPath::acceptsTrim() const | 
| 101 | { | 
| 102 |     return true; | 
| 103 | } | 
| 104 |  | 
| 105 | void BMTrimPath::applyTrim(const BMTrimPath &other) | 
| 106 | { | 
| 107 |      qCDebug(lcLottieQtBodymovinUpdate) << "Join trim paths:"  | 
| 108 |                                         << other.name() << "into:"  << name(); | 
| 109 |  | 
| 110 |     m_name = m_name + QStringLiteral(" & " ) + other.name(); | 
| 111 |     qreal newStart = other.start() + (m_start.value() / 100.0) * | 
| 112 |             (other.end() - other.start()); | 
| 113 |     qreal newEnd = other.start() + (m_end.value() / 100.0) * | 
| 114 |             (other.end() - other.start()); | 
| 115 |  | 
| 116 |     m_start.setValue(newStart); | 
| 117 |     m_end.setValue(newEnd); | 
| 118 |     m_offset.setValue(m_offset.value() + other.offset()); | 
| 119 | } | 
| 120 |  | 
| 121 | qreal BMTrimPath::start() const | 
| 122 | { | 
| 123 |     return m_start.value(); | 
| 124 | } | 
| 125 |  | 
| 126 | qreal BMTrimPath::end() const | 
| 127 | { | 
| 128 |     return m_end.value(); | 
| 129 | } | 
| 130 |  | 
| 131 | qreal BMTrimPath::offset() const | 
| 132 | { | 
| 133 |     return m_offset.value(); | 
| 134 | } | 
| 135 |  | 
| 136 | bool BMTrimPath::simultaneous() const | 
| 137 | { | 
| 138 |     return m_simultaneous; | 
| 139 | } | 
| 140 |  | 
| 141 | QPainterPath BMTrimPath::trim(const QPainterPath &path) const | 
| 142 | { | 
| 143 |     TrimPath trimmer; | 
| 144 |     trimmer.setPath(path); | 
| 145 |     qreal offset = m_offset.value() / 360.0; | 
| 146 |     qreal start = m_start.value() / 100.0; | 
| 147 |     qreal end = m_end.value() / 100.0; | 
| 148 |     QPainterPath trimmedPath; | 
| 149 |     if (!qFuzzyIsNull(d: start - end)) | 
| 150 |         trimmedPath = trimmer.trimmed(f1: start, f2: end, offset); | 
| 151 |     return trimmedPath; | 
| 152 | } | 
| 153 |  |