lottie: Add Mask information to the layer node.
[platform/core/uifw/lottie-player.git] / src / lottie / lottieitem.cpp
1 #include "lottieitem.h"
2 #include <cmath>
3 #include <algorithm>
4 #include "vbitmap.h"
5 #include "vdasher.h"
6 #include "vpainter.h"
7 #include "vraster.h"
8
9 /* Lottie Layer Rules
10  * 1. time stretch is pre calculated and applied to all the properties of the
11  * lottilayer model and all its children
12  * 2. The frame property could be reversed using,time-reverse layer property in
13  * AE. which means (start frame > endFrame) 3.
14  */
15
16 LOTCompItem::LOTCompItem(LOTModel *model)
17     : mRootModel(model), mUpdateViewBox(false), mCurFrameNo(-1)
18 {
19     mCompData = model->mRoot.get();
20     mRootLayer = createLayerItem(mCompData->mRootLayer.get());
21     mRootLayer->updateStaticProperty();
22     mViewSize = mCompData->size();
23 }
24
25 std::unique_ptr<LOTLayerItem>
26 LOTCompItem::createLayerItem(LOTLayerData *layerData)
27 {
28     switch (layerData->mLayerType) {
29     case LayerType::Precomp: {
30         return std::make_unique<LOTCompLayerItem>(layerData);
31         break;
32     }
33     case LayerType::Solid: {
34         return std::make_unique<LOTSolidLayerItem>(layerData);
35         break;
36     }
37     case LayerType::Shape: {
38         return std::make_unique<LOTShapeLayerItem>(layerData);
39         break;
40     }
41     case LayerType::Null: {
42         return std::make_unique<LOTNullLayerItem>(layerData);
43         break;
44     }
45     default:
46         return nullptr;
47         break;
48     }
49 }
50
51 void LOTCompItem::resize(const VSize &size)
52 {
53     if (mViewSize == size) return;
54     mViewSize = size;
55     mUpdateViewBox = true;
56 }
57
58 VSize LOTCompItem::size() const
59 {
60     return mViewSize;
61 }
62
63 bool LOTCompItem::update(int frameNo)
64 {
65     // check if cached frame is same as requested frame.
66     if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false;
67
68     /*
69      * if viewbox dosen't scale exactly to the viewport
70      * we scale the viewbox keeping AspectRatioPreserved and then align the
71      * viewbox to the viewport using AlignCenter rule.
72      */
73     VSize viewPort = mViewSize;
74     VSize viewBox = mCompData->size();
75
76     float sx = float(viewPort.width()) / viewBox.width();
77     float sy = float(viewPort.height()) / viewBox.height();
78     float scale = fmin(sx, sy);
79     float tx = (viewPort.width() - viewBox.width() * scale) * 0.5;
80     float ty = (viewPort.height() - viewBox.height() * scale) * 0.5;
81
82     VMatrix m;
83     m.translate(tx, ty).scale(scale, scale);
84     mRootLayer->update(frameNo, m, 1.0);
85
86     mCurFrameNo = frameNo;
87     mUpdateViewBox = false;
88     return true;
89 }
90
91 void LOTCompItem::buildRenderList()
92 {
93     mDrawableList.clear();
94     mRootLayer->renderList(mDrawableList);
95
96     mRenderList.clear();
97     for (auto &i : mDrawableList) {
98         LOTDrawable *lotDrawable = static_cast<LOTDrawable *>(i);
99         lotDrawable->sync();
100         mRenderList.push_back(lotDrawable->mCNode.get());
101     }
102 }
103
104 const std::vector<LOTNode *> &LOTCompItem::renderList() const
105 {
106     return mRenderList;
107 }
108
109 void LOTCompItem::buildRenderTree()
110 {
111     mRootLayer->buildLayerNode();
112 }
113
114 const LOTLayerNode * LOTCompItem::renderTree() const
115 {
116     return mRootLayer->layerNode();
117 }
118
119 bool LOTCompItem::render(const lottie::Surface &surface)
120 {
121     VBitmap bitmap((uchar *)surface.buffer(), surface.width(), surface.height(),
122                    surface.bytesPerLine(), VBitmap::Format::ARGB32_Premultiplied,
123                    nullptr, nullptr);
124
125     /* schedule all preprocess task for this frame at once.
126      */
127     mDrawableList.clear();
128     mRootLayer->renderList(mDrawableList);
129     VRect clip(0, 0, surface.width(), surface.height());
130     for (auto &e : mDrawableList) {
131         e->preprocess(clip);
132     }
133
134     VPainter painter(&bitmap);
135     mRootLayer->render(&painter, {}, {}, nullptr);
136
137     return true;
138 }
139
140 void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
141                          float parentAlpha, const DirtyFlag &/*flag*/)
142 {
143     if (mData->mShape.isStatic()) {
144         if (mLocalPath.empty()) {
145             mData->mShape.value(frameNo).toPath(mLocalPath);
146         }
147     } else {
148         mData->mShape.value(frameNo).toPath(mLocalPath);
149     }
150     float opacity = mData->opacity(frameNo);
151     opacity = opacity * parentAlpha;
152     mCombinedAlpha = opacity;
153
154     mFinalPath.reset();
155     mFinalPath.addPath(mLocalPath);
156     mFinalPath.transform(parentMatrix);
157
158     VPath tmp = mFinalPath;
159
160     mRleTask = VRaster::generateFillInfo(std::move(tmp), std::move(mRle));
161     mRle = VRle();
162 }
163
164 VRle LOTMaskItem::rle()
165 {
166     if (mRleTask.valid()) {
167         mRle = mRleTask.get();
168         if (!vCompare(mCombinedAlpha, 1.0f))
169             mRle *= (mCombinedAlpha * 255);
170         if (mData->mInv) mRle.invert();
171     }
172     return mRle;
173 }
174
175 void LOTLayerItem::buildLayerNode()
176 {
177     if (!mLayerCNode) {
178         mLayerCNode = std::make_unique<LOTLayerNode>();
179         mLayerCNode->mMaskList.ptr = nullptr;
180         mLayerCNode->mMaskList.size = 0;
181         mLayerCNode->mLayerList.ptr = nullptr;
182         mLayerCNode->mLayerList.size = 0;
183         mLayerCNode->mNodeList.ptr = nullptr;
184         mLayerCNode->mNodeList.size = 0;
185         mLayerCNode->mMatte = MatteNone;
186         mLayerCNode->mVisible = 0;
187     }
188     mLayerCNode->mVisible = visible();
189     // update matte
190     if (hasMatte()) {
191         switch (mLayerData->mMatteType) {
192         case MatteType::Alpha:
193             mLayerCNode->mMatte = MatteAlpha;
194             break;
195         case MatteType::AlphaInv:
196             mLayerCNode->mMatte = MatteAlphaInv;
197             break;
198         case MatteType::Luma:
199             mLayerCNode->mMatte = MatteLuma;
200             break;
201         case MatteType::LumaInv:
202             mLayerCNode->mMatte = MatteLumaInv;
203             break;
204         default:
205             mLayerCNode->mMatte = MatteNone;
206             break;
207         }
208     }
209     if (hasMask()) {
210         mMasksCNode.clear();
211         for (const auto &mask : mMasks) {
212             LOTMask cNode;
213             const std::vector<VPath::Element> &elm = mask->mFinalPath.elements();
214             const std::vector<VPointF> &       pts = mask->mFinalPath.points();
215             const float *ptPtr = reinterpret_cast<const float *>(pts.data());
216             const char * elmPtr = reinterpret_cast<const char *>(elm.data());
217             cNode.mPath.ptPtr = ptPtr;
218             cNode.mPath.ptCount = pts.size();
219             cNode.mPath.elmPtr = elmPtr;
220             cNode.mPath.elmCount = elm.size();
221             switch (mask->maskMode()) {
222             case LOTMaskData::Mode::Add:
223                 cNode.mMode = MaskModeAdd;
224                 break;
225             case LOTMaskData::Mode::Substarct:
226                 cNode.mMode = MaskModeSubstract;
227                 break;
228             case LOTMaskData::Mode::Intersect:
229                 cNode.mMode = MaskModeIntersect;
230                 break;
231             case LOTMaskData::Mode::Difference:
232                 cNode.mMode = MaskModeDifference;
233                 break;
234             default:
235                 cNode.mMode = MaskModeAdd;
236                 break;
237             }
238             mMasksCNode.push_back(std::move(cNode));
239         }
240         mLayerCNode->mMaskList.ptr = mMasksCNode.data();
241         mLayerCNode->mMaskList.size = mMasksCNode.size();
242     }
243 }
244
245 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, const VRle &inheritMatte, LOTLayerItem *matteSource)
246 {
247     VRle matteRle;
248     if (matteSource) {
249         mDrawableList.clear();
250         matteSource->renderList(mDrawableList);
251         for (auto &i : mDrawableList) {
252             matteRle = matteRle + i->rle();
253         }
254         if (!inheritMatte.empty())
255             matteRle = matteRle & inheritMatte;
256     } else {
257         matteRle = inheritMatte;
258     }
259     mDrawableList.clear();
260     renderList(mDrawableList);
261
262     VRle mask;
263     if (hasMask()) {
264         mask = maskRle(painter->clipBoundingRect());
265         if (!inheritMask.empty())
266             mask = mask & inheritMask;
267         // if resulting mask is empty then return.
268         if (mask.empty())
269             return;
270     } else {
271         mask = inheritMask;
272     }
273
274     for (auto &i : mDrawableList) {
275         painter->setBrush(i->mBrush);
276         VRle rle = i->rle();
277         if (!mask.empty()) rle = rle & mask;
278
279         if (rle.empty()) continue;
280
281         if (!matteRle.empty()) {
282             if (matteType() == MatteType::AlphaInv) {
283                 rle = rle - matteRle;
284             } else {
285                 rle = rle & matteRle;
286             }
287         }
288         painter->drawRle(VPoint(), rle);
289     }
290 }
291
292 VRle LOTLayerItem::maskRle(const VRect &clipRect)
293 {
294     VRle rle;
295     for (auto &i : mMasks) {
296         switch (i->maskMode()) {
297         case LOTMaskData::Mode::Add: {
298             rle = rle + i->rle();
299             break;
300         }
301         case LOTMaskData::Mode::Substarct: {
302             if (rle.empty() && !clipRect.empty())
303                 rle = VRle::toRle(clipRect);
304             rle = rle - i->rle();
305             break;
306         }
307         case LOTMaskData::Mode::Intersect: {
308             rle = rle & i->rle();
309             break;
310         }
311         case LOTMaskData::Mode::Difference: {
312             rle = rle ^ i->rle();
313             break;
314         }
315         default:
316             break;
317         }
318     }
319     return rle;
320 }
321
322 LOTLayerItem::LOTLayerItem(LOTLayerData *layerData): mLayerData(layerData)
323 {
324     if (mLayerData->mHasMask) {
325         for (auto &i : mLayerData->mMasks) {
326             mMasks.push_back(std::make_unique<LOTMaskItem>(i.get()));
327         }
328     }
329 }
330
331 void LOTLayerItem::updateStaticProperty()
332 {
333     if (mParentLayer) mParentLayer->updateStaticProperty();
334
335     mStatic = mLayerData->isStatic();
336     mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
337     mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
338 }
339
340 void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix,
341                           float parentAlpha)
342 {
343     mFrameNo = frameNumber;
344     // 1. check if the layer is part of the current frame
345     if (!visible()) return;
346
347     // 2. calculate the parent matrix and alpha
348     VMatrix m = matrix(frameNo());
349     m *= parentMatrix;
350     float alpha = parentAlpha * opacity(frameNo());
351
352     // 6. update the mask
353     if (hasMask()) {
354         for (auto &i : mMasks) i->update(frameNo(), m, alpha, mDirtyFlag);
355     }
356
357     // 3. update the dirty flag based on the change
358     if (!mCombinedMatrix.fuzzyCompare(m)) {
359         mDirtyFlag |= DirtyFlagBit::Matrix;
360     }
361     if (!vCompare(mCombinedAlpha, alpha)) {
362         mDirtyFlag |= DirtyFlagBit::Alpha;
363     }
364     mCombinedMatrix = m;
365     mCombinedAlpha = alpha;
366
367     // 4. if no parent property change and layer is static then nothing to do.
368     if ((flag() & DirtyFlagBit::None) && isStatic()) return;
369
370     // 5. update the content of the layer
371     updateContent();
372
373     // 6. reset the dirty flag
374     mDirtyFlag = DirtyFlagBit::None;
375 }
376
377 float LOTLayerItem::opacity(int frameNo) const
378 {
379     return mLayerData->mTransform->opacity(frameNo);
380 }
381
382 VMatrix LOTLayerItem::matrix(int frameNo) const
383 {
384     if (mParentLayer)
385         return mLayerData->mTransform->matrix(frameNo, mLayerData->autoOrient()) *
386                mParentLayer->matrix(frameNo);
387     else
388         return mLayerData->mTransform->matrix(frameNo, mLayerData->autoOrient());
389 }
390
391 bool LOTLayerItem::visible() const
392 {
393     if (frameNo() >= mLayerData->inFrame() &&
394         frameNo() < mLayerData->outFrame())
395         return true;
396     else
397         return false;
398 }
399
400 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel)
401     : LOTLayerItem(layerModel)
402 {
403     // 1. create layer item
404     for (auto &i : mLayerData->mChildren) {
405         LOTLayerData *layerModel = static_cast<LOTLayerData *>(i.get());
406         auto layerItem = LOTCompItem::createLayerItem(layerModel);
407         if (layerItem) mLayers.push_back(std::move(layerItem));
408     }
409
410     // 2. update parent layer
411     for (const auto &layer : mLayers) {
412         int id = layer->parentId();
413         if (id >= 0) {
414             auto search = std::find_if(mLayers.begin(), mLayers.end(),
415                             [id](const auto& val){ return val->id() == id;});
416             if (search != mLayers.end()) layer->setParentLayer((*search).get());
417         }
418         // update the precomp layer if its not the root layer.
419         if (!layerModel->root()) layer->setPrecompLayer(this);
420     }
421
422     // 3. keep the layer in back-to-front order.
423     // as lottie model keeps the data in front-toback-order.
424     std::reverse(mLayers.begin(), mLayers.end());
425 }
426
427 void LOTCompLayerItem::updateStaticProperty()
428 {
429     LOTLayerItem::updateStaticProperty();
430
431     for (const auto &layer : mLayers) {
432         layer->updateStaticProperty();
433     }
434 }
435
436 void LOTCompLayerItem::buildLayerNode()
437 {
438     LOTLayerItem::buildLayerNode();
439     if (mLayers.size() != mLayersCNode.size()) {
440         for (const auto &layer : mLayers) {
441             layer->buildLayerNode();
442             mLayersCNode.push_back(layer->layerNode());
443         }
444         layerNode()->mLayerList.ptr = mLayersCNode.data();
445         layerNode()->mLayerList.size = mLayersCNode.size();
446     } else {
447         for (const auto &layer : mLayers) {
448             layer->buildLayerNode();
449         }
450     }
451 }
452
453 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, const VRle &inheritMatte, LOTLayerItem *matteSource)
454 {
455     VRle matteRle;
456     if (matteSource) {
457         mDrawableList.clear();
458         matteSource->renderList(mDrawableList);
459         for (auto &i : mDrawableList) {
460             matteRle = matteRle + i->rle();
461         }
462
463         if (matteType() == MatteType::AlphaInv ) {
464             matteRle = VRle::toRle(painter->clipBoundingRect()) - matteRle;
465         }
466
467         if (!inheritMatte.empty())
468             matteRle = matteRle & inheritMatte;
469     } else {
470         matteRle = inheritMatte;
471     }
472
473     VRle mask;
474     if (hasMask()) {
475         mask = maskRle(painter->clipBoundingRect());
476         if (!inheritMask.empty())
477             mask = mask & inheritMask;
478         // if resulting mask is empty then return.
479         if (mask.empty())
480             return;
481     } else {
482         mask = inheritMask;
483     }
484
485     LOTLayerItem *matteLayer = nullptr;
486     for (const auto &layer : mLayers) {
487         if (!matteLayer && layer->hasMatte()) {
488             matteLayer = layer.get();
489             continue;
490         }
491
492         if (matteLayer) {
493             if (matteLayer->visible() && layer->visible())
494                 matteLayer->render(painter, mask, matteRle, layer.get());
495             matteLayer = nullptr;
496         } else {
497             if (layer->visible())
498                 layer->render(painter, mask, matteRle, nullptr);
499         }
500     }
501 }
502
503 void LOTCompLayerItem::updateContent()
504 {
505     for (const auto &layer : mLayers) {
506         layer->update( mLayerData->timeRemap(frameNo()) - mLayerData->startFrame(),
507                        combinedMatrix(), combinedAlpha());
508     }
509 }
510
511 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
512 {
513     if (!visible()) return;
514
515     for (const auto &layer : mLayers) {
516         layer->renderList(list);
517     }
518 }
519
520 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData)
521     : LOTLayerItem(layerData)
522 {
523 }
524
525 void LOTSolidLayerItem::updateContent()
526 {
527     if (!mRenderNode) {
528         mRenderNode = std::make_unique<LOTDrawable>();
529         mRenderNode->mType = VDrawable::Type::Fill;
530         mRenderNode->mFlag |= VDrawable::DirtyState::All;
531     }
532
533     if (flag() & DirtyFlagBit::Matrix) {
534         VPath path;
535         path.addRect(
536             VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
537         path.transform(combinedMatrix());
538         mRenderNode->mFlag |= VDrawable::DirtyState::Path;
539         mRenderNode->mPath = path;
540     }
541     if (flag() & DirtyFlagBit::Alpha) {
542         LottieColor color = mLayerData->solidColor();
543         VBrush      brush(color.toColor(combinedAlpha()));
544         mRenderNode->setBrush(brush);
545         mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
546     }
547 }
548
549 void LOTSolidLayerItem::buildLayerNode()
550 {
551     LOTLayerItem::buildLayerNode();
552
553     mDrawableList.clear();
554     renderList(mDrawableList);
555
556     mCNodeList.clear();
557     for (auto &i : mDrawableList) {
558         LOTDrawable *lotDrawable = static_cast<LOTDrawable *>(i);
559         lotDrawable->sync();
560         mCNodeList.push_back(lotDrawable->mCNode.get());
561     }
562     layerNode()->mNodeList.ptr = mCNodeList.data();
563     layerNode()->mNodeList.size = mCNodeList.size();
564 }
565
566 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
567 {
568     if (!visible()) return;
569
570     list.push_back(mRenderNode.get());
571 }
572
573 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData)
574     : LOTLayerItem(layerData)
575 {
576 }
577 void LOTNullLayerItem::updateContent() {}
578
579 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData)
580     : LOTLayerItem(layerData)
581 {
582     mRoot = std::make_unique<LOTContentGroupItem>(nullptr);
583     mRoot->addChildren(layerData);
584
585     std::vector<LOTPathDataItem *> list;
586     mRoot->processPaintItems(list);
587
588     if (layerData->hasPathOperator()) {
589         list.clear();
590         mRoot->processTrimItems(list);
591     }
592 }
593
594 std::unique_ptr<LOTContentItem>
595 LOTShapeLayerItem::createContentItem(LOTData *contentData)
596 {
597     switch (contentData->type()) {
598     case LOTData::Type::ShapeGroup: {
599         return std::make_unique<LOTContentGroupItem>(
600             static_cast<LOTGroupData *>(contentData));
601         break;
602     }
603     case LOTData::Type::Rect: {
604         return std::make_unique<LOTRectItem>(static_cast<LOTRectData *>(contentData));
605         break;
606     }
607     case LOTData::Type::Ellipse: {
608         return std::make_unique<LOTEllipseItem>(static_cast<LOTEllipseData *>(contentData));
609         break;
610     }
611     case LOTData::Type::Shape: {
612         return std::make_unique<LOTShapeItem>(static_cast<LOTShapeData *>(contentData));
613         break;
614     }
615     case LOTData::Type::Polystar: {
616         return std::make_unique<LOTPolystarItem>(static_cast<LOTPolystarData *>(contentData));
617         break;
618     }
619     case LOTData::Type::Fill: {
620         return std::make_unique<LOTFillItem>(static_cast<LOTFillData *>(contentData));
621         break;
622     }
623     case LOTData::Type::GFill: {
624         return std::make_unique<LOTGFillItem>(static_cast<LOTGFillData *>(contentData));
625         break;
626     }
627     case LOTData::Type::Stroke: {
628         return std::make_unique<LOTStrokeItem>(static_cast<LOTStrokeData *>(contentData));
629         break;
630     }
631     case LOTData::Type::GStroke: {
632         return std::make_unique<LOTGStrokeItem>(static_cast<LOTGStrokeData *>(contentData));
633         break;
634     }
635     case LOTData::Type::Repeater: {
636         return std::make_unique<LOTRepeaterItem>(static_cast<LOTRepeaterData *>(contentData));
637         break;
638     }
639     case LOTData::Type::Trim: {
640         return std::make_unique<LOTTrimItem>(static_cast<LOTTrimData *>(contentData));
641         break;
642     }
643     default:
644         return nullptr;
645         break;
646     }
647 }
648
649 void LOTShapeLayerItem::updateContent()
650 {
651     mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
652
653     if (mLayerData->hasPathOperator()) {
654         mRoot->applyTrim();
655     }
656 }
657
658 void LOTShapeLayerItem::buildLayerNode()
659 {
660     LOTLayerItem::buildLayerNode();
661
662     mDrawableList.clear();
663     renderList(mDrawableList);
664
665     mCNodeList.clear();
666     for (auto &i : mDrawableList) {
667         LOTDrawable *lotDrawable = static_cast<LOTDrawable *>(i);
668         lotDrawable->sync();
669         mCNodeList.push_back(lotDrawable->mCNode.get());
670     }
671     layerNode()->mNodeList.ptr = mCNodeList.data();
672     layerNode()->mNodeList.size = mCNodeList.size();
673 }
674
675 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
676 {
677     if (!visible()) return;
678     mRoot->renderList(list);
679 }
680
681 LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) : mData(data)
682 {
683     addChildren(mData);
684 }
685
686 void LOTContentGroupItem::addChildren(LOTGroupData *data)
687 {
688     if (!data) return;
689
690     for (auto &i : data->mChildren) {
691         auto content = LOTShapeLayerItem::createContentItem(i.get());
692         if (content) {
693             content->setParent(this);
694             mContents.push_back(std::move(content));
695         }
696     }
697
698     // keep the content in back-to-front order.
699     std::reverse(mContents.begin(), mContents.end());
700 }
701
702 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix,
703                                  float parentAlpha, const DirtyFlag &flag)
704 {
705     VMatrix   m = parentMatrix;
706     float     alpha = parentAlpha;
707     DirtyFlag newFlag = flag;
708
709     if (mData && mData->mTransform) {
710         // update the matrix and the flag
711         if ((flag & DirtyFlagBit::Matrix) ||
712             !mData->mTransform->staticMatrix()) {
713             newFlag |= DirtyFlagBit::Matrix;
714         }
715         m = mData->mTransform->matrix(frameNo);
716         m *= parentMatrix;
717         alpha *= mData->mTransform->opacity(frameNo);
718
719         if (!vCompare(alpha, parentAlpha)) {
720             newFlag |= DirtyFlagBit::Alpha;
721         }
722     }
723
724     mMatrix = m;
725
726     for (const auto &content : mContents) {
727         content->update(frameNo, m, alpha, newFlag);
728     }
729 }
730
731 void LOTContentGroupItem::applyTrim()
732 {
733     for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
734         auto content = (*i).get();
735         if (auto trim = dynamic_cast<LOTTrimItem *>(content)) {
736             trim->update();
737         } else if (auto group = dynamic_cast<LOTContentGroupItem *>(content)) {
738             group->applyTrim();
739         }
740     }
741 }
742
743 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
744 {
745     for (const auto &content : mContents) {
746         content->renderList(list);
747     }
748 }
749
750 void LOTContentGroupItem::processPaintItems(
751     std::vector<LOTPathDataItem *> &list)
752 {
753     int curOpCount = list.size();
754     for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
755         auto content = (*i).get();
756         if (auto pathNode = dynamic_cast<LOTPathDataItem *>(content)) {
757             // add it to the list
758             list.push_back(pathNode);
759         } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(content)) {
760             // the node is a paint data node update the path list of the paint item.
761             paintNode->addPathItems(list, curOpCount);
762         } else if (auto groupNode =
763                        dynamic_cast<LOTContentGroupItem *>(content)) {
764             // update the groups node with current list
765             groupNode->processPaintItems(list);
766         }
767     }
768 }
769
770 void LOTContentGroupItem::processTrimItems(
771     std::vector<LOTPathDataItem *> &list)
772 {
773     int curOpCount = list.size();
774     for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
775         auto content = (*i).get();
776         if (auto pathNode = dynamic_cast<LOTPathDataItem *>(content)) {
777             // add it to the list
778             list.push_back(pathNode);
779         } else if (auto trimNode = dynamic_cast<LOTTrimItem *>(content)) {
780             // the node is a paint data node update the path list of the paint item.
781             trimNode->addPathItems(list, curOpCount);
782         } else if (auto groupNode =
783                        dynamic_cast<LOTContentGroupItem *>(content)) {
784             // update the groups node with current list
785             groupNode->processTrimItems(list);
786         }
787     }
788 }
789
790 void LOTPathDataItem::update(int frameNo, const VMatrix &,
791                              float, const DirtyFlag &flag)
792 {
793     mPathChanged = false;
794
795     // 1. update the local path if needed
796     if (hasChanged(frameNo)) {
797         updatePath(mLocalPath, frameNo);
798         mPathChanged = true;
799         mNeedUpdate = true;
800     }
801
802     mTemp = mLocalPath;
803
804     // 3. compute the final path with parentMatrix
805     if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
806         mPathChanged = true;
807     }
808 }
809
810 const VPath & LOTPathDataItem::finalPath()
811 {
812     if (mPathChanged || mNeedUpdate) {
813         mFinalPath.clone(mTemp);
814         mFinalPath.transform(static_cast<LOTContentGroupItem *>(parent())->matrix());
815         mNeedUpdate = false;
816     }
817     return mFinalPath;
818 }
819 LOTRectItem::LOTRectItem(LOTRectData *data)
820     : LOTPathDataItem(data->isStatic()), mData(data)
821 {
822 }
823
824 void LOTRectItem::updatePath(VPath& path, int frameNo)
825 {
826     VPointF pos = mData->mPos.value(frameNo);
827     VPointF size = mData->mSize.value(frameNo);
828     float   roundness = mData->mRound.value(frameNo);
829     VRectF  r(pos.x() - size.x() / 2, pos.y() - size.y() / 2, size.x(),
830              size.y());
831
832     path.reset();
833     path.addRoundRect(r, roundness, mData->direction());
834 }
835
836 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data)
837     : LOTPathDataItem(data->isStatic()), mData(data)
838 {
839 }
840
841 void LOTEllipseItem::updatePath(VPath& path, int frameNo)
842 {
843     VPointF pos = mData->mPos.value(frameNo);
844     VPointF size = mData->mSize.value(frameNo);
845     VRectF  r(pos.x() - size.x() / 2, pos.y() - size.y() / 2, size.x(),
846              size.y());
847
848     path.reset();
849     path.addOval(r, mData->direction());
850 }
851
852 LOTShapeItem::LOTShapeItem(LOTShapeData *data)
853     : LOTPathDataItem(data->isStatic()), mData(data)
854 {
855 }
856
857 void LOTShapeItem::updatePath(VPath& path, int frameNo)
858 {
859     mData->mShape.value(frameNo).toPath(path);
860 }
861
862 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data)
863     : LOTPathDataItem(data->isStatic()), mData(data)
864 {
865 }
866
867 void LOTPolystarItem::updatePath(VPath& path, int frameNo)
868 {
869     VPointF pos = mData->mPos.value(frameNo);
870     float   points = mData->mPointCount.value(frameNo);
871     float   innerRadius = mData->mInnerRadius.value(frameNo);
872     float   outerRadius = mData->mOuterRadius.value(frameNo);
873     float   innerRoundness = mData->mInnerRoundness.value(frameNo);
874     float   outerRoundness = mData->mOuterRoundness.value(frameNo);
875     float   rotation = mData->mRotation.value(frameNo);
876
877     path.reset();
878     VMatrix m;
879
880     if (mData->mType == LOTPolystarData::PolyType::Star) {
881         path.addPolystar(points, innerRadius, outerRadius, innerRoundness,
882                          outerRoundness, 0.0, 0.0, 0.0, mData->direction());
883     } else {
884         path.addPolygon(points, outerRadius, outerRoundness, 0.0, 0.0, 0.0,
885                         mData->direction());
886     }
887
888     m.translate(pos.x(), pos.y()).rotate(rotation);
889     m.rotate(rotation);
890     path.transform(m);
891 }
892
893 /*
894  * PaintData Node handling
895  *
896  */
897 LOTPaintDataItem::LOTPaintDataItem(bool staticContent):mDrawable(std::make_unique<LOTDrawable>()),
898                                                        mStaticContent(staticContent){}
899
900 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix,
901                               float parentAlpha, const DirtyFlag &flag)
902 {
903     mRenderNodeUpdate = true;
904     mParentAlpha = parentAlpha;
905     mFlag = flag;
906     mFrameNo = frameNo;
907
908     updateContent(frameNo);
909 }
910
911 void LOTPaintDataItem::updateRenderNode()
912 {
913     bool dirty = false;
914     for (auto &i : mPathItems) {
915         if (i->dirty()) {
916             dirty = true;
917             break;
918         }
919     }
920
921     if (dirty) {
922         mPath.reset();
923
924         for (auto &i : mPathItems) {
925             mPath.addPath(i->finalPath());
926         }
927         mDrawable->setPath(mPath);
928     } else {
929         if (mDrawable->mFlag & VDrawable::DirtyState::Path)
930             mDrawable->mPath = mPath;
931     }
932 }
933
934 void LOTPaintDataItem::renderList(std::vector<VDrawable *> &list)
935 {
936     if (mRenderNodeUpdate) {
937         updateRenderNode();
938         LOTPaintDataItem::updateRenderNode();
939         mRenderNodeUpdate = false;
940     }
941     list.push_back(mDrawable.get());
942 }
943
944
945 void LOTPaintDataItem::addPathItems(std::vector<LOTPathDataItem *> &list, int startOffset)
946 {
947     std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems));
948 }
949
950
951 LOTFillItem::LOTFillItem(LOTFillData *data)
952     : LOTPaintDataItem(data->isStatic()), mData(data)
953 {
954 }
955
956 void LOTFillItem::updateContent(int frameNo)
957 {
958     LottieColor c = mData->mColor.value(frameNo);
959     float       opacity = mData->opacity(frameNo);
960     mColor = c.toColor(opacity);
961     mFillRule = mData->fillRule();
962 }
963
964 void LOTFillItem::updateRenderNode()
965 {
966     VColor color = mColor;
967
968     color.setAlpha(color.a * parentAlpha());
969     VBrush brush(color);
970     mDrawable->setBrush(brush);
971     mDrawable->setFillRule(mFillRule);
972 }
973
974 LOTGFillItem::LOTGFillItem(LOTGFillData *data)
975     : LOTPaintDataItem(data->isStatic()), mData(data)
976 {
977 }
978
979 void LOTGFillItem::updateContent(int frameNo)
980 {
981     mData->update(mGradient, frameNo);
982     mGradient->mMatrix = static_cast<LOTContentGroupItem *>(parent())->matrix();
983     mFillRule = mData->fillRule();
984 }
985
986 void LOTGFillItem::updateRenderNode()
987 {
988     mGradient->setAlpha(parentAlpha());
989     mDrawable->setBrush(VBrush(mGradient.get()));
990     mDrawable->setFillRule(mFillRule);
991 }
992
993 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data)
994     : LOTPaintDataItem(data->isStatic()), mData(data)
995 {
996     mDashArraySize = 0;
997 }
998
999 void LOTStrokeItem::updateContent(int frameNo)
1000 {
1001     LottieColor c = mData->mColor.value(frameNo);
1002     float       opacity = mData->opacity(frameNo);
1003     mColor = c.toColor(opacity);
1004     mCap = mData->capStyle();
1005     mJoin = mData->joinStyle();
1006     mMiterLimit = mData->meterLimit();
1007     mWidth = mData->width(frameNo);
1008     if (mData->hasDashInfo()) {
1009         mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1010     }
1011 }
1012
1013 static float getScale(const VMatrix &matrix)
1014 {
1015     constexpr float SQRT_2 = 1.41421;
1016     VPointF         p1(0, 0);
1017     VPointF         p2(SQRT_2, SQRT_2);
1018     p1 = matrix.map(p1);
1019     p2 = matrix.map(p2);
1020     VPointF final = p2 - p1;
1021
1022     return std::sqrt(final.x() * final.x() + final.y() * final.y()) / 2.0;
1023 }
1024
1025 void LOTStrokeItem::updateRenderNode()
1026 {
1027     VColor color = mColor;
1028
1029     color.setAlpha(color.a * parentAlpha());
1030     VBrush brush(color);
1031     mDrawable->setBrush(brush);
1032     float scale = getScale(static_cast<LOTContentGroupItem *>(parent())->matrix());
1033     mDrawable->setStrokeInfo(mCap, mJoin, mMiterLimit,
1034                             mWidth * scale);
1035     if (mDashArraySize) {
1036         for (int i = 0 ; i < mDashArraySize ; i++)
1037             mDashArray[i] *= scale;
1038
1039         /* AE draw the dash even if dash value is 0 */
1040         if (vCompare(mDashArray[0], 0.0f)) mDashArray[0]= 0.1;
1041
1042         mDrawable->setDashInfo(mDashArray, mDashArraySize);
1043     }
1044 }
1045
1046 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data)
1047     : LOTPaintDataItem(data->isStatic()), mData(data)
1048 {
1049     mDashArraySize = 0;
1050 }
1051
1052 void LOTGStrokeItem::updateContent(int frameNo)
1053 {
1054     mData->update(mGradient, frameNo);
1055     mGradient->mMatrix = static_cast<LOTContentGroupItem *>(parent())->matrix();
1056     mCap = mData->capStyle();
1057     mJoin = mData->joinStyle();
1058     mMiterLimit = mData->meterLimit();
1059     mWidth = mData->width(frameNo);
1060     if (mData->hasDashInfo()) {
1061         mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1062     }
1063 }
1064
1065 void LOTGStrokeItem::updateRenderNode()
1066 {
1067     float scale = getScale(mGradient->mMatrix);
1068     mGradient->setAlpha(parentAlpha());
1069     mDrawable->setBrush(VBrush(mGradient.get()));
1070     mDrawable->setStrokeInfo(mCap, mJoin, mMiterLimit,
1071                             mWidth * scale);
1072     if (mDashArraySize) {
1073         for (int i = 0 ; i < mDashArraySize ; i++)
1074             mDashArray[i] *= scale;
1075         mDrawable->setDashInfo(mDashArray, mDashArraySize);
1076     }
1077 }
1078
1079 LOTTrimItem::LOTTrimItem(LOTTrimData *data) : mData(data) {}
1080
1081 void LOTTrimItem::update(int frameNo, const VMatrix &/*parentMatrix*/,
1082                          float /*parentAlpha*/, const DirtyFlag &/*flag*/)
1083 {
1084     mDirty = false;
1085
1086     if (mCache.mFrameNo == frameNo) return;
1087
1088     LOTTrimData::Segment segment = mData->segment(frameNo);
1089
1090     if (!(vCompare(mCache.mSegment.start, segment.start) &&
1091           vCompare(mCache.mSegment.end, segment.end))) {
1092         mDirty = true;
1093         mCache.mSegment = segment;
1094     }
1095     mCache.mFrameNo = frameNo;
1096 }
1097
1098 void LOTTrimItem::update()
1099 {
1100     // when both path and trim are not dirty
1101     if (!(mDirty || pathDirty())) return;
1102
1103     if (vCompare(mCache.mSegment.start, mCache.mSegment.end)) {
1104         for (auto &i : mPathItems) {
1105             i->updatePath(VPath());
1106         }
1107         return;
1108     }
1109
1110     if (vCompare(std::fabs(mCache.mSegment.start - mCache.mSegment.end) , 1)) {
1111         for (auto &i : mPathItems) {
1112             i->updatePath(i->localPath());
1113         }
1114         return;
1115     }
1116
1117     if (mData->type() == LOTTrimData::TrimType::Simultaneously) {
1118         for (auto &i : mPathItems) {
1119             VPathMesure pm;
1120             pm.setStart(mCache.mSegment.start);
1121             pm.setEnd(mCache.mSegment.end);
1122             i->updatePath(pm.trim(i->localPath()));
1123         }
1124     } else { // LOTTrimData::TrimType::Individually
1125         float totalLength = 0.0;
1126         for (auto &i : mPathItems) {
1127             totalLength += i->localPath().length();
1128         }
1129         float start = totalLength * mCache.mSegment.start;
1130         float end  = totalLength * mCache.mSegment.end;
1131
1132         if (start < end ) {
1133             float curLen = 0.0;
1134             for (auto &i : mPathItems) {
1135                 if (curLen > end) {
1136                     // update with empty path.
1137                     i->updatePath(VPath());
1138                     continue;
1139                 }
1140                 float len = i->localPath().length();
1141
1142                 if (curLen < start  && curLen + len < start) {
1143                     curLen += len;
1144                     // update with empty path.
1145                     i->updatePath(VPath());
1146                     continue;
1147                 } else if (start <= curLen && end >= curLen + len) {
1148                     // inside segment
1149                     curLen += len;
1150                     continue;
1151                 } else {
1152                     float local_start = start > curLen ? start - curLen : 0;
1153                     local_start /= len;
1154                     float local_end = curLen + len < end ? len : end - curLen;
1155                     local_end /= len;
1156                     VPathMesure pm;
1157                     pm.setStart(local_start);
1158                     pm.setEnd(local_end);
1159                     VPath p = pm.trim(i->localPath());
1160                     i->updatePath(p);
1161                     curLen += len;
1162                 }
1163             }
1164         }
1165     }
1166
1167 }
1168
1169
1170 void LOTTrimItem::addPathItems(std::vector<LOTPathDataItem *> &list, int startOffset)
1171 {
1172     std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems));
1173 }
1174
1175
1176 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data)
1177 {
1178     assert(mData->mChildren.size() == 1);
1179     LOTGroupData *root = reinterpret_cast<LOTGroupData *>(mData->mChildren[0].get());
1180     assert(root);
1181
1182     for (int i= 0; i < mData->copies(0); i++) {
1183         auto content = std::make_unique<LOTContentGroupItem>(static_cast<LOTGroupData *>(root));
1184         content->setParent(this);
1185         mContents.push_back(std::move(content));
1186     }
1187 }
1188
1189 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1190 {
1191
1192     DirtyFlag newFlag = flag;
1193
1194     if (mData->hasMtrixChange(frameNo)) {
1195         newFlag |= DirtyFlagBit::Matrix;
1196     }
1197
1198     float multiplier = mData->offset(frameNo);
1199     float startOpacity = mData->mTransform->startOpacity(frameNo);
1200     float endOpacity = mData->mTransform->endOpacity(frameNo);
1201     float index = 0;
1202     float copies = mData->copies(frameNo);
1203     if (!vCompare(copies, 1)) copies -=1;
1204
1205     newFlag |= DirtyFlagBit::Alpha;
1206     for (const auto &content : mContents) {
1207         float newAlpha = parentAlpha * lerp(startOpacity, endOpacity, index / copies);
1208         VMatrix result = mData->mTransform->matrixForRepeater(frameNo, multiplier) * parentMatrix;
1209         content->update(frameNo, result, newAlpha, newFlag);
1210         multiplier += 1;
1211         index +=1;
1212     }
1213 }
1214
1215 static void updateGStops(LOTNode *n, const VGradient *grad)
1216 {
1217     if (grad->mStops.size() != n->mGradient.stopCount) {
1218         if (n->mGradient.stopCount)
1219             free(n->mGradient.stopPtr);
1220         n->mGradient.stopCount = grad->mStops.size();
1221         n->mGradient.stopPtr = (LOTGradientStop *) malloc(n->mGradient.stopCount * sizeof(LOTGradientStop));
1222     }
1223
1224     LOTGradientStop *ptr = n->mGradient.stopPtr;
1225     for (const auto &i : grad->mStops) {
1226         ptr->pos = i.first;
1227         ptr->a = i.second.alpha() * grad->alpha();
1228         ptr->r = i.second.red();
1229         ptr->g = i.second.green();
1230         ptr->b = i.second.blue();
1231         ptr++;
1232     }
1233
1234 }
1235
1236 void LOTDrawable::sync()
1237 {
1238     if (!mCNode) {
1239         mCNode = std::make_unique<LOTNode>();
1240         mCNode->mGradient.stopPtr = nullptr;
1241         mCNode->mGradient.stopCount = 0;
1242     }
1243
1244     mCNode->mFlag = ChangeFlagNone;
1245     if (mFlag & DirtyState::None) return;
1246
1247     if (mFlag & DirtyState::Path) {
1248         if (mStroke.mDash.size()) {
1249             VDasher dasher(mStroke.mDash.data(), mStroke.mDash.size());
1250             mPath = dasher.dashed(mPath);
1251         }
1252         const std::vector<VPath::Element> &elm = mPath.elements();
1253         const std::vector<VPointF> &       pts = mPath.points();
1254         const float *ptPtr = reinterpret_cast<const float *>(pts.data());
1255         const char * elmPtr = reinterpret_cast<const char *>(elm.data());
1256         mCNode->mPath.elmPtr = elmPtr;
1257         mCNode->mPath.elmCount = elm.size();
1258         mCNode->mPath.ptPtr = ptPtr;
1259         mCNode->mPath.ptCount = 2 * pts.size();
1260         mCNode->mFlag |= ChangeFlagPath;
1261     }
1262
1263     if (mStroke.enable) {
1264         mCNode->mStroke.width = mStroke.width;
1265         mCNode->mStroke.meterLimit = mStroke.meterLimit;
1266         mCNode->mStroke.enable = 1;
1267
1268         switch (mStroke.cap) {
1269         case CapStyle::Flat:
1270             mCNode->mStroke.cap = LOTCapStyle::CapFlat;
1271             break;
1272         case CapStyle::Square:
1273             mCNode->mStroke.cap = LOTCapStyle::CapSquare;
1274             break;
1275         case CapStyle::Round:
1276             mCNode->mStroke.cap = LOTCapStyle::CapRound;
1277             break;
1278         default:
1279             mCNode->mStroke.cap = LOTCapStyle::CapFlat;
1280             break;
1281         }
1282
1283         switch (mStroke.join) {
1284         case JoinStyle::Miter:
1285             mCNode->mStroke.join = LOTJoinStyle::JoinMiter;
1286             break;
1287         case JoinStyle::Bevel:
1288             mCNode->mStroke.join = LOTJoinStyle::JoinBevel;
1289             break;
1290         case JoinStyle::Round:
1291             mCNode->mStroke.join = LOTJoinStyle::JoinRound;
1292             break;
1293         default:
1294             mCNode->mStroke.join = LOTJoinStyle::JoinMiter;
1295             break;
1296         }
1297     } else {
1298         mCNode->mStroke.enable = 0;
1299     }
1300
1301     switch (mFillRule) {
1302     case FillRule::EvenOdd:
1303         mCNode->mFillRule = LOTFillRule::FillEvenOdd;
1304         break;
1305     default:
1306         mCNode->mFillRule = LOTFillRule::FillWinding;
1307         break;
1308     }
1309
1310     switch (mBrush.type()) {
1311     case VBrush::Type::Solid:
1312         mCNode->mBrushType = LOTBrushType::BrushSolid;
1313         mCNode->mColor.r = mBrush.mColor.r;
1314         mCNode->mColor.g = mBrush.mColor.g;
1315         mCNode->mColor.b = mBrush.mColor.b;
1316         mCNode->mColor.a = mBrush.mColor.a;
1317         break;
1318     case VBrush::Type::LinearGradient: {
1319         mCNode->mBrushType = LOTBrushType::BrushGradient;
1320         mCNode->mGradient.type = LOTGradientType::GradientLinear;
1321         VPointF s = mBrush.mGradient->mMatrix.map({mBrush.mGradient->linear.x1,
1322                                                    mBrush.mGradient->linear.y1});
1323         VPointF e = mBrush.mGradient->mMatrix.map({mBrush.mGradient->linear.x2,
1324                                                    mBrush.mGradient->linear.y2});
1325         mCNode->mGradient.start.x = s.x();
1326         mCNode->mGradient.start.y = s.y();
1327         mCNode->mGradient.end.x = e.x();
1328         mCNode->mGradient.end.y = e.y();
1329         updateGStops(mCNode.get(), mBrush.mGradient);
1330         break;
1331     }
1332     case VBrush::Type::RadialGradient: {
1333         mCNode->mBrushType = LOTBrushType::BrushGradient;
1334         mCNode->mGradient.type = LOTGradientType::GradientRadial;
1335         VPointF c = mBrush.mGradient->mMatrix.map({mBrush.mGradient->radial.cx,
1336                                                    mBrush.mGradient->radial.cy});
1337         VPointF f = mBrush.mGradient->mMatrix.map({mBrush.mGradient->radial.fx,
1338                                                    mBrush.mGradient->radial.fy});
1339         mCNode->mGradient.center.x = c.x();
1340         mCNode->mGradient.center.y = c.y();
1341         mCNode->mGradient.focal.x = f.x();
1342         mCNode->mGradient.focal.y = f.y();
1343
1344         float scale = getScale(mBrush.mGradient->mMatrix);
1345         mCNode->mGradient.cradius = mBrush.mGradient->radial.cradius * scale;
1346         mCNode->mGradient.fradius = mBrush.mGradient->radial.fradius * scale;
1347         updateGStops(mCNode.get(), mBrush.mGradient);
1348         break;
1349     }
1350     default:
1351         break;
1352     }
1353 }