1 #include "lottieitem.h"
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.
15 LOTCompItem::LOTCompItem(LOTModel *model)
16 : mRootModel(model), mUpdateViewBox(false), mCurFrameNo(-1)
18 mCompData = model->mRoot.get();
19 mRootLayer = std::unique_ptr<LOTLayerItem>(createLayerItem(mCompData->mRootLayer.get()));
20 mRootLayer->updateStaticProperty();
21 mViewSize = mCompData->size();
24 LOTLayerItem *LOTCompItem::createLayerItem(LOTLayerData *layerData)
26 switch (layerData->mLayerType) {
27 case LayerType::Precomp: {
28 return new LOTCompLayerItem(layerData);
31 case LayerType::Solid: {
32 return new LOTSolidLayerItem(layerData);
35 case LayerType::Shape: {
36 return new LOTShapeLayerItem(layerData);
39 case LayerType::Null: {
40 return new LOTNullLayerItem(layerData);
49 void LOTCompItem::resize(const VSize &size)
51 if (mViewSize == size) return;
53 mUpdateViewBox = true;
56 VSize LOTCompItem::size() const
61 bool LOTCompItem::update(int frameNo)
63 // check if cached frame is same as requested frame.
64 if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false;
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.
71 VSize viewPort = mViewSize;
72 VSize viewBox = mCompData->size();
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;
81 m.scale(scale, scale).translate(tx, ty);
82 mRootLayer->update(frameNo, m, 1.0);
85 mCurFrameNo = frameNo;
86 mUpdateViewBox = false;
90 void LOTCompItem::buildRenderList()
92 mDrawableList.clear();
93 mRootLayer->renderList(mDrawableList);
96 for (auto &i : mDrawableList) {
97 LOTDrawable *lotDrawable = static_cast<LOTDrawable *>(i);
99 mRenderList.push_back(&lotDrawable->mCNode);
103 const std::vector<LOTNode *> &LOTCompItem::renderList() const
108 bool LOTCompItem::render(const LOTBuffer &buffer)
110 VBitmap bitmap((uchar *)buffer.buffer, buffer.width, buffer.height,
111 buffer.bytesPerLine, VBitmap::Format::ARGB32_Premultiplied,
114 /* schedule all preprocess task for this frame at once.
116 for (auto &e : mDrawableList) {
120 VPainter painter(&bitmap);
122 mRootLayer->render(&painter, mask, nullptr);
127 void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
128 float parentAlpha, const DirtyFlag &flag)
130 if (mData->mShape.isStatic()) {
131 if (mLocalPath.isEmpty()) {
132 mData->mShape.value(frameNo).toPath(mLocalPath);
135 mData->mShape.value(frameNo).toPath(mLocalPath);
137 float opacity = mData->opacity(frameNo);
138 opacity = opacity * parentAlpha;
139 mCombinedAlpha = opacity;
141 VPath path = mLocalPath;
142 path.transform(parentMatrix);
144 mRleTask = VRaster::instance().generateFillInfo(std::move(path), std::move(mRle));
148 VRle LOTMaskItem::rle()
150 if (mRleTask.valid()) {
151 mRle = mRleTask.get();
152 if (!vCompare(mCombinedAlpha, 1.0f))
153 mRle *= (mCombinedAlpha * 255);
154 if (mData->mInv) mRle.invert();
159 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, LOTLayerItem *matteSource)
163 std::vector<VDrawable *> matteList;
164 matteSource->renderList(matteList);
165 for (auto &i : matteList) {
166 matteRle = matteRle + i->rle();
169 std::vector<VDrawable *> list;
171 VRle mask = inheritMask;
174 mask = maskRle(painter->clipBoundingRect());
176 mask = mask & inheritMask;
179 for (auto &i : list) {
180 painter->setBrush(i->mBrush);
182 if (!mask.isEmpty()) rle = i->rle() & mask;
184 if (!matteRle.isEmpty()) {
185 if (mLayerData->mMatteType == MatteType::AlphaInv) {
186 rle = rle - matteRle;
188 rle = rle & matteRle;
191 painter->drawRle(VPoint(), rle);
195 VRle LOTLayerItem::maskRle(const VRect &clipRect)
198 for (auto &i : mMasks) {
199 switch (i->maskMode()) {
200 case LOTMaskData::Mode::Add: {
201 rle = rle + i->rle();
204 case LOTMaskData::Mode::Substarct: {
205 if (rle.isEmpty() && !clipRect.isEmpty())
206 rle = VRle::toRle(clipRect);
207 rle = rle - i->rle();
210 case LOTMaskData::Mode::Intersect: {
211 rle = rle & i->rle();
221 LOTLayerItem::LOTLayerItem(LOTLayerData *layerData)
222 : mLayerData(layerData),
223 mParentLayer(nullptr),
224 mPrecompLayer(nullptr),
225 mCombinedAlpha(0.0f),
227 mDirtyFlag(DirtyFlagBit::All)
229 if (mLayerData->mHasMask) {
230 for (auto &i : mLayerData->mMasks) {
231 mMasks.push_back(std::make_unique<LOTMaskItem>(i.get()));
236 void LOTLayerItem::updateStaticProperty()
238 if (mParentLayer) mParentLayer->updateStaticProperty();
240 mStatic = mLayerData->isStatic();
241 mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
242 mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
245 void LOTLayerItem::update(int frameNo, const VMatrix &parentMatrix,
249 // 1. check if the layer is part of the current frame
250 if (!visible()) return;
252 // 2. calculate the parent matrix and alpha
253 VMatrix m = matrix(frameNo);
255 float alpha = parentAlpha * opacity(frameNo);
257 // 6. update the mask
259 for (auto &i : mMasks) i->update(frameNo, m, alpha, mDirtyFlag);
262 // 3. update the dirty flag based on the change
263 if (!mCombinedMatrix.fuzzyCompare(m)) {
264 mDirtyFlag |= DirtyFlagBit::Matrix;
266 if (!vCompare(mCombinedAlpha, alpha)) {
267 mDirtyFlag |= DirtyFlagBit::Alpha;
270 mCombinedAlpha = alpha;
272 // 4. if no parent property change and layer is static then nothing to do.
273 if ((flag() & DirtyFlagBit::None) && isStatic()) return;
275 // 5. update the content of the layer
278 // 6. reset the dirty flag
279 mDirtyFlag = DirtyFlagBit::None;
282 float LOTLayerItem::opacity(int frameNo) const
284 return mLayerData->mTransform->opacity(frameNo);
287 VMatrix LOTLayerItem::matrix(int frameNo) const
290 return mLayerData->mTransform->matrix(frameNo) *
291 mParentLayer->matrix(frameNo);
293 return mLayerData->mTransform->matrix(frameNo);
296 bool LOTLayerItem::visible() const
298 if (frameNo() >= mLayerData->inFrame() &&
299 frameNo() < mLayerData->outFrame())
305 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel)
306 : LOTLayerItem(layerModel)
308 for (auto &i : mLayerData->mChildren) {
309 LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
311 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
313 mLayers.push_back(layerItem);
314 mLayerMap[layerItem->id()] = layerItem;
319 // 2. update parent layer
320 for (auto &i : mLayers) {
321 int id = i->parentId();
323 auto search = mLayerMap.find(id);
324 if (search != mLayerMap.end()) {
325 LOTLayerItem *parentLayer = search->second;
326 i->setParentLayer(parentLayer);
329 i->setPrecompLayer(this);
333 void LOTCompLayerItem::updateStaticProperty()
335 LOTLayerItem::updateStaticProperty();
337 for (auto &i : mLayers) {
338 i->updateStaticProperty();
342 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, LOTLayerItem *matteSource)
346 std::vector<VDrawable *> matteList;
347 matteSource->renderList(matteList);
348 for (auto &i : matteList) {
349 matteRle = matteRle + i->rle();
353 VRle mask = inheritMask;
357 mask = maskRle(painter->clipBoundingRect());
359 mask = mask & inheritMask;
362 LOTLayerItem *matteLayer = nullptr;
363 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
364 LOTLayerItem *layer = *i;
366 if (!matteLayer && layer->hasMatte()) {
372 matteLayer->render(painter, mask, layer);
373 matteLayer = nullptr;
375 layer->render(painter, mask, nullptr);
380 LOTCompLayerItem::~LOTCompLayerItem()
382 for (auto &i : mLayers) {
387 void LOTCompLayerItem::updateContent()
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());
396 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
398 if (!visible()) return;
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);
407 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData)
408 : LOTLayerItem(layerData)
412 void LOTSolidLayerItem::updateContent()
415 mRenderNode = std::make_unique<LOTDrawable>();
416 mRenderNode->mType = VDrawable::Type::Fill;
417 mRenderNode->mFlag |= VDrawable::DirtyState::All;
420 if (flag() & DirtyFlagBit::Matrix) {
423 VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
424 path.transform(combinedMatrix());
425 mRenderNode->mFlag |= VDrawable::DirtyState::Path;
426 mRenderNode->mPath = path;
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;
436 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
438 if (!visible()) return;
440 list.push_back(mRenderNode.get());
443 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData)
444 : LOTLayerItem(layerData)
447 void LOTNullLayerItem::updateContent() {}
449 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData)
450 : LOTLayerItem(layerData)
452 mRoot = new LOTContentGroupItem(nullptr);
453 mRoot->addChildren(layerData);
454 mRoot->processPaintOperation();
455 if (layerData->hasPathOperator()) mRoot->processTrimOperation();
458 LOTShapeLayerItem::~LOTShapeLayerItem()
463 LOTContentItem *LOTShapeLayerItem::createContentItem(LOTData *contentData)
465 switch (contentData->type()) {
466 case LOTData::Type::ShapeGroup: {
467 return new LOTContentGroupItem(
468 static_cast<LOTShapeGroupData *>(contentData));
471 case LOTData::Type::Rect: {
472 return new LOTRectItem(static_cast<LOTRectData *>(contentData));
475 case LOTData::Type::Ellipse: {
476 return new LOTEllipseItem(static_cast<LOTEllipseData *>(contentData));
479 case LOTData::Type::Shape: {
480 return new LOTShapeItem(static_cast<LOTShapeData *>(contentData));
483 case LOTData::Type::Polystar: {
484 return new LOTPolystarItem(static_cast<LOTPolystarData *>(contentData));
487 case LOTData::Type::Fill: {
488 return new LOTFillItem(static_cast<LOTFillData *>(contentData));
491 case LOTData::Type::GFill: {
492 return new LOTGFillItem(static_cast<LOTGFillData *>(contentData));
495 case LOTData::Type::Stroke: {
496 return new LOTStrokeItem(static_cast<LOTStrokeData *>(contentData));
499 case LOTData::Type::GStroke: {
500 return new LOTGStrokeItem(static_cast<LOTGStrokeData *>(contentData));
503 case LOTData::Type::Repeater: {
504 return new LOTRepeaterItem(static_cast<LOTRepeaterData *>(contentData));
507 case LOTData::Type::Trim: {
508 return new LOTTrimItem(static_cast<LOTTrimData *>(contentData));
517 void LOTShapeLayerItem::updateContent()
519 mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
522 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
524 if (!visible()) return;
525 mRoot->renderList(list);
528 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data) : mData(data)
533 void LOTContentGroupItem::addChildren(LOTGroupData *data)
537 for (auto i : data->mChildren) {
538 LOTData * data = i.get();
539 LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
540 if (content) mContents.push_back(content);
544 LOTContentGroupItem::~LOTContentGroupItem()
546 for (auto i : mContents) {
551 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix,
552 float parentAlpha, const DirtyFlag &flag)
554 VMatrix m = parentMatrix;
555 float alpha = parentAlpha;
556 DirtyFlag newFlag = flag;
559 // update the matrix and the flag
560 if ((flag & DirtyFlagBit::Matrix) ||
561 !mData->mTransform->staticMatrix()) {
562 newFlag |= DirtyFlagBit::Matrix;
564 m = mData->mTransform->matrix(frameNo);
566 alpha *= mData->mTransform->opacity(frameNo);
568 if (!vCompare(alpha, parentAlpha)) {
569 newFlag |= DirtyFlagBit::Alpha;
573 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
574 (*i)->update(frameNo, m, alpha, newFlag);
578 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
580 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
581 (*i)->renderList(list);
585 void LOTContentGroupItem::processPaintOperation()
587 std::vector<LOTPaintDataItem *> list;
588 paintOperationHelper(list);
591 void LOTContentGroupItem::paintOperationHelper(
592 std::vector<LOTPaintDataItem *> &list)
594 int curOpCount = list.size();
595 for (auto i = mContents.rbegin(); i != mContents.rend(); ++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);
609 list.erase(list.begin() + curOpCount, list.end());
612 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list,
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));
623 void LOTContentGroupItem::processTrimOperation()
625 std::vector<LOTTrimItem *> list;
626 trimOperationHelper(list);
629 void LOTContentGroupItem::trimOperationHelper(std::vector<LOTTrimItem *> &list)
631 int curOpCount = list.size();
632 for (auto i = mContents.rbegin(); i != mContents.rend(); ++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);
646 list.erase(list.begin() + curOpCount, list.end());
649 void LOTPathDataItem::addTrimOperation(std::vector<LOTTrimItem *> &list)
651 for (auto trimItem : list) {
652 mTrimNodeRefs.push_back(trimItem);
656 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix,
657 float parentAlpha, const DirtyFlag &flag)
661 mPathChanged = false;
662 mCombinedAlpha = parentAlpha;
664 // 1. update the local path if needed
665 if (!(mInit && mStaticPath) && hasChanged(frameNo)) {
666 updatePath(mLocalPath, frameNo);
671 tempPath = mLocalPath;
673 // 2. apply path operation if needed
674 if (mTrimNodeRefs.size() > 0) {
675 // TODO apply more than one trim path if necessary
677 float s = mTrimNodeRefs.front()->getStart(frameNo) / 100.0f;
678 float e = mTrimNodeRefs.front()->getEnd(frameNo) / 100.0f;
681 tempPath = pm.trim(tempPath);
685 // 3. compute the final path with parentMatrix
687 if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
688 mFinalPath.clone(tempPath);
689 mFinalPath.transform(parentMatrix);
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,
699 i.drawable->mFlag |= VDrawable::DirtyState::Path;
701 if (i.drawable->mFlag & VDrawable::DirtyState::Path)
702 i.drawable->mPath = mFinalPath;
706 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
708 for (const auto &i : mRenderList) {
709 list.push_back(i.drawable);
713 VPath LOTPathDataItem::path() const
718 LOTRectItem::LOTRectItem(LOTRectData *data)
719 : LOTPathDataItem(data->isStatic()), mData(data)
723 void LOTRectItem::updatePath(VPath& path, int frameNo)
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(),
732 path.addRoundRect(r, roundness, roundness, mData->direction());
733 updateCache(frameNo, pos, size, roundness);
736 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data)
737 : LOTPathDataItem(data->isStatic()), mData(data)
741 void LOTEllipseItem::updatePath(VPath& path, int frameNo)
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(),
749 path.addOval(r, mData->direction());
750 updateCache(frameNo, pos, size);
753 LOTShapeItem::LOTShapeItem(LOTShapeData *data)
754 : LOTPathDataItem(data->isStatic()), mData(data)
758 void LOTShapeItem::updatePath(VPath& path, int frameNo)
760 mData->mShape.value(frameNo).toPath(path);
763 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data)
764 : LOTPathDataItem(data->isStatic()), mData(data)
768 void LOTPolystarItem::updatePath(VPath& path, int frameNo)
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);
781 if (mData->mType == LOTPolystarData::PolyType::Star) {
782 path.addPolystar(points, innerRadius, outerRadius, innerRoundness,
783 outerRoundness, 0.0, 0.0, 0.0, mData->direction());
785 path.addPolygon(points, outerRadius, outerRoundness, 0.0, 0.0, 0.0,
789 m.translate(pos.x(), pos.y()).rotate(rotation);
792 updateCache(frameNo, pos, points, innerRadius, outerRadius,
793 innerRoundness, outerRoundness, rotation);
797 * PaintData Node handling
801 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix,
802 float parentAlpha, const DirtyFlag &flag)
804 mContentChanged = false;
805 mParentAlpha = parentAlpha;
806 mParentMatrix = parentMatrix;
809 // 1. update the local content if needed
810 // if (!(mInit && mStaticContent)) {
812 updateContent(frameNo);
813 mContentChanged = true;
817 LOTFillItem::LOTFillItem(LOTFillData *data)
818 : LOTPaintDataItem(data->isStatic()), mData(data)
822 void LOTFillItem::updateContent(int frameNo)
824 LottieColor c = mData->mColor.value(frameNo);
825 float opacity = mData->opacity(frameNo);
826 mColor = c.toColor(opacity);
827 mFillRule = mData->fillRule();
830 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode,
831 VDrawable *drawable, bool sameParent)
833 VColor color = mColor;
835 color.setAlpha(color.a * pathNode->combinedAlpha());
837 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
839 drawable->setBrush(brush);
840 drawable->setFillRule(mFillRule);
843 LOTGFillItem::LOTGFillItem(LOTGFillData *data)
844 : LOTPaintDataItem(data->isStatic()), mData(data)
848 void LOTGFillItem::updateContent(int frameNo)
850 mData->update(mGradient, frameNo);
851 mGradient->mMatrix = mParentMatrix;
852 mFillRule = mData->fillRule();
855 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode,
856 VDrawable *drawable, bool sameParent)
858 drawable->setBrush(VBrush(mGradient.get()));
859 drawable->setFillRule(mFillRule);
862 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data)
863 : LOTPaintDataItem(data->isStatic()), mData(data)
868 void LOTStrokeItem::updateContent(int frameNo)
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);
882 static float getScale(const VMatrix &matrix)
884 constexpr float SQRT_2 = 1.41421;
886 VPointF p2(SQRT_2, SQRT_2);
889 VPointF final = p2 - p1;
891 return std::sqrt(final.x() * final.x() + final.y() * final.y());
894 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode,
895 VDrawable *drawable, bool sameParent)
897 VColor color = mColor;
899 color.setAlpha(color.a * pathNode->combinedAlpha());
901 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
904 drawable->setBrush(brush);
905 float scale = getScale(mParentMatrix);
906 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit,
908 if (mDashArraySize) {
909 for (int i = 0 ; i < mDashArraySize ; i++)
910 mDashArray[i] *= scale;
911 drawable->setDashInfo(mDashArray, mDashArraySize);
915 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data)
916 : LOTPaintDataItem(data->isStatic()), mData(data)
921 void LOTGStrokeItem::updateContent(int frameNo)
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);
934 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode,
935 VDrawable *drawable, bool sameParent)
937 float scale = getScale(mParentMatrix);
938 drawable->setBrush(VBrush(mGradient.get()));
939 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit,
941 if (mDashArraySize) {
942 for (int i = 0 ; i < mDashArraySize ; i++)
943 mDashArray[i] *= scale;
944 drawable->setDashInfo(mDashArray, mDashArraySize);
948 LOTTrimItem::LOTTrimItem(LOTTrimData *data) : mData(data) {}
950 void LOTTrimItem::update(int frameNo, const VMatrix &parentMatrix,
951 float parentAlpha, const DirtyFlag &flag)
955 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data) {}
957 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix,
958 float parentAlpha, const DirtyFlag &flag)
962 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list) {}
964 void LOTDrawable::sync()
966 mCNode.mFlag = ChangeFlagNone;
967 if (mFlag & DirtyState::None) return;
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;
981 if (mStroke.enable) {
982 mCNode.mStroke.width = mStroke.width;
983 mCNode.mStroke.meterLimit = mStroke.meterLimit;
984 mCNode.mStroke.enable = 1;
987 case FillRule::EvenOdd:
988 mCNode.mFillRule = LOTNode::EvenOdd;
991 mCNode.mFillRule = LOTNode::Winding;
995 switch (mStroke.cap) {
997 mCNode.mStroke.cap = LOTNode::FlatCap;
999 case CapStyle::Square:
1000 mCNode.mStroke.cap = LOTNode::SquareCap;
1002 case CapStyle::Round:
1003 mCNode.mStroke.cap = LOTNode::RoundCap;
1006 mCNode.mStroke.cap = LOTNode::FlatCap;
1010 switch (mStroke.join) {
1011 case JoinStyle::Miter:
1012 mCNode.mStroke.join = LOTNode::MiterJoin;
1014 case JoinStyle::Bevel:
1015 mCNode.mStroke.join = LOTNode::BevelJoin;
1017 case JoinStyle::Round:
1018 mCNode.mStroke.join = LOTNode::RoundJoin;
1021 mCNode.mStroke.join = LOTNode::MiterJoin;
1025 mCNode.mStroke.dashArray = mStroke.mDash.data();
1026 mCNode.mStroke.dashArraySize = mStroke.mDash.size();
1029 mCNode.mStroke.enable = 0;
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;
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;
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;