| 1 | // Copyright (C) 2018 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only | 
| 3 |  | 
| 4 | #include "bmstroke_p.h" | 
| 5 |  | 
| 6 | #include <QLoggingCategory> | 
| 7 |  | 
| 8 | #include "bmconstants_p.h" | 
| 9 |  | 
| 10 | QT_BEGIN_NAMESPACE | 
| 11 |  | 
| 12 | BMStroke::BMStroke(const BMStroke &other) | 
| 13 |     : BMShape(other) | 
| 14 | { | 
| 15 |     m_opacity = other.m_opacity; | 
| 16 |     m_width = other.m_width; | 
| 17 |     m_color = other.m_color; | 
| 18 |     m_capStyle = other.m_capStyle; | 
| 19 |     m_joinStyle = other.m_joinStyle; | 
| 20 |     m_miterLimit = other.m_miterLimit; | 
| 21 |     m_dashOffset = other.m_dashOffset; | 
| 22 |     m_dashLength = other.m_dashLength; | 
| 23 |     m_dashGap = other.m_dashGap; | 
| 24 |     m_isDashed = other.m_isDashed; | 
| 25 | } | 
| 26 |  | 
| 27 | BMStroke::BMStroke(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) | 
| 28 | { | 
| 29 |     setParent(parent); | 
| 30 |  | 
| 31 |     BMBase::parse(definition); | 
| 32 |     if (m_hidden) | 
| 33 |         return; | 
| 34 |  | 
| 35 |     qCDebug(lcLottieQtBodymovinParser) << "BMStroke::BMStroke()"  << m_name; | 
| 36 |  | 
| 37 |     int lineCap = definition.value(key: QLatin1String("lc" )).toVariant().toInt(); | 
| 38 |     switch (lineCap) { | 
| 39 |     case 1: | 
| 40 |         m_capStyle = Qt::FlatCap; | 
| 41 |         break; | 
| 42 |     case 2: | 
| 43 |         m_capStyle = Qt::RoundCap; | 
| 44 |         break; | 
| 45 |     case 3: | 
| 46 |         m_capStyle = Qt::SquareCap; | 
| 47 |         break; | 
| 48 |     default: | 
| 49 |         qCDebug(lcLottieQtBodymovinParser) << "Unknown line cap style in BMStroke" ; | 
| 50 |     } | 
| 51 |  | 
| 52 |     int lineJoin = definition.value(key: QLatin1String("lj" )).toVariant().toInt(); | 
| 53 |     switch (lineJoin) { | 
| 54 |     case 1: | 
| 55 |         m_joinStyle = Qt::MiterJoin; | 
| 56 |         m_miterLimit = definition.value(key: QLatin1String("ml" )).toVariant().toReal(); | 
| 57 |         break; | 
| 58 |     case 2: | 
| 59 |         m_joinStyle = Qt::RoundJoin; | 
| 60 |         break; | 
| 61 |     case 3: | 
| 62 |         m_joinStyle = Qt::BevelJoin; | 
| 63 |         break; | 
| 64 |     default: | 
| 65 |         qCDebug(lcLottieQtBodymovinParser) << "Unknown line join style in BMStroke" ; | 
| 66 |     } | 
| 67 |  | 
| 68 |     QJsonObject opacity = definition.value(key: QLatin1String("o" )).toObject(); | 
| 69 |     opacity = resolveExpression(definition: opacity); | 
| 70 |     m_opacity.construct(definition: opacity, version); | 
| 71 |  | 
| 72 |     QJsonObject width = definition.value(key: QLatin1String("w" )).toObject(); | 
| 73 |     width = resolveExpression(definition: width); | 
| 74 |     m_width.construct(definition: width, version); | 
| 75 |  | 
| 76 |     QJsonObject color = definition.value(key: QLatin1String("c" )).toObject(); | 
| 77 |     color = resolveExpression(definition: color); | 
| 78 |     m_color.construct(definition: color, version); | 
| 79 |  | 
| 80 |     QJsonArray dashes = definition.value(key: QLatin1String("d" )).toArray(); | 
| 81 |     if (dashes.size()) { | 
| 82 |         auto it = dashes.cend(); | 
| 83 |         while (it != dashes.cbegin()) { | 
| 84 |             --it; | 
| 85 |             QJsonObject dashSpec = it->toObject(); | 
| 86 |             QJsonObject val = resolveExpression(definition: dashSpec.value(key: QLatin1String("v" )).toObject()); | 
| 87 |             QString n = dashSpec.value(key: QLatin1String("n" )).toString(); | 
| 88 |             if (n == QLatin1String("o" )) | 
| 89 |                 m_dashOffset.construct(definition: val, version); | 
| 90 |             else if (n == QLatin1String("g" )) | 
| 91 |                 m_dashGap.construct(definition: val, version); | 
| 92 |             else if (n == QLatin1String("d" )) | 
| 93 |                 m_dashLength.construct(definition: val, version); | 
| 94 |         } | 
| 95 |         m_isDashed = true; | 
| 96 |     } | 
| 97 | } | 
| 98 |  | 
| 99 | BMBase *BMStroke::clone() const | 
| 100 | { | 
| 101 |     return new BMStroke(*this); | 
| 102 | } | 
| 103 |  | 
| 104 | void BMStroke::updateProperties(int frame) | 
| 105 | { | 
| 106 |     m_opacity.update(frame); | 
| 107 |     m_width.update(frame); | 
| 108 |     m_color.update(frame); | 
| 109 |     if (m_isDashed) { | 
| 110 |         m_dashOffset.update(frame); | 
| 111 |         m_dashLength.update(frame); | 
| 112 |         m_dashGap.update(frame); | 
| 113 |     } | 
| 114 | } | 
| 115 |  | 
| 116 | void BMStroke::render(LottieRenderer &renderer) const | 
| 117 | { | 
| 118 |     renderer.render(stroke: *this); | 
| 119 | } | 
| 120 |  | 
| 121 | QPen BMStroke::pen() const | 
| 122 | { | 
| 123 |     qreal width = m_width.value(); | 
| 124 |     if (qFuzzyIsNull(d: width)) | 
| 125 |         return QPen(Qt::NoPen); | 
| 126 |     QPen pen; | 
| 127 |     pen.setColor(getColor()); | 
| 128 |     pen.setWidthF(width); | 
| 129 |     pen.setCapStyle(m_capStyle); | 
| 130 |     pen.setJoinStyle(m_joinStyle); | 
| 131 |     pen.setMiterLimit(m_miterLimit); | 
| 132 |     if (m_isDashed) { | 
| 133 |         pen.setDashOffset(m_dashOffset.value() / width); | 
| 134 |         pen.setDashPattern({m_dashLength.value() / width, m_dashGap.value() / width}); | 
| 135 |     } | 
| 136 |     return pen; | 
| 137 | } | 
| 138 |  | 
| 139 | QColor BMStroke::getColor() const | 
| 140 | { | 
| 141 |     QVector4D cVec = m_color.value(); | 
| 142 |     QColor color; | 
| 143 |     qreal r = static_cast<qreal>(cVec.x()); | 
| 144 |     qreal g = static_cast<qreal>(cVec.y()); | 
| 145 |     qreal b = static_cast<qreal>(cVec.z()); | 
| 146 |     qreal a = static_cast<qreal>(cVec.w()); | 
| 147 |     color.setRgbF(r, g, b, a); | 
| 148 |     return color; | 
| 149 | } | 
| 150 |  | 
| 151 | qreal BMStroke::opacity() const | 
| 152 | { | 
| 153 |     return m_opacity.value(); | 
| 154 | } | 
| 155 |  | 
| 156 | QT_END_NAMESPACE | 
| 157 |  |