lottie: fixed valgrind warning for unintialized variable
[platform/core/uifw/lottie-player.git] / src / lottie / lottieitem.cpp
1 #include "lottieitem.h"
2 #include"vbitmap.h"
3 #include"vpainter.h"
4 #include"vraster.h"
5 #include"vdasher.h"
6 #include <cmath>
7
8
9 VDrawable::VDrawable():mFlag(DirtyState::All),
10                        mType(Type::Fill),
11                        mFillRule(FillRule::Winding)
12 {
13     mStroke.dashArraySize = 0;
14     mStroke.cap = CapStyle::Round;
15     mStroke.join= JoinStyle::Round;
16     mStroke.meterLimit = 10;
17     mStroke.enable = false;
18 }
19
20 void VDrawable::preprocess()
21 {
22     if (mFlag & (DirtyState::Path)) {
23         if (mStroke.enable) {
24             VPath newPath = mPath;
25             if (mStroke.dashArraySize) {
26                 VDasher dasher(mStroke.dashArray, mStroke.dashArraySize);
27                 newPath = dasher.dashed(mPath);
28             }
29             FTOutline *outline = VRaster::toFTOutline(newPath);
30             mRleTask = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
31                                                               mStroke.width, mStroke.meterLimit);
32         } else {
33             FTOutline *outline = VRaster::toFTOutline(mPath);
34             mRleTask = VRaster::instance().generateFillInfo(outline, mFillRule);
35         }
36         mFlag &= ~DirtyFlag(DirtyState::Path);
37     }
38 }
39
40 VRle VDrawable::rle()
41 {
42     if (mRleTask.valid()) {
43         mRle = std::move(mRleTask.get());
44     }
45     return mRle;
46 }
47
48 void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth)
49 {
50     mStroke.enable = true;
51     mStroke.cap = cap;
52     mStroke.join = join;
53     mStroke.meterLimit = meterLimit;
54     mStroke.width = strokeWidth;
55     mFlag |= DirtyState::Path;
56 }
57 void VDrawable::setDashInfo(float *array, int size)
58 {
59     mStroke.dashArray = array;
60     mStroke.dashArraySize = size;
61     mFlag |= DirtyState::Path;
62 }
63
64 void VDrawable::sync()
65 {
66     mCNode.mFlag = ChangeFlagNone;
67     if (mFlag & DirtyState::None) return;
68
69     if (mFlag & DirtyState::Path) {
70         const std::vector<VPath::Element> &elm = mPath.elements();
71         const std::vector<VPointF> &pts  = mPath.points();
72         const float *ptPtr = reinterpret_cast<const float *>(pts.data());
73         const char *elmPtr = reinterpret_cast<const char *>(elm.data());
74         mCNode.mPath.elmPtr = elmPtr;
75         mCNode.mPath.elmCount = elm.size();
76         mCNode.mPath.ptPtr = ptPtr;
77         mCNode.mPath.ptCount = 2 * pts.size();
78         mCNode.mFlag |= ChangeFlagPath;
79     }
80
81     if (mStroke.enable) {
82         mCNode.mStroke.width = mStroke.width;
83         mCNode.mStroke.meterLimit = mStroke.meterLimit;
84         mCNode.mStroke.enable = 1;
85
86         switch (mFillRule) {
87         case FillRule::EvenOdd:
88             mCNode.mFillRule = LOTNode::EvenOdd;
89             break;
90         default:
91             mCNode.mFillRule = LOTNode::Winding;
92             break;
93         }
94
95         switch (mStroke.cap) {
96         case CapStyle::Flat:
97             mCNode.mStroke.cap = LOTNode::FlatCap;
98             break;
99         case CapStyle::Square:
100             mCNode.mStroke.cap = LOTNode::SquareCap;
101             break;
102         case CapStyle::Round:
103             mCNode.mStroke.cap = LOTNode::RoundCap;
104             break;
105         default:
106             mCNode.mStroke.cap = LOTNode::FlatCap;
107             break;
108         }
109
110         switch (mStroke.join) {
111         case JoinStyle::Miter:
112             mCNode.mStroke.join = LOTNode::MiterJoin;
113             break;
114         case JoinStyle::Bevel:
115             mCNode.mStroke.join = LOTNode::BevelJoin;
116             break;
117         case JoinStyle::Round:
118             mCNode.mStroke.join = LOTNode::RoundJoin;
119             break;
120         default:
121             mCNode.mStroke.join = LOTNode::MiterJoin;
122             break;
123         }
124
125         mCNode.mStroke.dashArray = mStroke.dashArray;
126         mCNode.mStroke.dashArraySize = mStroke.dashArraySize;
127
128     } else {
129         mCNode.mStroke.enable = 0;
130     }
131
132     switch (mBrush.type()) {
133     case VBrush::Type::Solid:
134         mCNode.mType = LOTNode::BrushSolid;
135         mCNode.mColor.r = mBrush.mColor.r;
136         mCNode.mColor.g = mBrush.mColor.g;
137         mCNode.mColor.b = mBrush.mColor.b;
138         mCNode.mColor.a = mBrush.mColor.a;
139         break;
140     case VBrush::Type::LinearGradient:
141         mCNode.mType = LOTNode::BrushGradient;
142         mCNode.mGradient.type = LOTNode::Gradient::Linear;
143         mCNode.mGradient.start.x = mBrush.mGradient->linear.x1;
144         mCNode.mGradient.start.y = mBrush.mGradient->linear.y1;
145         mCNode.mGradient.end.x = mBrush.mGradient->linear.x2;
146         mCNode.mGradient.end.y = mBrush.mGradient->linear.y2;
147         break;
148     case VBrush::Type::RadialGradient:
149         mCNode.mType = LOTNode::BrushGradient;
150         mCNode.mGradient.type = LOTNode::Gradient::Radial;
151         mCNode.mGradient.center.x = mBrush.mGradient->radial.cx;
152         mCNode.mGradient.center.y = mBrush.mGradient->radial.cy;
153         mCNode.mGradient.focal.x = mBrush.mGradient->radial.fx;
154         mCNode.mGradient.focal.y = mBrush.mGradient->radial.fy;
155         mCNode.mGradient.cradius = mBrush.mGradient->radial.cradius;
156         mCNode.mGradient.fradius = mBrush.mGradient->radial.fradius;
157         break;
158     default:
159         break;
160     }
161 }
162
163 /* Lottie Layer Rules
164  * 1. time stretch is pre calculated and applied to all the properties of the lottilayer model and all its children
165  * 2. The frame property could be reversed using,time-reverse layer property in AE. which means (start frame > endFrame)
166  * 3.
167  */
168
169 LOTCompItem::LOTCompItem(LOTModel *model):mRootModel(model), mUpdateViewBox(false),mCurFrameNo(-1)
170 {
171    // 1. build layer item list
172    mCompData = model->mRoot.get();
173    for(auto i : mCompData->mChildren) {
174       LOTLayerData *layerData = dynamic_cast<LOTLayerData *>(i.get());
175       if (layerData) {
176          LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerData);
177          if (layerItem) {
178             mLayers.push_back(layerItem);
179             mLayerMap[layerItem->id()] = layerItem;
180          }
181       }
182    }
183
184    //2. update parent layer
185    for(auto i : mLayers) {
186       int id = i->parentId();
187       if (id >=0) {
188          auto search = mLayerMap.find(id);
189          if (search != mLayerMap.end()) {
190            LOTLayerItem *parentLayer = search->second;
191            i->setParentLayer(parentLayer);
192          }
193       }
194    }
195    //3. update static property of each layer
196    for(auto i : mLayers) {
197       i->updateStaticProperty();
198    }
199
200    mViewSize = mCompData->size();
201 }
202
203 LOTCompItem::~LOTCompItem()
204 {
205     for(auto i : mLayers) {
206        delete i;
207     }
208 }
209
210 LOTLayerItem *
211 LOTCompItem::createLayerItem(LOTLayerData *layerData)
212 {
213     switch(layerData->mLayerType) {
214         case LayerType::Precomp: {
215             return new LOTCompLayerItem(layerData);
216             break;
217         }
218         case LayerType::Solid: {
219             return new LOTSolidLayerItem(layerData);
220             break;
221         }
222         case LayerType::Shape: {
223             return new LOTShapeLayerItem(layerData);
224             break;
225         }
226         case LayerType::Null: {
227             return new LOTNullLayerItem(layerData);
228             break;
229         }
230         default:
231             return nullptr;
232             break;
233     }
234 }
235
236 void LOTCompItem::resize(const VSize &size)
237 {
238    if (mViewSize == size) return;
239    mViewSize = size;
240    mUpdateViewBox = true;
241 }
242
243 VSize LOTCompItem::size() const
244 {
245    return mViewSize;
246 }
247
248 bool LOTCompItem::update(int frameNo)
249 {
250    VMatrix m;
251    float sx, sy;
252
253    // check if cached frame is same as requested frame.
254    if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false;
255
256    sx = mViewSize.width() / float(mCompData->size().width());
257    sy = mViewSize.height() / float(mCompData->size().height());
258    float scale = fmin(sx, sy);
259    m.scale(scale, scale);
260
261    // update the layer from back to front
262    for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
263       LOTLayerItem *layer = *i;
264       layer->update(frameNo, m, 1.0);
265    }
266    buildRenderList();
267    mCurFrameNo = frameNo;
268    mUpdateViewBox = false;
269    return true;
270 }
271
272 void LOTCompItem::buildRenderList()
273 {
274     mRenderList.clear();
275     std::vector<VDrawable *> list;
276     for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
277        LOTLayerItem *layer = *i;
278        layer->renderList(list);
279     }
280
281     for(auto i : list) {
282         i->sync();
283         mRenderList.push_back(&i->mCNode);
284     }
285 }
286
287 const std::vector<LOTNode *>& LOTCompItem::renderList() const
288 {
289     return mRenderList;
290 }
291
292 bool LOTCompItem::render(const LOTBuffer &buffer)
293 {
294     VBitmap bitmap((uchar *)buffer.buffer, buffer.width, buffer.height,
295                    buffer.bytesPerLine, VBitmap::Format::ARGB32_Premultiplied, nullptr, nullptr);
296
297     VPainter painter(&bitmap);
298     VRle mask;
299     for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
300        LOTLayerItem *layer = *i;
301        layer->render(&painter, mask);
302     }
303
304     return true;
305 }
306
307 void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
308                          float parentAlpha, const DirtyFlag &flag)
309 {
310     if (mData->mShape.isStatic()) {
311         if (mLocalPath.isEmpty()) {
312             mLocalPath = mData->mShape.value(frameNo).toPath();
313         }
314     } else {
315         mLocalPath = mData->mShape.value(frameNo).toPath();
316     }
317     float opacity = mData->opacity(frameNo);
318     opacity = opacity * parentAlpha;
319     mCombinedAlpha = opacity;
320
321     VPath path = mLocalPath;
322     path.transform(parentMatrix);
323
324     FTOutline *outline = VRaster::toFTOutline(path);
325     mRleTask = VRaster::instance().generateFillInfo(outline);
326 }
327
328 VRle LOTMaskItem::rle()
329 {
330     if (mRleTask.valid()) {
331         mRle = std::move(mRleTask.get());
332         if (!vCompare(mCombinedAlpha, 1.0f))
333             mRle = mRle * (mCombinedAlpha * 255);
334         if (mData->mInv)
335             mRle = ~mRle;
336     }
337     return mRle;
338 }
339
340 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
341 {
342     std::vector<VDrawable *> list;
343     renderList(list);
344     VRle mask = inheritMask;
345     if (hasMask()) {
346         if (mask.isEmpty())
347             mask = maskRle(painter->clipBoundingRect());
348         else
349             mask = mask & inheritMask;
350     }
351
352     // do preprocessing first to take advantage of thread pool.
353     for(auto i : list) {
354         i->preprocess();
355     }
356
357     for(auto i : list) {
358         painter->setBrush(i->mBrush);
359         if (!mask.isEmpty()) {
360             VRle rle = i->rle() & mask;
361             painter->drawRle(VPoint(), rle);
362         } else {
363             painter->drawRle(VPoint(), i->rle());
364         }
365     }
366 }
367
368 VRle LOTLayerItem::maskRle(const VRect &clipRect)
369 {
370
371     VRle rle;
372     for (auto &i : mMasks) {
373         switch (i->maskMode()) {
374             case LOTMaskData::Mode::Add: {
375                 rle = rle + i->rle();
376                 break;
377             }
378             case LOTMaskData::Mode::Substarct: {
379                 if (rle.isEmpty() && !clipRect.isEmpty())
380                     rle = VRle::toRle(clipRect);
381                 rle = rle - i->rle();
382                 break;
383             }
384             case LOTMaskData::Mode::Intersect: {
385                 rle = rle & i->rle();
386                 break;
387             }
388             default:
389                 break;
390         }
391     }
392     return rle;
393 }
394
395 LOTLayerItem::LOTLayerItem(LOTLayerData *layerData):mLayerData(layerData),
396                                                     mParentLayer(nullptr),
397                                                     mPrecompLayer(nullptr),
398                                                     mCombinedAlpha(0.0f),
399                                                     mFrameNo(-1),
400                                                     mDirtyFlag(DirtyFlagBit::All)
401 {
402     if (mLayerData->mHasMask) {
403         for (auto i : mLayerData->mMasks) {
404             mMasks.push_back(std::unique_ptr<LOTMaskItem>(new LOTMaskItem(i.get())));
405         }
406     }
407 }
408
409 void LOTLayerItem::updateStaticProperty()
410 {
411    if (mParentLayer)
412      mParentLayer->updateStaticProperty();
413
414    mStatic = mLayerData->isStatic();
415    mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
416    mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
417 }
418
419 void LOTLayerItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha)
420 {
421    mFrameNo = frameNo;
422    // 1. check if the layer is part of the current frame
423    if (!visible()) return;
424
425    // 2. calculate the parent matrix and alpha
426    VMatrix m = matrix(frameNo) * parentMatrix;
427    float alpha = parentAlpha * opacity(frameNo);
428
429    //6. update the mask
430    if (hasMask()) {
431        for (auto &i : mMasks)
432            i->update(frameNo, m, alpha, mDirtyFlag);
433    }
434
435    // 3. update the dirty flag based on the change
436    if (!mCombinedMatrix.fuzzyCompare(m)) {
437        mDirtyFlag |= DirtyFlagBit::Matrix;
438    }
439    if (!vCompare(mCombinedAlpha, alpha)) {
440        mDirtyFlag |= DirtyFlagBit::Alpha;
441    }
442    mCombinedMatrix = m;
443    mCombinedAlpha = alpha;
444
445    // 4. if no parent property change and layer is static then nothing to do.
446    if ((flag() & DirtyFlagBit::None) && isStatic())
447       return;
448
449    //5. update the content of the layer
450    updateContent();
451
452    //6. reset the dirty flag
453    mDirtyFlag = DirtyFlagBit::None;
454 }
455
456 float
457 LOTLayerItem::opacity(int frameNo) const
458 {
459    return mLayerData->mTransform->opacity(frameNo);
460 }
461
462 VMatrix
463 LOTLayerItem::matrix(int frameNo) const
464 {
465     if (mParentLayer)
466         return mLayerData->mTransform->matrix(frameNo) * mParentLayer->matrix(frameNo);
467     else
468         return mLayerData->mTransform->matrix(frameNo);
469 }
470
471 bool LOTLayerItem::visible() const
472 {
473    if (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame())
474       return true;
475    else
476       return false;
477 }
478
479
480
481 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel):LOTLayerItem(layerModel)
482 {
483    for(auto i : mLayerData->mChildren) {
484       LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
485       if (layerModel) {
486          LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
487          if (layerItem) {
488             mLayers.push_back(layerItem);
489             mLayerMap[layerItem->id()] = layerItem;
490          }
491       }
492    }
493
494    //2. update parent layer
495    for(auto i : mLayers) {
496       int id = i->parentId();
497       if (id >=0) {
498          auto search = mLayerMap.find(id);
499          if (search != mLayerMap.end()) {
500            LOTLayerItem *parentLayer = search->second;
501            i->setParentLayer(parentLayer);
502          }
503       }
504       i->setPrecompLayer(this);
505    }
506 }
507
508 void LOTCompLayerItem::updateStaticProperty()
509 {
510     LOTLayerItem::updateStaticProperty();
511
512     for(auto i : mLayers) {
513        i->updateStaticProperty();
514     }
515 }
516
517 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask)
518 {
519     VRle mask = inheritMask;
520
521     if (hasMask()) {
522         if (mask.isEmpty())
523             mask = maskRle(painter->clipBoundingRect());
524         else
525             mask = mask & inheritMask;
526     }
527
528     for(auto i : mLayers) {
529        i->render(painter, mask);
530     }
531 }
532
533 LOTCompLayerItem::~LOTCompLayerItem()
534 {
535     for(auto i : mLayers) {
536        delete i;
537     }
538 }
539
540 void LOTCompLayerItem::updateContent()
541 {
542     // update the layer from back to front
543     for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
544        LOTLayerItem *layer = *i;
545        layer->update(frameNo(), combinedMatrix(), combinedAlpha());
546     }
547 }
548
549 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
550 {
551     if (!visible()) return;
552
553     // update the layer from back to front
554     for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
555        LOTLayerItem *layer = *i;
556        layer->renderList(list);
557     }
558 }
559
560 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
561 {
562
563 }
564
565 void LOTSolidLayerItem::updateContent()
566 {
567    if (!mRenderNode) {
568       mRenderNode = std::unique_ptr<VDrawable>(new VDrawable());
569       mRenderNode->mType = VDrawable::Type::Fill;
570       mRenderNode->mFlag |= VDrawable::DirtyState::All;
571    }
572
573    if (flag() & DirtyFlagBit::Matrix) {
574        VPath path;
575        path.addRect(VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
576        path.transform(combinedMatrix());
577        mRenderNode->mFlag |= VDrawable::DirtyState::Path;
578        mRenderNode->mPath = path;
579    }
580    if (flag() & DirtyFlagBit::Alpha) {
581        LottieColor color = mLayerData->solidColor();
582        VBrush brush(color.toColor(combinedAlpha()));
583        mRenderNode->setBrush(brush);
584        mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
585    }
586 }
587
588 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
589 {
590     if (!visible()) return;
591
592     list.push_back(mRenderNode.get());
593 }
594
595 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
596 {
597
598 }
599 void LOTNullLayerItem::updateContent()
600 {
601
602 }
603
604
605 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
606 {
607     mRoot = new LOTContentGroupItem(nullptr);
608     mRoot->addChildren(layerData);
609     mRoot->processPaintOperation();
610 }
611
612 LOTShapeLayerItem::~LOTShapeLayerItem()
613 {
614     delete mRoot;
615 }
616
617 LOTContentItem * LOTShapeLayerItem::createContentItem(LOTData *contentData)
618 {
619     switch(contentData->type()) {
620         case LOTData::Type::ShapeGroup: {
621             return new LOTContentGroupItem(static_cast<LOTShapeGroupData *>(contentData));
622             break;
623         }
624         case LOTData::Type::Rect: {
625             return new LOTRectItem(static_cast<LOTRectData *>(contentData));
626             break;
627         }
628         case LOTData::Type::Ellipse: {
629             return new LOTEllipseItem(static_cast<LOTEllipseData *>(contentData));
630             break;
631         }
632         case LOTData::Type::Shape: {
633             return new LOTShapeItem(static_cast<LOTShapeData *>(contentData));
634             break;
635         }
636         case LOTData::Type::Polystar: {
637             return new LOTPolystarItem(static_cast<LOTPolystarData *>(contentData));
638             break;
639         }
640         case LOTData::Type::Fill: {
641             return new LOTFillItem(static_cast<LOTFillData *>(contentData));
642             break;
643         }
644         case LOTData::Type::GFill: {
645             return new LOTGFillItem(static_cast<LOTGFillData *>(contentData));
646             break;
647         }
648         case LOTData::Type::Stroke: {
649             return new LOTStrokeItem(static_cast<LOTStrokeData *>(contentData));
650             break;
651         }
652         case LOTData::Type::GStroke: {
653             return new LOTGStrokeItem(static_cast<LOTGStrokeData *>(contentData));
654             break;
655         }
656         case LOTData::Type::Repeater: {
657                 return new LOTRepeaterItem(static_cast<LOTRepeaterData *>(contentData));
658                 break;
659             }
660         default:
661             return nullptr;
662             break;
663     }
664 }
665
666 void LOTShapeLayerItem::updateContent()
667 {
668    mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
669 }
670
671 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
672 {
673     if (!visible()) return;
674     mRoot->renderList(list);
675 }
676
677 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data):mData(data)
678 {
679    addChildren(mData);
680 }
681
682 void LOTContentGroupItem::addChildren(LOTGroupData *data)
683 {
684    if (!data) return;
685
686    for(auto i : data->mChildren) {
687       LOTData *data = i.get();
688       LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
689       if (content)
690          mContents.push_back(content);
691    }
692 }
693
694 LOTContentGroupItem::~LOTContentGroupItem()
695 {
696     for(auto i : mContents) {
697         delete i;
698     }
699 }
700
701
702 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
703 {
704    VMatrix m = parentMatrix;
705    float alpha = parentAlpha;
706    DirtyFlag newFlag = flag;
707
708    if (mData) {
709       // update the matrix and the flag
710       if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->staticMatrix() ) {
711          newFlag |= DirtyFlagBit::Matrix;
712       }
713       m = mData->mTransform->matrix(frameNo) * parentMatrix;
714       alpha *= mData->mTransform->opacity(frameNo);
715
716       if (!vCompare(alpha, parentAlpha)) {
717          newFlag |= DirtyFlagBit::Alpha;
718       }
719    }
720
721    for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
722       (*i)->update(frameNo, m, alpha, newFlag);
723    }
724 }
725
726 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
727 {
728     for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
729        (*i)->renderList(list);
730     }
731 }
732
733 void LOTContentGroupItem::processPaintOperation()
734 {
735    std::vector<LOTPaintDataItem *> list;
736    paintOperationHelper(list);
737 }
738
739 void LOTContentGroupItem::paintOperationHelper(std::vector<LOTPaintDataItem *> &list)
740 {
741    int curOpCount = list.size();
742    for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
743       auto child = *i;
744       if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
745          // the node is a path data node add the paint operation list to it.
746          pathNode->addPaintOperation(list, curOpCount);
747       } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(child)) {
748          // add it to the paint operation list
749          list.push_back(paintNode);
750       } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
751          // update the groups node with current list
752          groupNode->paintOperationHelper(list);
753       }
754    }
755    list.erase(list.begin() + curOpCount, list.end());
756 }
757
758 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list, int externalCount)
759 {
760     for(auto paintItem : list) {
761       bool sameGroup = (externalCount-- > 0) ? false : true;
762       mNodeList.push_back(std::unique_ptr<VDrawable>(new VDrawable()));
763       mRenderList.push_back(LOTRenderNode(this, paintItem, mNodeList.back().get(), sameGroup));
764     }
765 }
766
767
768 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
769 {
770    mPathChanged = false;
771    mCombinedAlpha = parentAlpha;
772
773    // 1. update the local path if needed
774    if (!(mInit && mStaticPath)) {
775       mLocalPath = getPath(frameNo);
776       mInit = true;
777       mPathChanged = true;
778    }
779
780    // 2. apply path operation if needed
781    // TODO
782
783    // 3. compute the final path with parentMatrix
784    if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
785       mFinalPath = mLocalPath;
786       mFinalPath.transform(parentMatrix);
787       mPathChanged = true;
788    }
789
790    // 2. update the rendernode list
791    for (const auto &i : mRenderList) {
792       i.drawable->mFlag = VDrawable::DirtyState::None;
793       i.paintNodeRef->updateRenderNode(i.pathNodeRef, i.drawable, i.sameGroup);
794       if (mPathChanged) {
795           i.drawable->mPath = mFinalPath;
796           i.drawable->mFlag |= VDrawable::DirtyState::Path;
797       }
798    }
799 }
800
801 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
802 {
803    for (const auto &i : mRenderList) {
804        list.push_back(i.drawable);
805    }
806 }
807
808 VPath LOTPathDataItem::path() const
809 {
810    return mFinalPath;
811 }
812
813
814 LOTRectItem::LOTRectItem(LOTRectData *data):LOTPathDataItem(data->isStatic()),mData(data)
815 {
816 }
817
818 VPath LOTRectItem::getPath(int frameNo)
819 {
820    VPointF pos = mData->mPos.value(frameNo);
821    VPointF size = mData->mSize.value(frameNo);
822    float radius = mData->mRound.value(frameNo);
823    VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
824
825    VPath path;
826    path.addRoundRect(r, radius, radius, mData->direction());
827
828    return path;
829 }
830
831 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data):LOTPathDataItem(data->isStatic()),mData(data)
832 {
833
834 }
835
836 VPath LOTEllipseItem::getPath(int frameNo)
837 {
838    VPointF pos = mData->mPos.value(frameNo);
839    VPointF size = mData->mSize.value(frameNo);
840    VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
841
842    VPath path;
843    path.addOval(r, mData->direction());
844
845    return path;
846 }
847
848 LOTShapeItem::LOTShapeItem(LOTShapeData *data):LOTPathDataItem(data->isStatic()),mData(data)
849 {
850
851 }
852
853 VPath LOTShapeItem::getPath(int frameNo)
854 {
855     LottieShapeData shapeData = mData->mShape.value(frameNo);
856
857     if (shapeData.mPoints.empty())
858      return VPath();
859
860     VPath path;
861
862     int size = shapeData.mPoints.size();
863     const VPointF *points = shapeData.mPoints.data();
864     path.moveTo(points[0]);
865     for (int i = 1 ; i < size; i+=3) {
866        path.cubicTo(points[i], points[i+1], points[i+2]);
867     }
868     if (shapeData.mClosed)
869       path.close();
870
871    return path;
872 }
873
874
875 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data):LOTPathDataItem(data->isStatic()),mData(data)
876 {
877
878 }
879
880 VPath LOTPolystarItem::getPath(int frameNo)
881 {
882    VPointF pos = mData->mPos.value(frameNo);
883    float points = mData->mPointCount.value(frameNo);
884    float innerRadius = mData->mInnerRadius.value(frameNo);
885    float outerRadius = mData->mOuterRadius.value(frameNo);
886    float innerRoundness = mData->mInnerRoundness.value(frameNo);
887    float outerRoundness = mData->mOuterRoundness.value(frameNo);
888    float rotation = mData->mRotation.value(frameNo);
889
890    VPath path;
891    VMatrix m;
892
893    if (mData->mType == LOTPolystarData::PolyType::Star) {
894         path.addPolystarStar(0.0, 0.0, 0.0, points,
895                              innerRadius, outerRadius,
896                              innerRoundness, outerRoundness,
897                              mData->direction());
898    } else {
899         path.addPolystarPolygon(0.0, 0.0, 0.0, points,
900                                 outerRadius, outerRoundness,
901                                 mData->direction());
902    }
903
904    m.translate(pos.x(), pos.y()).rotate(rotation);
905    m.rotate(rotation);
906    path.transform(m);
907
908    return path;
909 }
910
911
912
913 /*
914  * PaintData Node handling
915  *
916  */
917
918 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
919 {
920    mContentChanged = false;
921    mParentAlpha = parentAlpha;
922    mParentMatrix = parentMatrix;
923    mFlag = flag;
924    mFrameNo = frameNo;
925    // 1. update the local content if needed
926   // if (!(mInit && mStaticContent)) {
927       mInit = true;
928       updateContent(frameNo);
929       mContentChanged = true;
930   // }
931 }
932
933
934 LOTFillItem::LOTFillItem(LOTFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
935 {
936 }
937
938 void LOTFillItem::updateContent(int frameNo)
939 {
940    LottieColor c = mData->mColor.value(frameNo);
941    float opacity = mData->opacity(frameNo);
942    mColor = c.toColor(opacity);
943    mFillRule = mData->fillRule();
944 }
945
946 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
947 {
948     VColor color = mColor;
949     if (sameParent)
950       color.setAlpha(color.a * pathNode->combinedAlpha());
951     else
952       color.setAlpha(color.a  * parentAlpha() * pathNode->combinedAlpha());
953     VBrush brush(color);
954     drawable->setBrush(brush);
955     drawable->setFillRule(mFillRule);
956 }
957
958
959 LOTGFillItem::LOTGFillItem(LOTGFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
960 {
961 }
962
963 void LOTGFillItem::updateContent(int frameNo)
964 {
965     mData->update(mGradient, frameNo);
966     mGradient->mMatrix = mParentMatrix;
967     mFillRule = mData->fillRule();
968 }
969
970 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
971 {
972     drawable->setBrush(VBrush(mGradient.get()));
973     drawable->setFillRule(mFillRule);
974 }
975
976 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
977 {
978     mDashArraySize = 0;
979 }
980
981 void LOTStrokeItem::updateContent(int frameNo)
982 {
983     LottieColor c = mData->mColor.value(frameNo);
984     float opacity = mData->opacity(frameNo);
985     mColor = c.toColor(opacity);
986     mCap = mData->capStyle();
987     mJoin = mData->joinStyle();
988     mMiterLimit = mData->meterLimit();
989     mWidth = mData->width(frameNo);
990     if (mData->hasDashInfo()) {
991         mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
992     }
993 }
994
995 static float getScale(const VMatrix &matrix)
996 {
997     constexpr float SQRT_2 = 1.41421;
998     VPointF p1(0,0);
999     VPointF p2(SQRT_2,SQRT_2);
1000     p1 = matrix.map(p1);
1001     p2 = matrix.map(p2);
1002     VPointF final = p2 - p1;
1003
1004     return std::sqrt( final.x() * final.x() + final.y() * final.y());
1005 }
1006
1007 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1008 {
1009     VColor color = mColor;
1010     if (sameParent)
1011       color.setAlpha(color.a * pathNode->combinedAlpha());
1012     else
1013       color.setAlpha(color.a  * parentAlpha() * pathNode->combinedAlpha());
1014
1015     VBrush brush(color);
1016     drawable->setBrush(brush);
1017
1018     drawable->setStrokeInfo(mCap, mJoin, mMiterLimit,  mWidth * getScale(mParentMatrix));
1019     if (mDashArraySize) {
1020         drawable->setDashInfo(mDashArray, mDashArraySize);
1021     }
1022 }
1023
1024 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1025 {
1026     mDashArraySize = 0;
1027 }
1028
1029 void LOTGStrokeItem::updateContent(int frameNo)
1030 {
1031     mData->update(mGradient, frameNo);
1032     mGradient->mMatrix = mParentMatrix;
1033     mCap = mData->capStyle();
1034     mJoin = mData->joinStyle();
1035     mMiterLimit = mData->meterLimit();
1036     mWidth = mData->width(frameNo);
1037     if (mData->hasDashInfo()) {
1038         mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1039     }
1040 }
1041
1042 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1043 {
1044     drawable->setBrush(VBrush(mGradient.get()));
1045     drawable->setStrokeInfo(mCap, mJoin, mMiterLimit,  mWidth * getScale(mParentMatrix));
1046     if (mDashArraySize) {
1047         drawable->setDashInfo(mDashArray, mDashArraySize);
1048     }
1049 }
1050
1051 LOTTrimItem::LOTTrimItem(LOTTrimData *data):mData(data)
1052 {
1053
1054 }
1055
1056 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data):mData(data)
1057 {
1058
1059 }
1060
1061 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1062 {
1063
1064 }
1065
1066 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list)
1067 {
1068
1069 }
1070