common shape: code refactoring & data optimization.
[platform/core/graphics/tizenvg.git] / src / lib / tvgShapeImpl.h
1 /*
2  * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
3
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 #ifndef _TVG_SHAPE_IMPL_H_
24 #define _TVG_SHAPE_IMPL_H_
25
26 #include <memory.h>
27 #include "tvgPaint.h"
28
29 /************************************************************************/
30 /* Internal Class Implementation                                        */
31 /************************************************************************/
32
33 struct Shape::Impl
34 {
35     RenderShape rs;                     //shape data
36     RenderData rdata = nullptr;         //engine data
37     uint32_t flag = RenderUpdateFlag::None;
38
39     bool dispose(RenderMethod& renderer)
40     {
41         auto ret = renderer.dispose(rdata);
42         rdata = nullptr;
43         return ret;
44     }
45
46     bool render(RenderMethod& renderer)
47     {
48         return renderer.renderShape(rdata);
49     }
50
51     void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
52     {
53         rdata = renderer.prepare(rs, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
54         flag = RenderUpdateFlag::None;
55         return rdata;
56     }
57
58     RenderRegion bounds(RenderMethod& renderer)
59     {
60         return renderer.region(rdata);
61     }
62
63     bool bounds(float* x, float* y, float* w, float* h)
64     {
65         //Path bounding size
66         if (rs.path.ptsCnt > 0 ) {
67             Point min = { rs.path.pts[0].x, rs.path.pts[0].y };
68             Point max = { rs.path.pts[0].x, rs.path.pts[0].y };
69
70             for (uint32_t i = 1; i < rs.path.ptsCnt; ++i) {
71                 if (rs.path.pts[i].x < min.x) min.x = rs.path.pts[i].x;
72                 if (rs.path.pts[i].y < min.y) min.y = rs.path.pts[i].y;
73                 if (rs.path.pts[i].x > max.x) max.x = rs.path.pts[i].x;
74                 if (rs.path.pts[i].y > max.y) max.y = rs.path.pts[i].y;
75             }
76
77             if (x) *x = min.x;
78             if (y) *y = min.y;
79             if (w) *w = max.x - min.x;
80             if (h) *h = max.y - min.y;
81         }
82
83         //Stroke feathering
84         if (rs.stroke) {
85             if (x) *x -= rs.stroke->width * 0.5f;
86             if (y) *y -= rs.stroke->width * 0.5f;
87             if (w) *w += rs.stroke->width;
88             if (h) *h += rs.stroke->width;
89         }
90         return rs.path.ptsCnt > 0 ? true : false;
91     }
92
93     void reserveCmd(uint32_t cmdCnt)
94     {
95         if (cmdCnt <= rs.path.reservedCmdCnt) return;
96         rs.path.reservedCmdCnt = cmdCnt;
97         rs.path.cmds = static_cast<PathCommand*>(realloc(rs.path.cmds, sizeof(PathCommand) * rs.path.reservedCmdCnt));
98     }
99
100     void reservePts(uint32_t ptsCnt)
101     {
102         if (ptsCnt <= rs.path.reservedPtsCnt) return;
103         rs.path.reservedPtsCnt = ptsCnt;
104         rs.path.pts = static_cast<Point*>(realloc(rs.path.pts, sizeof(Point) * rs.path.reservedPtsCnt));
105     }
106
107     void grow(uint32_t cmdCnt, uint32_t ptsCnt)
108     {
109         reserveCmd(rs.path.cmdCnt + cmdCnt);
110         reservePts(rs.path.ptsCnt + ptsCnt);
111     }
112
113     void reset()
114     {
115         rs.path.cmdCnt = 0;
116         rs.path.ptsCnt = 0;
117
118         flag = RenderUpdateFlag::Path;
119     }
120
121     void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
122     {
123         memcpy(rs.path.cmds + rs.path.cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
124         memcpy(rs.path.pts + rs.path.ptsCnt, pts, sizeof(Point) * ptsCnt);
125         rs.path.cmdCnt += cmdCnt;
126         rs.path.ptsCnt += ptsCnt;
127
128         flag |= RenderUpdateFlag::Path;
129     }
130
131     void moveTo(float x, float y)
132     {
133         if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
134         if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
135
136         rs.path.cmds[rs.path.cmdCnt++] = PathCommand::MoveTo;
137         rs.path.pts[rs.path.ptsCnt++] = {x, y};
138
139         flag |= RenderUpdateFlag::Path;
140     }
141
142     void lineTo(float x, float y)
143     {
144         if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
145         if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
146
147         rs.path.cmds[rs.path.cmdCnt++] = PathCommand::LineTo;
148         rs.path.pts[rs.path.ptsCnt++] = {x, y};
149
150         flag |= RenderUpdateFlag::Path;
151     }
152
153     void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
154     {
155         if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
156         if (rs.path.ptsCnt + 3 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 3) * 2);
157
158         rs.path.cmds[rs.path.cmdCnt++] = PathCommand::CubicTo;
159         rs.path.pts[rs.path.ptsCnt++] = {cx1, cy1};
160         rs.path.pts[rs.path.ptsCnt++] = {cx2, cy2};
161         rs.path.pts[rs.path.ptsCnt++] = {x, y};
162
163         flag |= RenderUpdateFlag::Path;
164     }
165
166     void close()
167     {
168         if (rs.path.cmdCnt > 0 && rs.path.cmds[rs.path.cmdCnt - 1] == PathCommand::Close) return;
169
170         if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
171         rs.path.cmds[rs.path.cmdCnt++] = PathCommand::Close;
172
173         flag |= RenderUpdateFlag::Path;
174     }
175
176     bool strokeWidth(float width)
177     {
178         //TODO: Size Exception?
179
180         if (!rs.stroke) rs.stroke = new RenderStroke();
181         rs.stroke->width = width;
182         flag |= RenderUpdateFlag::Stroke;
183
184         return true;
185     }
186
187     bool strokeCap(StrokeCap cap)
188     {
189         if (!rs.stroke) rs.stroke = new RenderStroke();
190         rs.stroke->cap = cap;
191         flag |= RenderUpdateFlag::Stroke;
192
193         return true;
194     }
195
196     bool strokeJoin(StrokeJoin join)
197     {
198         if (!rs.stroke) rs.stroke = new RenderStroke();
199         rs.stroke->join = join;
200         flag |= RenderUpdateFlag::Stroke;
201
202         return true;
203     }
204
205     bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
206     {
207         if (!rs.stroke) rs.stroke = new RenderStroke();
208         if (rs.stroke->fill) {
209             delete(rs.stroke->fill);
210             rs.stroke->fill = nullptr;
211             flag |= RenderUpdateFlag::GradientStroke;
212         }
213
214         rs.stroke->color[0] = r;
215         rs.stroke->color[1] = g;
216         rs.stroke->color[2] = b;
217         rs.stroke->color[3] = a;
218
219         flag |= RenderUpdateFlag::Stroke;
220
221         return true;
222     }
223
224     Result strokeFill(unique_ptr<Fill> f)
225     {
226         auto p = f.release();
227         if (!p) return Result::MemoryCorruption;
228
229         if (!rs.stroke) rs.stroke = new RenderStroke();
230         if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
231         rs.stroke->fill = p;
232
233         flag |= RenderUpdateFlag::Stroke;
234         flag |= RenderUpdateFlag::GradientStroke;
235
236         return Result::Success;
237     }
238
239     bool strokeDash(const float* pattern, uint32_t cnt)
240     {
241         //Reset dash
242         if (!pattern && cnt == 0) {
243             free(rs.stroke->dashPattern);
244             rs.stroke->dashPattern = nullptr;
245         } else {
246             if (!rs.stroke) rs.stroke = new RenderStroke();
247             if (rs.stroke->dashCnt != cnt) {
248                 free(rs.stroke->dashPattern);
249                 rs.stroke->dashPattern = nullptr;
250             }
251             if (!rs.stroke->dashPattern) {
252                 rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
253                 if (!rs.stroke->dashPattern) return false;
254             }
255             for (uint32_t i = 0; i < cnt; ++i) {
256                 rs.stroke->dashPattern[i] = pattern[i];
257             }
258         }
259         rs.stroke->dashCnt = cnt;
260         flag |= RenderUpdateFlag::Stroke;
261
262         return true;
263     }
264
265     Paint* duplicate()
266     {
267         auto ret = Shape::gen();
268
269         auto dup = ret.get()->pImpl;
270         dup->rs.rule = rs.rule;
271
272         //Color
273         memcpy(dup->rs.color, rs.color, sizeof(rs.color));
274         dup->flag = RenderUpdateFlag::Color;
275
276         //Path
277         if (rs.path.cmdCnt > 0 && rs.path.ptsCnt > 0) {
278             dup->rs.path.cmdCnt = rs.path.cmdCnt;
279             dup->rs.path.reservedCmdCnt = rs.path.reservedCmdCnt;
280             dup->rs.path.ptsCnt = rs.path.ptsCnt;
281             dup->rs.path.reservedPtsCnt = rs.path.reservedPtsCnt;
282
283             dup->rs.path.cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * dup->rs.path.reservedCmdCnt));
284             if (dup->rs.path.cmds) memcpy(dup->rs.path.cmds, rs.path.cmds, sizeof(PathCommand) * dup->rs.path.cmdCnt);
285
286             dup->rs.path.pts = static_cast<Point*>(malloc(sizeof(Point) * dup->rs.path.reservedPtsCnt));
287             if (dup->rs.path.pts) memcpy(dup->rs.path.pts, rs.path.pts, sizeof(Point) * dup->rs.path.ptsCnt);
288         }
289         dup->flag |= RenderUpdateFlag::Path;
290
291         //Stroke
292         if (rs.stroke) {
293             dup->rs.stroke = new RenderStroke();
294             dup->rs.stroke->width = rs.stroke->width;
295             dup->rs.stroke->dashCnt = rs.stroke->dashCnt;
296             dup->rs.stroke->cap = rs.stroke->cap;
297             dup->rs.stroke->join = rs.stroke->join;
298             memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color));
299
300             if (rs.stroke->dashCnt > 0) {
301                 dup->rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * rs.stroke->dashCnt));
302                 memcpy(dup->rs.stroke->dashPattern, rs.stroke->dashPattern, sizeof(float) * rs.stroke->dashCnt);
303             }
304
305             dup->flag |= RenderUpdateFlag::Stroke;
306
307             if (rs.stroke->fill) {
308                 dup->rs.stroke->fill = rs.stroke->fill->duplicate();
309                 dup->flag |= RenderUpdateFlag::GradientStroke;
310             }
311         }
312
313         //Fill
314         if (rs.fill) {
315             dup->rs.fill = rs.fill->duplicate();
316             dup->flag |= RenderUpdateFlag::Gradient;
317         }
318
319         return ret.release();
320     }
321
322     Iterator* iterator()
323     {
324         return nullptr;
325     }
326 };
327
328 #endif //_TVG_SHAPE_IMPL_H_