lottie/example: Added image_test.json(resource with image resource )
[platform/core/uifw/lottie-player.git] / src / vector / vdasher.cpp
1 /* 
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
3  * 
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  * 
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  * 
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "vdasher.h"
20 #include "vbezier.h"
21 #include "vline.h"
22
23 V_BEGIN_NAMESPACE
24
25 VDasher::VDasher(const float *dashArray, int size)
26 {
27     mDashArray = reinterpret_cast<const VDasher::Dash *>(dashArray);
28     mArraySize = size / 2;
29     if (size % 2)
30         mDashOffset = dashArray[size - 1];
31     mIndex = 0;
32     mCurrentLength = 0;
33     mDiscard = false;
34 }
35
36 void VDasher::moveTo(const VPointF &p)
37 {
38     mDiscard = false;
39     mStartNewSegment = true;
40     mCurPt = p;
41     mIndex = 0;
42
43     if (!vCompare(mDashOffset, 0.0f)) {
44         float totalLength = 0.0;
45         for (int i = 0; i < mArraySize; i++) {
46             totalLength = mDashArray[i].length + mDashArray[i].gap;
47         }
48         float normalizeLen = fmod(mDashOffset, totalLength);
49         if (normalizeLen < 0.0) {
50             normalizeLen = totalLength + normalizeLen;
51         }
52         // now the length is less than total length and +ve
53         // findout the current dash index , dashlength and gap.
54         for (int i = 0; i < mArraySize; i++) {
55             if (normalizeLen < mDashArray[i].length) {
56                 mIndex = i;
57                 mCurrentLength = mDashArray[i].length - normalizeLen;
58                 mDiscard = false;
59                 break;
60             }
61             normalizeLen -= mDashArray[i].length;
62             if (normalizeLen < mDashArray[i].gap) {
63                 mIndex = i;
64                 mCurrentLength = mDashArray[i].gap - normalizeLen;
65                 mDiscard = true;
66                 break;
67             }
68             normalizeLen -= mDashArray[i].gap;
69         }
70     } else {
71         mCurrentLength = mDashArray[mIndex].length;
72     }
73     if (vIsZero(mCurrentLength)) updateActiveSegment();
74 }
75
76 void VDasher::addLine(const VPointF &p)
77 {
78    if (mDiscard) return;
79
80    if (mStartNewSegment) {
81         mResult.moveTo(mCurPt);
82         mStartNewSegment = false;
83    }
84    mResult.lineTo(p);
85 }
86
87 void VDasher::updateActiveSegment()
88 {
89     mStartNewSegment = true;
90
91     if (mDiscard) {
92         mDiscard = false;
93         mIndex = (mIndex + 1) % mArraySize;
94         mCurrentLength = mDashArray[mIndex].length;
95     } else {
96         mDiscard = true;
97         mCurrentLength = mDashArray[mIndex].gap;
98     }
99     if (vIsZero(mCurrentLength)) updateActiveSegment();
100 }
101
102 void VDasher::lineTo(const VPointF &p)
103 {
104     VLine left, right;
105     VLine line(mCurPt, p);
106     float length = line.length();
107
108     if (length <= mCurrentLength) {
109         mCurrentLength -= length;
110         addLine(p);
111     } else {
112         while (length > mCurrentLength) {
113             length -= mCurrentLength;
114             line.splitAtLength(mCurrentLength, left, right);
115
116             addLine(left.p2());
117             updateActiveSegment();
118
119             line = right;
120             mCurPt = line.p1();
121         }
122         // handle remainder
123         if (length > 1.0) {
124             mCurrentLength -= length;
125             addLine(line.p2());
126         }
127     }
128
129     if (mCurrentLength < 1.0) updateActiveSegment();
130
131     mCurPt = p;
132 }
133
134 void VDasher::addCubic(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
135 {
136     if (mDiscard) return;
137
138     if (mStartNewSegment) {
139         mResult.moveTo(mCurPt);
140         mStartNewSegment = false;
141     }
142     mResult.cubicTo(cp1, cp2, e);
143 }
144
145 void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
146 {
147     VBezier left, right;
148     float   bezLen = 0.0;
149     VBezier b = VBezier::fromPoints(mCurPt, cp1, cp2, e);
150     bezLen = b.length();
151
152     if (bezLen <= mCurrentLength) {
153         mCurrentLength -= bezLen;
154         addCubic(cp1, cp2, e);
155     } else {
156         while (bezLen > mCurrentLength) {
157             bezLen -= mCurrentLength;
158             b.splitAtLength(mCurrentLength, &left, &right);
159
160             addCubic(left.pt2(), left.pt3(), left.pt4());
161             updateActiveSegment();
162
163             b = right;
164             mCurPt = b.pt1();
165         }
166         // handle remainder
167         if (bezLen > 1.0) {
168             mCurrentLength -= bezLen;
169             addCubic(b.pt2(), b.pt3(), b.pt4());
170         }
171     }
172
173     if (mCurrentLength < 1.0) updateActiveSegment();
174
175     mCurPt = e;
176 }
177
178 VPath VDasher::dashed(const VPath &path)
179 {
180     if (path.empty()) return VPath();
181
182     mResult = VPath();
183     mIndex = 0;
184     const std::vector<VPath::Element> &elms = path.elements();
185     const std::vector<VPointF> &       pts = path.points();
186     const VPointF *                    ptPtr = pts.data();
187
188     for (auto &i : elms) {
189         switch (i) {
190         case VPath::Element::MoveTo: {
191             moveTo(*ptPtr++);
192             break;
193         }
194         case VPath::Element::LineTo: {
195             lineTo(*ptPtr++);
196             break;
197         }
198         case VPath::Element::CubicTo: {
199             cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
200             ptPtr += 3;
201             break;
202         }
203         case VPath::Element::Close: {
204             // The point is already joined to start point in VPath
205             // no need to do anything here.
206             break;
207         }
208         default:
209             break;
210         }
211     }
212     return std::move(mResult);
213 }
214
215 V_END_NAMESPACE