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