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