resolve some unpexpected code involving while upstream code sync.
[platform/core/graphics/tizenvg.git] / src / lib / tvgShapeImpl.h
1 /*
2  * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. 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 #ifndef _TVG_SHAPE_IMPL_H_
23 #define _TVG_SHAPE_IMPL_H_
24
25 #include <memory.h>
26 #include "tvgPaint.h"
27
28 /************************************************************************/
29 /* Internal Class Implementation                                        */
30 /************************************************************************/
31
32 struct ShapeStroke
33 {
34     float width = 0;
35     uint8_t color[4] = {0, 0, 0, 0};
36     Fill *fill = nullptr;
37     float* dashPattern = nullptr;
38     uint32_t dashCnt = 0;
39     StrokeCap cap = StrokeCap::Square;
40     StrokeJoin join = StrokeJoin::Bevel;
41
42     ShapeStroke() {}
43
44     ShapeStroke(const ShapeStroke* src)
45      : width(src->width),
46        dashCnt(src->dashCnt),
47        cap(src->cap),
48        join(src->join)
49     {
50         memcpy(color, src->color, sizeof(color));
51         dashPattern = static_cast<float*>(malloc(sizeof(float) * dashCnt));
52         memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt);
53         if (src->fill)
54             fill = src->fill->duplicate();
55     }
56
57     ~ShapeStroke()
58     {
59         if (dashPattern) free(dashPattern);
60         if (fill) delete(fill);
61     }
62 };
63
64
65 struct ShapePath
66 {
67     PathCommand* cmds = nullptr;
68     uint32_t cmdCnt = 0;
69     uint32_t reservedCmdCnt = 0;
70
71     Point *pts = nullptr;
72     uint32_t ptsCnt = 0;
73     uint32_t reservedPtsCnt = 0;
74
75     ~ShapePath()
76     {
77         if (cmds) free(cmds);
78         if (pts) free(pts);
79     }
80
81     ShapePath()
82     {
83     }
84
85     void duplicate(const ShapePath* src)
86     {
87         cmdCnt = src->cmdCnt;
88         reservedCmdCnt = src->reservedCmdCnt;
89         ptsCnt = src->ptsCnt;
90         reservedPtsCnt = src->reservedPtsCnt;
91
92         cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * reservedCmdCnt));
93         if (!cmds) return;
94         memcpy(cmds, src->cmds, sizeof(PathCommand) * cmdCnt);
95
96         pts = static_cast<Point*>(malloc(sizeof(Point) * reservedPtsCnt));
97         if (!pts) {
98             free(cmds);
99             return;
100         }
101         memcpy(pts, src->pts, sizeof(Point) * ptsCnt);
102     }
103
104     void reserveCmd(uint32_t cmdCnt)
105     {
106         if (cmdCnt <= reservedCmdCnt) return;
107         reservedCmdCnt = cmdCnt;
108         cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
109     }
110
111     void reservePts(uint32_t ptsCnt)
112     {
113         if (ptsCnt <= reservedPtsCnt) return;
114         reservedPtsCnt = ptsCnt;
115         pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
116     }
117
118     void grow(uint32_t cmdCnt, uint32_t ptsCnt)
119     {
120         reserveCmd(this->cmdCnt + cmdCnt);
121         reservePts(this->ptsCnt + ptsCnt);
122     }
123
124     void reset()
125     {
126         cmdCnt = 0;
127         ptsCnt = 0;
128     }
129
130     void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
131     {
132         memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
133         memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt);
134         this->cmdCnt += cmdCnt;
135         this->ptsCnt += ptsCnt;
136     }
137
138     void moveTo(float x, float y)
139     {
140         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
141         if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
142
143         cmds[cmdCnt++] = PathCommand::MoveTo;
144         pts[ptsCnt++] = {x, y};
145     }
146
147     void lineTo(float x, float y)
148     {
149         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
150         if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
151
152         cmds[cmdCnt++] = PathCommand::LineTo;
153         pts[ptsCnt++] = {x, y};
154     }
155
156     void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
157     {
158         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
159         if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
160
161         cmds[cmdCnt++] = PathCommand::CubicTo;
162         pts[ptsCnt++] = {cx1, cy1};
163         pts[ptsCnt++] = {cx2, cy2};
164         pts[ptsCnt++] = {x, y};
165     }
166
167     void close()
168     {
169         if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return;
170
171         if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
172         cmds[cmdCnt++] = PathCommand::Close;
173     }
174
175     bool bounds(float* x, float* y, float* w, float* h) const
176     {
177         if (ptsCnt == 0) return false;
178
179         Point min = { pts[0].x, pts[0].y };
180         Point max = { pts[0].x, pts[0].y };
181
182         for (uint32_t i = 1; i < ptsCnt; ++i) {
183             if (pts[i].x < min.x) min.x = pts[i].x;
184             if (pts[i].y < min.y) min.y = pts[i].y;
185             if (pts[i].x > max.x) max.x = pts[i].x;
186             if (pts[i].y > max.y) max.y = pts[i].y;
187         }
188
189         if (x) *x = min.x;
190         if (y) *y = min.y;
191         if (w) *w = max.x - min.x;
192         if (h) *h = max.y - min.y;
193
194         return true;
195     }
196 };
197
198
199 struct Shape::Impl
200 {
201     ShapePath path;
202     Fill *fill = nullptr;
203     ShapeStroke *stroke = nullptr;
204     uint8_t color[4] = {0, 0, 0, 0};    //r, g, b, a
205     FillRule rule = FillRule::Winding;
206     RenderData rdata = nullptr;         //engine data
207     Shape *shape = nullptr;
208     uint32_t flag = RenderUpdateFlag::None;
209
210     Impl(Shape* s) : shape(s)
211     {
212     }
213
214     ~Impl()
215     {
216         if (fill) delete(fill);
217         if (stroke) delete(stroke);
218     }
219
220     bool dispose(RenderMethod& renderer)
221     {
222         auto ret = renderer.dispose(rdata);
223         rdata = nullptr;
224         return ret;
225     }
226
227     bool render(RenderMethod& renderer)
228     {
229         return renderer.renderShape(rdata);
230     }
231
232     void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
233     {
234         this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
235         flag = RenderUpdateFlag::None;
236         return this->rdata;
237     }
238
239     RenderRegion bounds(RenderMethod& renderer)
240     {
241         return renderer.region(rdata);
242     }
243
244     bool bounds(float* x, float* y, float* w, float* h)
245     {
246         auto ret = path.bounds(x, y, w, h);
247
248         //Stroke feathering
249         if (stroke) {
250             if (x) *x -= stroke->width * 0.5f;
251             if (y) *y -= stroke->width * 0.5f;
252             if (w) *w += stroke->width;
253             if (h) *h += stroke->width;
254         }
255         return ret;
256     }
257
258     bool strokeWidth(float width)
259     {
260         //TODO: Size Exception?
261
262         if (!stroke) stroke = new ShapeStroke();
263         if (!stroke) return false;
264
265         stroke->width = width;
266         flag |= RenderUpdateFlag::Stroke;
267
268         return true;
269     }
270
271     bool strokeCap(StrokeCap cap)
272     {
273         if (!stroke) stroke = new ShapeStroke();
274         if (!stroke) return false;
275
276         stroke->cap = cap;
277         flag |= RenderUpdateFlag::Stroke;
278
279         return true;
280     }
281
282     bool strokeJoin(StrokeJoin join)
283     {
284         if (!stroke) stroke = new ShapeStroke();
285         if (!stroke) return false;
286
287         stroke->join = join;
288         flag |= RenderUpdateFlag::Stroke;
289
290         return true;
291     }
292
293     bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
294     {
295         if (!stroke) stroke = new ShapeStroke();
296         if (!stroke) return false;
297
298         if (stroke->fill) {
299             delete(stroke->fill);
300             stroke->fill = nullptr;
301             flag |= RenderUpdateFlag::GradientStroke;
302         }
303
304         stroke->color[0] = r;
305         stroke->color[1] = g;
306         stroke->color[2] = b;
307         stroke->color[3] = a;
308
309         flag |= RenderUpdateFlag::Stroke;
310
311         return true;
312     }
313
314     Result strokeFill(unique_ptr<Fill> f)
315     {
316         auto p = f.release();
317         if (!p) return Result::MemoryCorruption;
318
319         if (!stroke) stroke = new ShapeStroke();
320         if (!stroke) return Result::FailedAllocation;
321
322         if (stroke->fill && stroke->fill != p) delete(stroke->fill);
323         stroke->fill = p;
324
325         flag |= RenderUpdateFlag::Stroke;
326         flag |= RenderUpdateFlag::GradientStroke;
327
328         return Result::Success;
329     }
330
331     bool strokeDash(const float* pattern, uint32_t cnt)
332     {
333        if (!stroke) stroke = new ShapeStroke();
334        if (!stroke) return false;
335
336         if (stroke->dashCnt != cnt) {
337             if (stroke->dashPattern) free(stroke->dashPattern);
338             stroke->dashPattern = nullptr;
339         }
340
341         if (!stroke->dashPattern) {
342             stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
343             if (!stroke->dashPattern) return false;
344         }
345
346         for (uint32_t i = 0; i < cnt; ++i)
347             stroke->dashPattern[i] = pattern[i];
348
349         stroke->dashCnt = cnt;
350         flag |= RenderUpdateFlag::Stroke;
351
352         return true;
353     }
354
355     Paint* duplicate()
356     {
357         auto ret = Shape::gen();
358         if (!ret) return nullptr;
359
360         auto dup = ret.get()->pImpl;
361         dup->rule = rule;
362
363         //Color
364         memcpy(dup->color, color, sizeof(color));
365         dup->flag = RenderUpdateFlag::Color;
366
367         //Path
368         dup->path.duplicate(&path);
369         dup->flag |= RenderUpdateFlag::Path;
370
371         //Stroke
372         if (stroke) {
373             dup->stroke = new ShapeStroke(stroke);
374             dup->flag |= RenderUpdateFlag::Stroke;
375
376             if (stroke->fill)
377                 dup->flag |= RenderUpdateFlag::GradientStroke;
378         }
379
380         //Fill
381         if (fill) {
382             dup->fill = fill->duplicate();
383             dup->flag |= RenderUpdateFlag::Gradient;
384         }
385
386         return ret.release();
387     }
388 };
389
390 #endif //_TVG_SHAPE_IMPL_H_