implement rle raster.
[platform/core/graphics/tizenvg.git] / src / lib / sw_engine / tvgSwShape.cpp
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_SW_SHAPE_H_
18 #define _TVG_SW_SHAPE_H_
19
20 #include "tvgSwCommon.h"
21
22 /************************************************************************/
23 /* Internal Class Implementation                                        */
24 /************************************************************************/
25
26 static void growOutlineContour(SwOutline& outline, size_t n)
27 {
28     if (n == 0) {
29         free(outline.cntrs);
30         outline.cntrs = nullptr;
31         outline.cntrsCnt = 0;
32         outline.reservedCntrsCnt = 0;
33         return;
34     }
35     if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
36
37     cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
38     outline.reservedCntrsCnt = n;
39     outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
40     assert(outline.cntrs);
41 }
42
43
44 static void growOutlinePoint(SwOutline& outline, size_t n)
45 {
46     if (n == 0) {
47         free(outline.pts);
48         outline.pts = nullptr;
49         free(outline.tags);
50         outline.tags = nullptr;
51         outline.reservedPtsCnt = 0;
52         outline.ptsCnt = 0;
53         return;
54     }
55
56     if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
57
58     cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
59     outline.reservedPtsCnt = n;
60     outline.pts = static_cast<Point*>(realloc(outline.pts, n * sizeof(Point)));
61     assert(outline.pts);
62     outline.tags = static_cast<char*>(realloc(outline.tags, n * sizeof(char)));
63     assert(outline.tags);
64 }
65
66
67 static void outlineEnd(SwOutline& outline)
68 {
69     growOutlineContour(outline, 1);
70     if (outline.ptsCnt > 0) {
71         outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
72         ++outline.cntrsCnt;
73     }
74 }
75
76
77 static void outlineMoveTo(SwOutline& outline, const Point* pt)
78 {
79     assert(pt);
80
81     growOutlinePoint(outline, 1);
82
83     outline.pts[outline.ptsCnt] = *pt;
84     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
85
86     if (outline.ptsCnt > 0) {
87         growOutlineContour(outline, 1);
88         outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
89         ++outline.cntrsCnt;
90     }
91
92     ++outline.ptsCnt;
93 }
94
95
96 static void outlineLineTo(SwOutline& outline, const Point* pt)
97 {
98     assert(pt);
99
100     growOutlinePoint(outline, 1);
101
102     outline.pts[outline.ptsCnt] = *pt;
103     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
104
105     ++outline.ptsCnt;
106 }
107
108
109 static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* pt)
110 {
111     assert(ctrl1 && ctrl2 && pt);
112
113     growOutlinePoint(outline, 3);
114
115     outline.pts[outline.ptsCnt] = *ctrl1;
116     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
117     ++outline.ptsCnt;
118
119     outline.pts[outline.ptsCnt] = *ctrl2;
120     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
121     ++outline.ptsCnt;
122
123     outline.pts[outline.ptsCnt] = *ctrl1;
124     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
125     ++outline.ptsCnt;
126 }
127
128
129 static bool outlineClose(SwOutline& outline)
130 {
131     size_t i = 0;
132
133     if (outline.cntrsCnt > 0) {
134         i = outline.cntrs[outline.cntrsCnt - 1] + 1;
135     } else {
136         i = 0;   //First Path
137     }
138
139     //Make sure there is at least one point in the current path
140     if (outline.ptsCnt == i) return false;
141
142     //Close the path
143     growOutlinePoint(outline, 1);
144
145     outline.pts[outline.ptsCnt] = outline.pts[i];
146     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
147     ++outline.ptsCnt;
148
149     return true;
150 }
151
152
153 static void initBBox(SwShape& sdata)
154 {
155     sdata.bbox.xMin = sdata.bbox.yMin = 0;
156     sdata.bbox.xMax = sdata.bbox.yMax = 0;
157 }
158
159
160 static bool updateBBox(SwShape& sdata)
161 {
162     auto outline = sdata.outline;
163     assert(outline);
164
165     auto pt = outline->pts;
166     assert(pt);
167
168     if (outline->ptsCnt <= 0) {
169         initBBox(sdata);
170         return false;
171     }
172
173     auto xMin = pt->x;
174     auto xMax = pt->y;
175     auto yMin = pt->y;
176     auto yMax = pt->y;
177
178     ++pt;
179
180     for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
181         assert(pt);
182         if (xMin > pt->x) xMin = pt->x;
183         if (xMax < pt->y) xMax = pt->x;
184         if (yMin > pt->y) yMin = pt->y;
185         if (yMax < pt->y) yMax = pt->y;
186     }
187     sdata.bbox.xMin = round(xMin - 0.49);
188     sdata.bbox.xMax = round(xMax + 0.49);
189     sdata.bbox.yMin = round(yMin - 0.49);
190     sdata.bbox.yMax = round(yMax + 0.49);
191
192     if (xMax - xMin < 1 || yMax - yMin < 1) return false;
193
194     return true;
195 }
196
197
198 /************************************************************************/
199 /* External Class Implementation                                        */
200 /************************************************************************/
201
202 bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
203 {
204     //TODO:
205     return true;
206 }
207
208
209 void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
210 {
211     if (sdata.rle.spans) free(sdata.rle.spans);
212     sdata.rle.spans = nullptr;
213 }
214
215
216 bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
217 {
218     shapeDelRle(shape, sdata);
219     if (!updateBBox(sdata)) return false;
220     return rleRender(sdata);
221 }
222
223
224 void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
225 {
226     if (!sdata.outline) return;
227
228     SwOutline* outline = sdata.outline;
229     if (outline->cntrs) free(outline->cntrs);
230     if (outline->pts) free(outline->pts);
231     if (outline->tags) free(outline->tags);
232     free(outline);
233
234     sdata.outline = nullptr;
235 }
236
237
238 bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
239 {
240     initBBox(sdata);
241
242     const PathCommand* cmds = nullptr;
243     auto cmdCnt = shape.pathCommands(&cmds);
244
245     const Point* pts = nullptr;
246     auto ptsCnt = shape.pathCoords(&pts);
247
248     //No actual shape data
249     if (cmdCnt == 0 || ptsCnt == 0) return false;
250
251     //smart reservation
252     auto outlinePtsCnt = 0;
253     auto outlineCntrsCnt = 0;
254 //    auto closed = false;
255
256     for (auto i = 0; i < cmdCnt; ++i) {
257         switch(*(cmds + i)) {
258             case PathCommand::Close: {
259                 ++outlinePtsCnt;
260                 break;
261             }
262             case PathCommand::MoveTo: {
263                 ++outlineCntrsCnt;
264                 ++outlinePtsCnt;
265                 break;
266             }
267             case PathCommand::LineTo: {
268                 ++outlinePtsCnt;
269                 break;
270             }
271             case PathCommand::CubicTo: {
272                 outlinePtsCnt += 3;
273                 break;
274             }
275         }
276     }
277
278     ++outlinePtsCnt;    //for close
279     ++outlineCntrsCnt;  //for end
280
281     SwOutline* outline = sdata.outline;
282
283     if (!outline) {
284         outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
285         assert(outline);
286     } else {
287         cout << "Outline was already allocated? How?" << endl;
288     }
289
290     //TODO: Probabry we can copy pts from shape directly.
291     growOutlinePoint(*outline, outlinePtsCnt);
292     growOutlineContour(*outline, outlineCntrsCnt);
293
294     //Generate Outlines
295     while (cmdCnt-- > 0) {
296         switch(*cmds) {
297             case PathCommand::Close: {
298                 outlineClose(*outline);
299                 break;
300             }
301             case PathCommand::MoveTo: {
302                 outlineMoveTo(*outline, pts);
303                 ++pts;
304                 break;
305             }
306             case PathCommand::LineTo: {
307                 outlineLineTo(*outline, pts);
308                 ++pts;
309                 break;
310             }
311             case PathCommand::CubicTo: {
312                 outlineCubicTo(*outline, pts, pts + 1, pts + 2);
313                 pts += 3;
314                 break;
315             }
316         }
317         ++cmds;
318     }
319
320     outlineEnd(*outline);
321
322     //FIXME:
323     //outline->flags = SwOutline::FillRule::Winding;
324
325     sdata.outline = outline;
326
327     return true;
328 }
329
330
331 #endif /* _TVG_SW_SHAPE_H_ */