e36e96997b3a0070e744afc9b8bd7e862055fc1f
[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         return true;
223         auto ret = renderer.dispose(rdata);
224         rdata = nullptr;
225         return ret;
226     }
227
228     bool render(RenderMethod& renderer)
229     {
230         return true;
231         return renderer.renderShape(rdata);
232     }
233
234     void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
235     {
236         return nullptr;
237         this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
238         flag = RenderUpdateFlag::None;
239         return this->rdata;
240     }
241
242     RenderRegion bounds(RenderMethod& renderer)
243     {
244         return renderer.region(rdata);
245     }
246
247     bool bounds(float* x, float* y, float* w, float* h)
248     {
249         auto ret = path.bounds(x, y, w, h);
250
251         //Stroke feathering
252         if (stroke) {
253             if (x) *x -= stroke->width * 0.5f;
254             if (y) *y -= stroke->width * 0.5f;
255             if (w) *w += stroke->width;
256             if (h) *h += stroke->width;
257         }
258         return ret;
259     }
260
261     bool strokeWidth(float width)
262     {
263         //TODO: Size Exception?
264
265         if (!stroke) stroke = new ShapeStroke();
266         if (!stroke) return false;
267
268         stroke->width = width;
269         flag |= RenderUpdateFlag::Stroke;
270
271         return true;
272     }
273
274     bool strokeCap(StrokeCap cap)
275     {
276         if (!stroke) stroke = new ShapeStroke();
277         if (!stroke) return false;
278
279         stroke->cap = cap;
280         flag |= RenderUpdateFlag::Stroke;
281
282         return true;
283     }
284
285     bool strokeJoin(StrokeJoin join)
286     {
287         if (!stroke) stroke = new ShapeStroke();
288         if (!stroke) return false;
289
290         stroke->join = join;
291         flag |= RenderUpdateFlag::Stroke;
292
293         return true;
294     }
295
296     bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
297     {
298         if (!stroke) stroke = new ShapeStroke();
299         if (!stroke) return false;
300
301         if (stroke->fill) {
302             delete(stroke->fill);
303             stroke->fill = nullptr;
304             flag |= RenderUpdateFlag::GradientStroke;
305         }
306
307         stroke->color[0] = r;
308         stroke->color[1] = g;
309         stroke->color[2] = b;
310         stroke->color[3] = a;
311
312         flag |= RenderUpdateFlag::Stroke;
313
314         return true;
315     }
316
317     Result strokeFill(unique_ptr<Fill> f)
318     {
319         auto p = f.release();
320         if (!p) return Result::MemoryCorruption;
321
322         if (!stroke) stroke = new ShapeStroke();
323         if (!stroke) return Result::FailedAllocation;
324
325         if (stroke->fill && stroke->fill != p) delete(stroke->fill);
326         stroke->fill = p;
327
328         flag |= RenderUpdateFlag::Stroke;
329         flag |= RenderUpdateFlag::GradientStroke;
330
331         return Result::Success;
332     }
333
334     bool strokeDash(const float* pattern, uint32_t cnt)
335     {
336        if (!stroke) stroke = new ShapeStroke();
337        if (!stroke) return false;
338
339         if (stroke->dashCnt != cnt) {
340             if (stroke->dashPattern) free(stroke->dashPattern);
341             stroke->dashPattern = nullptr;
342         }
343
344         if (!stroke->dashPattern) {
345             stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
346             if (!stroke->dashPattern) return false;
347         }
348
349         for (uint32_t i = 0; i < cnt; ++i)
350             stroke->dashPattern[i] = pattern[i];
351
352         stroke->dashCnt = cnt;
353         flag |= RenderUpdateFlag::Stroke;
354
355         return true;
356     }
357
358     Paint* duplicate()
359     {
360         auto ret = Shape::gen();
361         if (!ret) return nullptr;
362
363         auto dup = ret.get()->pImpl;
364         dup->rule = rule;
365
366         //Color
367         memcpy(dup->color, color, sizeof(color));
368         dup->flag = RenderUpdateFlag::Color;
369
370         //Path
371         dup->path.duplicate(&path);
372         dup->flag |= RenderUpdateFlag::Path;
373
374         //Stroke
375         if (stroke) {
376             dup->stroke = new ShapeStroke(stroke);
377             dup->flag |= RenderUpdateFlag::Stroke;
378
379             if (stroke->fill)
380                 dup->flag |= RenderUpdateFlag::GradientStroke;
381         }
382
383         //Fill
384         if (fill) {
385             dup->fill = fill->duplicate();
386             dup->flag |= RenderUpdateFlag::Gradient;
387         }
388
389         return ret.release();
390     }
391 };
392
393 #endif //_TVG_SHAPE_IMPL_H_