1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #ifndef LOTTIEPROXYMODEL_H
20 #define LOTTIEPROXYMODEL_H
21 
22 #include<bitset>
23 #include<algorithm>
24 #include<cassert>
25 #include "lottiemodel.h"
26 #include "rlottie.h"
27 
28 // Naive way to implement std::variant
29 // refactor it when we move to c++17
30 // users should make sure proper combination
31 // of id and value are passed while creating the object.
32 class LOTVariant
33 {
34 public:
35     using ValueFunc = std::function<float(const rlottie::FrameInfo &)>;
36     using ColorFunc = std::function<rlottie::Color(const rlottie::FrameInfo &)>;
37     using PointFunc = std::function<rlottie::Point(const rlottie::FrameInfo &)>;
38     using SizeFunc = std::function<rlottie::Size(const rlottie::FrameInfo &)>;
39 
LOTVariant(rlottie::Property prop,const ValueFunc & v)40     LOTVariant(rlottie::Property prop, const ValueFunc &v):mPropery(prop), mTag(Value)
41     {
42         construct(impl.valueFunc, v);
43     }
44 
LOTVariant(rlottie::Property prop,ValueFunc && v)45     LOTVariant(rlottie::Property prop, ValueFunc &&v):mPropery(prop), mTag(Value)
46     {
47         moveConstruct(impl.valueFunc, std::move(v));
48     }
49 
LOTVariant(rlottie::Property prop,const ColorFunc & v)50     LOTVariant(rlottie::Property prop, const ColorFunc &v):mPropery(prop), mTag(Color)
51     {
52         construct(impl.colorFunc, v);
53     }
54 
LOTVariant(rlottie::Property prop,ColorFunc && v)55     LOTVariant(rlottie::Property prop, ColorFunc &&v):mPropery(prop), mTag(Color)
56     {
57         moveConstruct(impl.colorFunc, std::move(v));
58     }
59 
LOTVariant(rlottie::Property prop,const PointFunc & v)60     LOTVariant(rlottie::Property prop, const PointFunc &v):mPropery(prop), mTag(Point)
61     {
62         construct(impl.pointFunc, v);
63     }
64 
LOTVariant(rlottie::Property prop,PointFunc && v)65     LOTVariant(rlottie::Property prop, PointFunc &&v):mPropery(prop), mTag(Point)
66     {
67         moveConstruct(impl.pointFunc, std::move(v));
68     }
69 
LOTVariant(rlottie::Property prop,const SizeFunc & v)70     LOTVariant(rlottie::Property prop, const SizeFunc &v):mPropery(prop), mTag(Size)
71     {
72         construct(impl.sizeFunc, v);
73     }
74 
LOTVariant(rlottie::Property prop,SizeFunc && v)75     LOTVariant(rlottie::Property prop, SizeFunc &&v):mPropery(prop), mTag(Size)
76     {
77         moveConstruct(impl.sizeFunc, std::move(v));
78     }
79 
property()80     rlottie::Property property() const { return mPropery; }
81 
color()82     const ColorFunc& color() const
83     {
84         assert(mTag == Color);
85         return impl.colorFunc;
86     }
87 
value()88     const ValueFunc& value() const
89     {
90         assert(mTag == Value);
91         return impl.valueFunc;
92     }
93 
point()94     const PointFunc& point() const
95     {
96         assert(mTag == Point);
97         return impl.pointFunc;
98     }
99 
size()100     const SizeFunc& size() const
101     {
102         assert(mTag == Size);
103         return impl.sizeFunc;
104     }
105 
106     LOTVariant() = default;
~LOTVariant()107     ~LOTVariant() noexcept {Destroy();}
LOTVariant(const LOTVariant & other)108     LOTVariant(const LOTVariant& other) { Copy(other);}
LOTVariant(LOTVariant && other)109     LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other));}
110     LOTVariant& operator=(LOTVariant&& other) { Destroy(); Move(std::move(other)); return *this;}
111     LOTVariant& operator=(const LOTVariant& other) { Destroy(); Copy(other); return *this;}
112 private:
113     template <typename T>
construct(T & member,const T & val)114     void construct(T& member, const T& val)
115     {
116         new (&member) T(val);
117     }
118 
119     template <typename T>
moveConstruct(T & member,T && val)120     void moveConstruct(T& member, T&& val)
121     {
122         new (&member) T(std::move(val));
123     }
124 
Move(LOTVariant && other)125     void Move(LOTVariant&& other)
126     {
127         switch (other.mTag) {
128         case Type::Value:
129             moveConstruct(impl.valueFunc, std::move(other.impl.valueFunc));
130             break;
131         case Type::Color:
132             moveConstruct(impl.colorFunc, std::move(other.impl.colorFunc));
133             break;
134         case Type::Point:
135             moveConstruct(impl.pointFunc, std::move(other.impl.pointFunc));
136             break;
137         case Type::Size:
138             moveConstruct(impl.sizeFunc, std::move(other.impl.sizeFunc));
139             break;
140         default:
141             break;
142         }
143         mTag = other.mTag;
144         mPropery = other.mPropery;
145         other.mTag = MonoState;
146     }
147 
Copy(const LOTVariant & other)148     void Copy(const LOTVariant& other)
149     {
150         switch (other.mTag) {
151         case Type::Value:
152             construct(impl.valueFunc, other.impl.valueFunc);
153             break;
154         case Type::Color:
155             construct(impl.colorFunc, other.impl.colorFunc);
156             break;
157         case Type::Point:
158             construct(impl.pointFunc, other.impl.pointFunc);
159             break;
160         case Type::Size:
161             construct(impl.sizeFunc, other.impl.sizeFunc);
162             break;
163         default:
164             break;
165         }
166         mTag = other.mTag;
167         mPropery = other.mPropery;
168     }
169 
Destroy()170     void Destroy()
171     {
172         switch(mTag) {
173         case MonoState: {
174             break;
175         }
176         case Value: {
177             impl.valueFunc.~ValueFunc();
178             break;
179         }
180         case Color: {
181             impl.colorFunc.~ColorFunc();
182             break;
183         }
184         case Point: {
185             impl.pointFunc.~PointFunc();
186             break;
187         }
188         case Size: {
189             impl.sizeFunc.~SizeFunc();
190             break;
191         }
192         }
193     }
194 
195     enum Type {MonoState, Value, Color, Point , Size};
196     rlottie::Property mPropery;
197     Type              mTag{MonoState};
198     union details{
199       ColorFunc   colorFunc;
200       ValueFunc   valueFunc;
201       PointFunc   pointFunc;
202       SizeFunc    sizeFunc;
details()203       details(){}
~details()204       ~details(){}
205     }impl;
206 };
207 
208 class LOTFilter
209 {
210 public:
addValue(LOTVariant & value)211     void addValue(LOTVariant &value)
212     {
213         uint index = static_cast<uint>(value.property());
214         if (mBitset.test(index)) {
215             std::replace_if(mFilters.begin(),
216                             mFilters.end(),
217                             [&value](const LOTVariant &e) {return e.property() == value.property();},
218                             value);
219         } else {
220             mBitset.set(index);
221             mFilters.push_back(value);
222         }
223     }
224 
removeValue(LOTVariant & value)225     void removeValue(LOTVariant &value)
226     {
227         uint index = static_cast<uint>(value.property());
228         if (mBitset.test(index)) {
229             mBitset.reset(index);
230             mFilters.erase(std::remove_if(mFilters.begin(),
231                                           mFilters.end(),
232                                           [&value](const LOTVariant &e) {return e.property() == value.property();}),
233                            mFilters.end());
234         }
235     }
hasFilter(rlottie::Property prop)236     bool hasFilter(rlottie::Property prop) const
237     {
238         return mBitset.test(static_cast<uint>(prop));
239     }
color(rlottie::Property prop,int frame)240     LottieColor color(rlottie::Property prop, int frame) const
241     {
242         rlottie::FrameInfo info(frame);
243         rlottie::Color col = data(prop).color()(info);
244         return LottieColor(col.r(), col.g(), col.b());
245     }
opacity(rlottie::Property prop,int frame)246     float opacity(rlottie::Property prop, int frame) const
247     {
248         rlottie::FrameInfo info(frame);
249         float val = data(prop).value()(info);
250         return val/100;
251     }
value(rlottie::Property prop,int frame)252     float value(rlottie::Property prop, int frame) const
253     {
254         rlottie::FrameInfo info(frame);
255         return data(prop).value()(info);
256     }
257 private:
data(rlottie::Property prop)258     const LOTVariant& data(rlottie::Property prop) const
259     {
260         auto result = std::find_if(mFilters.begin(),
261                                    mFilters.end(),
262                                    [prop](const LOTVariant &e){return e.property() == prop;});
263         return *result;
264     }
265     std::bitset<32>            mBitset{0};
266     std::vector<LOTVariant>    mFilters;
267 };
268 
269 template <typename T>
270 class LOTProxyModel
271 {
272 public:
LOTProxyModel(T * model)273     LOTProxyModel(T *model): _modelData(model) {}
filter()274     LOTFilter& filter() {return mFilter;}
name()275     const std::string & name() const {return _modelData->name();}
color(int frame)276     LottieColor color(int frame) const
277     {
278         if (mFilter.hasFilter(rlottie::Property::StrokeColor)) {
279             return mFilter.color(rlottie::Property::StrokeColor, frame);
280         }
281         return _modelData->color(frame);
282     }
opacity(int frame)283     float opacity(int frame) const
284     {
285         if (mFilter.hasFilter(rlottie::Property::StrokeOpacity)) {
286             return mFilter.opacity(rlottie::Property::StrokeOpacity, frame);
287         }
288         return _modelData->opacity(frame);
289     }
strokeWidth(int frame)290     float strokeWidth(int frame) const
291     {
292         if (mFilter.hasFilter(rlottie::Property::StrokeWidth)) {
293             return mFilter.value(rlottie::Property::StrokeWidth, frame);
294         }
295         return _modelData->strokeWidth(frame);
296     }
miterLimit()297     float miterLimit() const {return _modelData->miterLimit();}
capStyle()298     CapStyle capStyle() const {return _modelData->capStyle();}
joinStyle()299     JoinStyle joinStyle() const {return _modelData->joinStyle();}
hasDashInfo()300     bool hasDashInfo() const { return _modelData->hasDashInfo();}
getDashInfo(int frameNo,std::vector<float> & result)301     void getDashInfo(int frameNo, std::vector<float>& result) const {
302         return _modelData->getDashInfo(frameNo, result);
303     }
304 
305 private:
306     T                         *_modelData;
307     LOTFilter                  mFilter;
308 };
309 
310 template <>
311 class LOTProxyModel<LOTFillData>
312 {
313 public:
LOTProxyModel(LOTFillData * model)314     LOTProxyModel(LOTFillData *model): _modelData(model) {}
filter()315     LOTFilter& filter() {return mFilter;}
name()316     const std::string & name() const {return _modelData->name();}
color(int frame)317     LottieColor color(int frame) const
318     {
319         if (mFilter.hasFilter(rlottie::Property::FillColor)) {
320             return mFilter.color(rlottie::Property::FillColor, frame);
321         }
322         return _modelData->color(frame);
323     }
opacity(int frame)324     float opacity(int frame) const
325     {
326         if (mFilter.hasFilter(rlottie::Property::FillOpacity)) {
327             return mFilter.opacity(rlottie::Property::FillOpacity, frame);
328         }
329         return _modelData->opacity(frame);
330     }
fillRule()331     FillRule fillRule() const {return _modelData->fillRule();}
332 private:
333     LOTFillData               *_modelData;
334     LOTFilter                  mFilter;
335 };
336 
337 #endif // LOTTIEITEM_H
338