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