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