tvg format: code refactoring #8
[platform/core/graphics/tizenvg.git] / src / lib / tvgSceneImpl.h
1 /*
2  * Copyright (c) 2020-2021 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_SCENE_IMPL_H_
23 #define _TVG_SCENE_IMPL_H_
24
25 #include <float.h>
26 #include "tvgPaint.h"
27
28 /************************************************************************/
29 /* Internal Class Implementation                                        */
30 /************************************************************************/
31
32 struct SceneIterator : Iterator
33 {
34     Array<Paint*>* paints;
35     uint32_t idx = 0;
36
37     SceneIterator(Array<Paint*>* p) : paints(p)
38     {
39     }
40
41     const Paint* next() override
42     {
43         if (idx >= paints->count) return nullptr;
44         return paints->data[idx++];
45     }
46 };
47
48 struct Scene::Impl
49 {
50     Array<Paint*> paints;
51     uint8_t opacity;                     //for composition
52     RenderMethod* renderer = nullptr;    //keep it for explicit clear
53
54     ~Impl()
55     {
56         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
57             delete(*paint);
58         }
59     }
60
61     bool dispose(RenderMethod& renderer)
62     {
63         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
64             (*paint)->pImpl->dispose(renderer);
65         }
66
67         this->renderer = nullptr;
68
69         return true;
70     }
71
72     bool needComposition(uint32_t opacity)
73     {
74         //Half translucent requires intermediate composition.
75         if (opacity == 255 || opacity == 0) return false;
76
77         //If scene has several children or only scene, it may require composition.
78         if (paints.count > 1) return true;
79         if (paints.count == 1 && (*paints.data)->id() == TVG_CLASS_ID_SCENE) return true;
80         return false;
81     }
82
83     void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
84     {
85         /* Overriding opacity value. If this scene is half-translucent,
86            It must do intermeidate composition with that opacity value. */
87         this->opacity = static_cast<uint8_t>(opacity);
88         if (needComposition(opacity)) opacity = 255;
89
90         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
91             (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast<uint32_t>(flag));
92         }
93
94         /* FXIME: it requires to return list of children engine data
95            This is necessary for scene composition */
96
97         this->renderer = &renderer;
98
99         return nullptr;
100     }
101
102     bool render(RenderMethod& renderer)
103     {
104         Compositor* cmp = nullptr;
105
106         if (needComposition(opacity)) {
107             cmp = renderer.target(bounds(renderer));
108             renderer.beginComposite(cmp, CompositeMethod::None, opacity);
109         }
110
111         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
112             if (!(*paint)->pImpl->render(renderer)) return false;
113         }
114
115         if (cmp) renderer.endComposite(cmp);
116
117         return true;
118     }
119
120     RenderRegion bounds(RenderMethod& renderer) const
121     {
122         if (paints.count == 0) return {0, 0, 0, 0};
123
124         uint32_t x1 = UINT32_MAX;
125         uint32_t y1 = UINT32_MAX;
126         uint32_t x2 = 0;
127         uint32_t y2 = 0;
128
129         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
130             auto region = (*paint)->pImpl->bounds(renderer);
131
132             //Merge regions
133             if (region.x < x1) x1 = region.x;
134             if (x2 < region.x + region.w) x2 = (region.x + region.w);
135             if (region.y < y1) y1 = region.y;
136             if (y2 < region.y + region.h) y2 = (region.y + region.h);
137         }
138
139         return {x1, y1, (x2 - x1), (y2 - y1)};
140     }
141
142     bool bounds(float* px, float* py, float* pw, float* ph) const
143     {
144         if (paints.count == 0) return false;
145
146         auto x1 = FLT_MAX;
147         auto y1 = FLT_MAX;
148         auto x2 = -FLT_MAX;
149         auto y2 = -FLT_MAX;
150
151         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
152             auto x = FLT_MAX;
153             auto y = FLT_MAX;
154             auto w = 0.0f;
155             auto h = 0.0f;
156
157             if (!(*paint)->pImpl->bounds(&x, &y, &w, &h)) continue;
158
159             //Merge regions
160             if (x < x1) x1 = x;
161             if (x2 < x + w) x2 = (x + w);
162             if (y < y1) y1 = y;
163             if (y2 < y + h) y2 = (y + h);
164         }
165
166         if (px) *px = x1;
167         if (py) *py = y1;
168         if (pw) *pw = (x2 - x1);
169         if (ph) *ph = (y2 - y1);
170
171         return true;
172     }
173
174     Paint* duplicate()
175     {
176         auto ret = Scene::gen();
177         if (!ret) return nullptr;
178         auto dup = ret.get()->pImpl;
179
180         dup->paints.reserve(paints.count);
181
182         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
183             dup->paints.push((*paint)->duplicate());
184         }
185
186         return ret.release();
187     }
188
189     void clear(bool free)
190     {
191         auto dispose = renderer ? true : false;
192
193         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
194             if (dispose) (*paint)->pImpl->dispose(*renderer);
195             if (free) delete(*paint);
196         }
197         paints.clear();
198         renderer = nullptr;
199     }
200
201     Iterator* iterator()
202     {
203         return new SceneIterator(&paints);
204     }
205 };
206
207 #endif //_TVG_SCENE_IMPL_H_