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