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