sw_engine: implment basic stroke functions.
[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, uint32_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<uint32_t*>(realloc(outline.cntrs, n * sizeof(uint32_t)));
40     assert(outline.cntrs);
41 }
42
43
44 static void _growOutlinePoint(SwOutline& outline, uint32_t n)
45 {
46     if (n == 0) {
47         free(outline.pts);
48         outline.pts = nullptr;
49         free(outline.types);
50         outline.types = 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<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
61     assert(outline.pts);
62     outline.types = static_cast<uint8_t*>(realloc(outline.types, n * sizeof(uint8_t)));
63     assert(outline.types);
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* to)
78 {
79     assert(to);
80
81     _growOutlinePoint(outline, 1);
82
83     outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
84     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
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* to)
97 {
98     assert(to);
99
100     _growOutlinePoint(outline, 1);
101
102     outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
103     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
104
105     ++outline.ptsCnt;
106 }
107
108
109 static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
110 {
111     assert(ctrl1 && ctrl2 && to);
112
113     _growOutlinePoint(outline, 3);
114
115     outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
116     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC;
117     ++outline.ptsCnt;
118
119     outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2);
120     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC;
121     ++outline.ptsCnt;
122
123     outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
124     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
125     ++outline.ptsCnt;
126 }
127
128
129 static void _outlineClose(SwOutline& outline)
130 {
131     uint32_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) {
141         outline.opened = true;
142         return;
143     }
144
145     //Close the path
146     _growOutlinePoint(outline, 1);
147
148     outline.pts[outline.ptsCnt] = outline.pts[i];
149     outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
150     ++outline.ptsCnt;
151
152     outline.opened = false;
153 }
154
155
156 static void _initBBox(SwShape& sdata)
157 {
158     sdata.bbox.min.x = sdata.bbox.min.y = 0;
159     sdata.bbox.max.x = sdata.bbox.max.y = 0;
160 }
161
162
163 static bool _updateBBox(SwShape& sdata)
164 {
165     auto outline = sdata.outline;
166     assert(outline);
167
168     auto pt = outline->pts;
169     assert(pt);
170
171     if (outline->ptsCnt <= 0) {
172         _initBBox(sdata);
173         return false;
174     }
175
176     auto xMin = pt->x;
177     auto xMax = pt->x;
178     auto yMin = pt->y;
179     auto yMax = pt->y;
180
181     ++pt;
182
183     for(uint32_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
184         assert(pt);
185         if (xMin > pt->x) xMin = pt->x;
186         if (xMax < pt->x) xMax = pt->x;
187         if (yMin > pt->y) yMin = pt->y;
188         if (yMax < pt->y) yMax = pt->y;
189     }
190     sdata.bbox.min.x = xMin >> 6;
191     sdata.bbox.max.x = (xMax + 63) >> 6;
192     sdata.bbox.min.y = yMin >> 6;
193     sdata.bbox.max.y = (yMax + 63) >> 6;
194
195     if (xMax - xMin < 1 || yMax - yMin < 1) return false;
196
197     return true;
198 }
199
200
201 static bool _checkValid(SwShape& sdata, const SwSize& clip)
202 {
203     assert(sdata.outline);
204
205     if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false;
206
207     //Check boundary
208     if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) ||
209         (sdata.bbox.min.x + sdata.bbox.max.x < 0) ||
210         (sdata.bbox.min.y + sdata.bbox.max.y < 0)) return false;
211
212     return true;
213 }
214
215
216 static void _deleteRle(SwShape& sdata)
217 {
218     if (!sdata.rle) return;
219     if (sdata.rle->spans) free(sdata.rle->spans);
220     free(sdata.rle);
221     sdata.rle = nullptr;
222 }
223
224
225
226 /************************************************************************/
227 /* External Class Implementation                                        */
228 /************************************************************************/
229
230 void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform)
231 {
232     auto outline = sdata.outline;
233     assert(outline);
234
235     for(uint32_t i = 0; i < outline->ptsCnt; ++i) {
236         auto dx = static_cast<float>(outline->pts[i].x >> 6);
237         auto dy = static_cast<float>(outline->pts[i].y >> 6);
238         auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13;
239         auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23;
240         auto pt = Point{tx + transform.e31, ty + transform.e32};
241         outline->pts[i] = TO_SWPOINT(&pt);
242     }
243 }
244
245
246 bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
247 {
248     if (!_updateBBox(sdata)) goto end;
249     if (!_checkValid(sdata, clip)) goto end;
250
251     sdata.rle = rleRender(sdata, clip);
252
253 end:
254     if (sdata.rle) return true;
255     return false;
256 }
257
258
259 void shapeDelOutline(SwShape& sdata)
260 {
261     auto outline = sdata.outline;
262     if (!outline) return;
263
264     if (outline->cntrs) free(outline->cntrs);
265     if (outline->pts) free(outline->pts);
266     if (outline->types) free(outline->types);
267     free(outline);
268     sdata.outline = nullptr;
269 }
270
271
272 void shapeReset(SwShape& sdata)
273 {
274     shapeDelOutline(sdata);
275     _deleteRle(sdata);
276     _initBBox(sdata);
277 }
278
279
280 bool shapeGenOutline(const Shape& shape, SwShape& sdata)
281 {
282     const PathCommand* cmds = nullptr;
283     auto cmdCnt = shape.pathCommands(&cmds);
284
285     const Point* pts = nullptr;
286     auto ptsCnt = shape.pathCoords(&pts);
287
288     //No actual shape data
289     if (cmdCnt == 0 || ptsCnt == 0) return false;
290
291     //smart reservation
292     auto outlinePtsCnt = 0;
293     auto outlineCntrsCnt = 0;
294
295     for (uint32_t i = 0; i < cmdCnt; ++i) {
296         switch(*(cmds + i)) {
297             case PathCommand::Close: {
298                 ++outlinePtsCnt;
299                 break;
300             }
301             case PathCommand::MoveTo: {
302                 ++outlineCntrsCnt;
303                 ++outlinePtsCnt;
304                 break;
305             }
306             case PathCommand::LineTo: {
307                 ++outlinePtsCnt;
308                 break;
309             }
310             case PathCommand::CubicTo: {
311                 outlinePtsCnt += 3;
312                 break;
313             }
314         }
315     }
316
317     ++outlinePtsCnt;    //for close
318     ++outlineCntrsCnt;  //for end
319
320     auto outline = sdata.outline;
321     if (!outline) outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
322     assert(outline);
323
324     _growOutlinePoint(*outline, outlinePtsCnt);
325     _growOutlineContour(*outline, outlineCntrsCnt);
326
327     //Generate Outlines
328     while (cmdCnt-- > 0) {
329         switch(*cmds) {
330             case PathCommand::Close: {
331                 _outlineClose(*outline);
332                 break;
333             }
334             case PathCommand::MoveTo: {
335                 _outlineMoveTo(*outline, pts);
336                 ++pts;
337                 break;
338             }
339             case PathCommand::LineTo: {
340                 _outlineLineTo(*outline, pts);
341                 ++pts;
342                 break;
343             }
344             case PathCommand::CubicTo: {
345                 _outlineCubicTo(*outline, pts, pts + 1, pts + 2);
346                 pts += 3;
347                 break;
348             }
349         }
350         ++cmds;
351     }
352
353     _outlineEnd(*outline);
354
355     //FIXME:
356     //outline->flags = SwOutline::FillRule::Winding;
357
358     sdata.outline = outline;
359
360     return true;
361 }
362
363
364 void shapeFree(SwShape* sdata)
365 {
366     assert(sdata);
367
368     shapeDelOutline(*sdata);
369     _deleteRle(*sdata);
370     strokeFree(sdata->stroke);
371     free(sdata);
372 }
373
374
375 void shapeResetStroke(const Shape& shape, SwShape& sdata)
376 {
377     if (!sdata.stroke) sdata.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
378     auto stroke = sdata.stroke;
379     assert(stroke);
380
381     strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin());
382 }
383
384
385 bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
386 {
387     if (!sdata.outline) {
388         if (!shapeGenOutline(shape, sdata)) return false;
389     }
390
391     if (!_checkValid(sdata, clip)) return false;
392
393     if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false;
394
395     return true;
396 }
397
398 #endif /* _TVG_SW_SHAPE_H_ */