common engines: code refactoring
[platform/core/graphics/tizenvg.git] / src / lib / tvgPaint.h
1 /*
2  * Copyright (c) 2020 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_PAINT_H_
23 #define _TVG_PAINT_H_
24
25 #include <float.h>
26 #include <math.h>
27 #include "tvgRender.h"
28
29 namespace tvg
30 {
31     enum class PaintType { Shape = 0, Scene, Picture };
32
33     struct StrategyMethod
34     {
35         virtual ~StrategyMethod() {}
36
37         virtual bool dispose(RenderMethod& renderer) = 0;
38         virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0;   //Return engine data if it has.
39         virtual bool render(RenderMethod& renderer) = 0;
40         virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
41         virtual RenderRegion bounds(RenderMethod& renderer) const = 0;
42         virtual Paint* duplicate() = 0;
43     };
44
45     struct Paint::Impl
46     {
47         StrategyMethod* smethod = nullptr;
48         RenderTransform *rTransform = nullptr;
49         uint32_t flag = RenderUpdateFlag::None;
50
51         Paint* cmpTarget = nullptr;
52         CompositeMethod cmpMethod = CompositeMethod::None;
53
54         uint8_t opacity = 255;
55
56         PaintType type;
57
58         ~Impl() {
59             if (cmpTarget) delete(cmpTarget);
60             if (smethod) delete(smethod);
61             if (rTransform) delete(rTransform);
62         }
63
64         void method(StrategyMethod* method)
65         {
66             smethod = method;
67         }
68
69         bool rotate(float degree)
70         {
71             if (rTransform) {
72                 if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true;
73             } else {
74                 if (fabsf(degree) <= FLT_EPSILON) return true;
75                 rTransform = new RenderTransform();
76                 if (!rTransform) return false;
77             }
78             rTransform->degree = degree;
79             if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
80
81             return true;
82         }
83
84         bool scale(float factor)
85         {
86             if (rTransform) {
87                 if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true;
88             } else {
89                 if (fabsf(factor) <= FLT_EPSILON) return true;
90                 rTransform = new RenderTransform();
91                 if (!rTransform) return false;
92             }
93             rTransform->scale = factor;
94             if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
95
96             return true;
97         }
98
99         bool translate(float x, float y)
100         {
101             if (rTransform) {
102                 if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true;
103             } else {
104                 if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true;
105                 rTransform = new RenderTransform();
106                 if (!rTransform) return false;
107             }
108             rTransform->x = x;
109             rTransform->y = y;
110             if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
111
112             return true;
113         }
114
115         bool transform(const Matrix& m)
116         {
117             if (!rTransform) {
118                 rTransform = new RenderTransform();
119                 if (!rTransform) return false;
120             }
121             rTransform->override(m);
122             flag |= RenderUpdateFlag::Transform;
123
124             return true;
125         }
126
127         bool bounds(float* x, float* y, float* w, float* h) const
128         {
129             return smethod->bounds(x, y, w, h);
130         }
131
132         RenderRegion bounds(RenderMethod& renderer) const
133         {
134             return smethod->bounds(renderer);
135         }
136
137         bool dispose(RenderMethod& renderer)
138         {
139             if (cmpTarget) cmpTarget->pImpl->dispose(renderer);
140             return smethod->dispose(renderer);
141         }
142
143         void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
144         {
145             if (flag & RenderUpdateFlag::Transform) {
146                 if (!rTransform) return nullptr;
147                 if (!rTransform->update()) {
148                     delete(rTransform);
149                     rTransform = nullptr;
150                 }
151             }
152
153             void *cmpData = nullptr;
154
155             if (cmpTarget) {
156                 cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag);
157                 if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
158             }
159
160             void *edata = nullptr;
161             auto newFlag = static_cast<RenderUpdateFlag>(pFlag | flag);
162             flag = RenderUpdateFlag::None;
163             opacity = (opacity * this->opacity) / 255;
164
165             if (rTransform && pTransform) {
166                 RenderTransform outTransform(pTransform, rTransform);
167                 edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
168             } else {
169                 auto outTransform = pTransform ? pTransform : rTransform;
170                 edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
171             }
172
173             if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop();
174
175             return edata;
176         }
177
178         bool render(RenderMethod& renderer)
179         {
180             Compositor* cmp = nullptr;
181
182             /* Note: only ClipPath is processed in update() step.
183                Create a composition image. */
184             if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) {
185                 auto region = cmpTarget->pImpl->bounds(renderer);
186                 if (region.w == 0 || region.h == 0) return false;
187                 cmp = renderer.target(region);
188                 renderer.beginComposite(cmp, CompositeMethod::None, 255);
189                 cmpTarget->pImpl->render(renderer);
190             }
191
192             if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity);
193
194             auto ret = smethod->render(renderer);
195
196             if (cmp) renderer.endComposite(cmp);
197
198             return ret;
199         }
200
201         Paint* duplicate()
202         {
203             auto ret = smethod->duplicate();
204             if (!ret) return nullptr;
205
206             //duplicate Transform
207             if (rTransform) {
208                 ret->pImpl->rTransform = new RenderTransform();
209                 if (ret->pImpl->rTransform) {
210                     *ret->pImpl->rTransform = *rTransform;
211                     ret->pImpl->flag |= RenderUpdateFlag::Transform;
212                 }
213             }
214
215             ret->pImpl->opacity = opacity;
216
217             if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate();
218
219             ret->pImpl->cmpMethod = cmpMethod;
220
221             return ret;
222         }
223
224         bool composite(Paint* target, CompositeMethod method)
225         {
226             if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false;
227             cmpTarget = target;
228             cmpMethod = method;
229             return true;
230         }
231     };
232
233
234     template<class T>
235     struct PaintMethod : StrategyMethod
236     {
237         T* inst = nullptr;
238
239         PaintMethod(T* _inst) : inst(_inst) {}
240         ~PaintMethod() {}
241
242         bool bounds(float* x, float* y, float* w, float* h) const override
243         {
244             return inst->bounds(x, y, w, h);
245         }
246
247         RenderRegion bounds(RenderMethod& renderer) const override
248         {
249             return inst->bounds(renderer);
250         }
251
252         bool dispose(RenderMethod& renderer) override
253         {
254             return inst->dispose(renderer);
255         }
256
257         void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag) override
258         {
259             return inst->update(renderer, transform, opacity, clips, flag);
260         }
261
262         bool render(RenderMethod& renderer) override
263         {
264             return inst->render(renderer);
265         }
266
267         Paint* duplicate() override
268         {
269             return inst->duplicate();
270         }
271     };
272 }
273
274 #endif //_TVG_PAINT_H_