common shape: support scale/rotate transform
[platform/core/graphics/tizenvg.git] / src / lib / tvgShapePath.h
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *               http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  */
17 #ifndef _TVG_SHAPE_PATH_CPP_
18 #define _TVG_SHAPE_PATH_CPP_
19
20 #include "tvgCommon.h"
21
22 /************************************************************************/
23 /* Internal Class Implementation                                        */
24 /************************************************************************/
25
26 struct ShapePath
27 {
28     PathCommand* cmds = nullptr;
29     size_t cmdCnt = 0;
30     size_t reservedCmdCnt = 0;
31
32     Point *pts = nullptr;
33     size_t ptsCnt = 0;
34     size_t reservedPtsCnt = 0;
35
36
37     ~ShapePath()
38     {
39         if (cmds) delete(cmds);
40         if (pts) delete(pts);
41     }
42
43     void reserveCmd(size_t cmdCnt)
44     {
45         if (cmdCnt <= reservedCmdCnt) return;
46         reservedCmdCnt = cmdCnt;
47         cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
48         assert(cmds);
49     }
50
51     void reservePts(size_t ptsCnt)
52     {
53         if (ptsCnt <= reservedPtsCnt) return;
54         reservedPtsCnt = ptsCnt;
55         pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
56         assert(pts);
57     }
58
59     void grow(size_t cmdCnt, size_t ptsCnt)
60     {
61         reserveCmd(this->cmdCnt + cmdCnt);
62         reservePts(this->ptsCnt + ptsCnt);
63     }
64
65     void reset()
66     {
67         cmdCnt = 0;
68         ptsCnt = 0;
69     }
70
71     void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt)
72     {
73         memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
74         memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt);
75         this->cmdCnt += cmdCnt;
76         this->ptsCnt += ptsCnt;
77     }
78
79     void moveTo(float x, float y)
80     {
81         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
82         if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
83
84         cmds[cmdCnt++] = PathCommand::MoveTo;
85         pts[ptsCnt++] = {x, y};
86     }
87
88     void lineTo(float x, float y)
89     {
90         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
91         if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
92
93         cmds[cmdCnt++] = PathCommand::LineTo;
94         pts[ptsCnt++] = {x, y};
95     }
96
97     void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
98     {
99         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
100         if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
101
102         cmds[cmdCnt++] = PathCommand::CubicTo;
103         pts[ptsCnt++] = {cx1, cy1};
104         pts[ptsCnt++] = {cx2, cy2};
105         pts[ptsCnt++] = {x, y};
106     }
107
108     void close()
109     {
110         if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return;
111
112         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
113         cmds[cmdCnt++] = PathCommand::Close;
114     }
115
116     bool bounds(float& x, float& y, float& w, float& h)
117     {
118         if (ptsCnt == 0) return false;
119
120         Point min = { pts[0].x, pts[0].y };
121         Point max = { pts[0].x, pts[0].y };
122
123         for(size_t i = 1; i < ptsCnt; ++i) {
124             if (pts[i].x < min.x) min.x = pts[i].x;
125             if (pts[i].y < min.y) min.y = pts[i].y;
126             if (pts[i].x > max.x) max.x = pts[i].x;
127             if (pts[i].y > max.y) max.y = pts[i].y;
128         }
129
130         x = min.x;
131         y = min.y;
132         w = max.x - min.x;
133         h = max.y - min.y;
134
135         return true;
136     }
137
138     bool rotate(float degree)
139     {
140         constexpr auto PI = 3.141592f;
141
142         if (fabsf(degree) <= FLT_EPSILON) return false;
143
144         float x, y, w, h;
145         if (!bounds(x, y, w, h)) return false;
146
147         auto radian = degree / 180.0f * PI;
148         auto cx = x + w * 0.5f;
149         auto cy = y + h * 0.5f;
150         auto cosVal = cosf(radian);
151         auto sinVal = sinf(radian);
152
153         for(size_t i = 0; i < ptsCnt; ++i) {
154             auto dx = pts[i].x - cx;
155             auto dy = pts[i].y - cy;
156             pts[i].x = (cosVal * dx - sinVal * dy) + cx;
157             pts[i].y = (sinVal * dx + cosVal * dy) + cy;
158         }
159
160         return true;
161     }
162
163     bool scale(float factor)
164     {
165         if (fabsf(factor - 1) <= FLT_EPSILON) return false;
166
167         float x, y, w, h;
168         if (!bounds(x, y, w, h)) return false;
169
170         auto cx = x + w * 0.5f;
171         auto cy = y + h * 0.5f;
172
173         for(size_t i = 0; i < ptsCnt; ++i) {
174             pts[i].x = (pts[i].x - cx) * factor + cx;
175             pts[i].y = (pts[i].y - cy) * factor + cy;
176         }
177
178         return true;
179     }
180 };
181
182 #endif //_TVG_SHAPE_PATH_CPP_