common: code refactoring
[platform/core/graphics/tizenvg.git] / src / lib / tvgShape.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_SHAPE_CPP_
18 #define _TVG_SHAPE_CPP_
19
20 #include "tvgCommon.h"
21 #include "tvgShapeImpl.h"
22
23 /************************************************************************/
24 /* Internal Class Implementation                                        */
25 /************************************************************************/
26 constexpr auto PATH_KAPPA = 0.552284f;
27
28 /************************************************************************/
29 /* External Class Implementation                                        */
30 /************************************************************************/
31
32 Shape :: Shape() : pImpl(make_unique<Impl>())
33 {
34     _id = PAINT_ID_SHAPE;
35
36     Paint::pImpl.get()->ts = pImpl.get()->transformMethod();
37 }
38
39
40 Shape :: ~Shape()
41 {
42 }
43
44
45 unique_ptr<Shape> Shape::gen() noexcept
46 {
47     return unique_ptr<Shape>(new Shape);
48 }
49
50
51 Result Shape::reset() noexcept
52 {
53     IMPL->path->reset();
54
55     IMPL->flag |= RenderUpdateFlag::Path;
56
57     return Result::Success;
58 }
59
60
61 uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept
62 {
63     if (!cmds) return 0;
64
65     *cmds = IMPL->path->cmds;
66
67     return IMPL->path->cmdCnt;
68 }
69
70
71 uint32_t Shape::pathCoords(const Point** pts) const noexcept
72 {
73     if (!pts) return 0;
74
75     *pts = IMPL->path->pts;
76
77     return IMPL->path->ptsCnt;
78 }
79
80
81 Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept
82 {
83     if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments;
84
85     IMPL->path->grow(cmdCnt, ptsCnt);
86     IMPL->path->append(cmds, cmdCnt, pts, ptsCnt);
87
88     IMPL->flag |= RenderUpdateFlag::Path;
89
90     return Result::Success;
91 }
92
93
94 Result Shape::moveTo(float x, float y) noexcept
95 {
96     IMPL->path->moveTo(x, y);
97
98     IMPL->flag |= RenderUpdateFlag::Path;
99
100     return Result::Success;
101 }
102
103
104 Result Shape::lineTo(float x, float y) noexcept
105 {
106     IMPL->path->lineTo(x, y);
107
108     IMPL->flag |= RenderUpdateFlag::Path;
109
110     return Result::Success;
111 }
112
113
114 Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept
115 {
116     IMPL->path->cubicTo(cx1, cy1, cx2, cy2, x, y);
117
118     IMPL->flag |= RenderUpdateFlag::Path;
119
120     return Result::Success;
121 }
122
123
124 Result Shape::close() noexcept
125 {
126     IMPL->path->close();
127
128     IMPL->flag |= RenderUpdateFlag::Path;
129
130     return Result::Success;
131 }
132
133
134 Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
135 {
136     auto impl = pImpl.get();
137
138     auto rxKappa = rx * PATH_KAPPA;
139     auto ryKappa = ry * PATH_KAPPA;
140
141     impl->path->grow(6, 13);
142     impl->path->moveTo(cx, cy - ry);
143     impl->path->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
144     impl->path->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
145     impl->path->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
146     impl->path->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
147     impl->path->close();
148
149     impl->flag |= RenderUpdateFlag::Path;
150
151     return Result::Success;
152 }
153
154
155 Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept
156 {
157     auto impl = pImpl.get();
158
159     auto halfW = w * 0.5f;
160     auto halfH = h * 0.5f;
161
162     //clamping cornerRadius by minimum size
163     if (rx > halfW) rx = halfW;
164     if (ry > halfH) ry = halfH;
165
166     //rectangle
167     if (rx == 0 && ry == 0) {
168         impl->path->grow(5, 4);
169         impl->path->moveTo(x, y);
170         impl->path->lineTo(x + w, y);
171         impl->path->lineTo(x + w, y + h);
172         impl->path->lineTo(x, y + h);
173         impl->path->close();
174     //circle
175     } else if (fabsf(rx - halfW) < FLT_EPSILON && fabsf(ry - halfH) < FLT_EPSILON) {
176         return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
177     } else {
178         auto hrx = rx * 0.5f;
179         auto hry = ry * 0.5f;
180         impl->path->grow(10, 17);
181         impl->path->moveTo(x + rx, y);
182         impl->path->lineTo(x + w - rx, y);
183         impl->path->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
184         impl->path->lineTo(x + w, y + h - ry);
185         impl->path->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
186         impl->path->lineTo(x + rx, y + h);
187         impl->path->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
188         impl->path->lineTo(x, y + ry);
189         impl->path->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
190         impl->path->close();
191     }
192
193     impl->flag |= RenderUpdateFlag::Path;
194
195     return Result::Success;
196 }
197
198
199 Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
200 {
201     auto impl = pImpl.get();
202
203     impl->color[0] = r;
204     impl->color[1] = g;
205     impl->color[2] = b;
206     impl->color[3] = a;
207     impl->flag |= RenderUpdateFlag::Color;
208
209     if (impl->fill) {
210         delete(impl->fill);
211         impl->fill = nullptr;
212         impl->flag |= RenderUpdateFlag::Gradient;
213     }
214
215     return Result::Success;
216 }
217
218
219 Result Shape::fill(unique_ptr<Fill> f) noexcept
220 {
221     auto impl = pImpl.get();
222
223     auto p = f.release();
224     if (!p) return Result::MemoryCorruption;
225
226     if (impl->fill) delete(impl->fill);
227     impl->fill = p;
228     impl->flag |= RenderUpdateFlag::Gradient;
229
230     return Result::Success;
231 }
232
233
234 Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
235 {
236     auto impl = pImpl.get();
237
238     if (r) *r = impl->color[0];
239     if (g) *g = impl->color[1];
240     if (b) *b = impl->color[2];
241     if (a) *a = impl->color[3];
242
243     return Result::Success;
244 }
245
246 const Fill* Shape::fill() const noexcept
247 {
248     return IMPL->fill;
249 }
250
251
252 Result Shape::stroke(float width) noexcept
253 {
254     if (!IMPL->strokeWidth(width)) return Result::FailedAllocation;
255
256     return Result::Success;
257 }
258
259
260 float Shape::strokeWidth() const noexcept
261 {
262     if (!IMPL->stroke) return 0;
263     return IMPL->stroke->width;
264 }
265
266
267 Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
268 {
269     if (!IMPL->strokeColor(r, g, b, a)) return Result::FailedAllocation;
270
271     return Result::Success;
272 }
273
274
275 Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
276 {
277     auto impl = pImpl.get();
278
279     if (!impl->stroke) return Result::InsufficientCondition;
280
281     if (r) *r = impl->stroke->color[0];
282     if (g) *g = impl->stroke->color[1];
283     if (b) *b = impl->stroke->color[2];
284     if (a) *a = impl->stroke->color[3];
285
286     return Result::Success;
287 }
288
289
290 Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept
291 {
292     if (cnt < 2 || !dashPattern) return Result::InvalidArguments;
293
294     if (!IMPL->strokeDash(dashPattern, cnt)) return Result::FailedAllocation;
295
296     return Result::Success;
297 }
298
299
300 uint32_t Shape::strokeDash(const float** dashPattern) const noexcept
301 {
302     if (!IMPL->stroke) return 0;
303
304     if (dashPattern) *dashPattern = IMPL->stroke->dashPattern;
305     return IMPL->stroke->dashCnt;
306 }
307
308
309 Result Shape::stroke(StrokeCap cap) noexcept
310 {
311     if (!IMPL->strokeCap(cap)) return Result::FailedAllocation;
312
313     return Result::Success;
314 }
315
316
317 Result Shape::stroke(StrokeJoin join) noexcept
318 {
319     if (!IMPL->strokeJoin(join)) return Result::FailedAllocation;
320
321     return Result::Success;
322 }
323
324
325 StrokeCap Shape::strokeCap() const noexcept
326 {
327     if (!IMPL->stroke) return StrokeCap::Square;
328
329     return IMPL->stroke->cap;
330 }
331
332
333 StrokeJoin Shape::strokeJoin() const noexcept
334 {
335     if (!IMPL->stroke) return StrokeJoin::Bevel;
336
337     return IMPL->stroke->join;
338 }
339
340
341 #endif //_TVG_SHAPE_CPP_