2 * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
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:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
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
27 #include "tvgRender.h"
29 static inline bool FLT_SAME(float a, float b)
31 return (fabsf(a - b) < FLT_EPSILON);
34 static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transform, RenderRegion& viewport)
36 /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
37 auto shape = static_cast<Shape*>(cmpTarget);
39 //Rectangle Candidates?
41 if (shape->pathCoords(&pts) != 4) return false;
45 if (transform->m.e12 != 0 || transform->m.e21 != 0 || transform->m.e11 != transform->m.e22) return false;
48 //Othogonal Rectangle?
54 if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) ||
55 (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) {
63 x1 = x1 * transform->m.e11 + transform->m.e13;
64 y1 = y1 * transform->m.e22 + transform->m.e23;
65 x2 = x2 * transform->m.e11 + transform->m.e13;
66 y2 = y2 * transform->m.e22 + transform->m.e23;
69 viewport.x = static_cast<uint32_t>(x1);
70 viewport.y = static_cast<uint32_t>(y1);
71 viewport.w = static_cast<uint32_t>(roundf(x2 - x1 + 0.5f));
72 viewport.h = static_cast<uint32_t>(roundf(y2 - y1 + 0.5f));
83 enum class PaintType { Shape = 0, Scene, Picture };
87 virtual ~StrategyMethod() {}
89 virtual bool dispose(RenderMethod& renderer) = 0;
90 virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
91 virtual bool render(RenderMethod& renderer) = 0;
92 virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
93 virtual RenderRegion bounds(RenderMethod& renderer) const = 0;
94 virtual Paint* duplicate() = 0;
99 StrategyMethod* smethod = nullptr;
100 RenderTransform *rTransform = nullptr;
101 uint32_t flag = RenderUpdateFlag::None;
103 Paint* cmpTarget = nullptr;
104 CompositeMethod cmpMethod = CompositeMethod::None;
106 uint8_t opacity = 255;
111 if (cmpTarget) delete(cmpTarget);
112 if (smethod) delete(smethod);
113 if (rTransform) delete(rTransform);
116 void method(StrategyMethod* method)
121 bool rotate(float degree)
124 if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true;
126 if (fabsf(degree) <= FLT_EPSILON) return true;
127 rTransform = new RenderTransform();
128 if (!rTransform) return false;
130 rTransform->degree = degree;
131 if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
136 bool scale(float factor)
139 if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true;
141 if (fabsf(factor) <= FLT_EPSILON) return true;
142 rTransform = new RenderTransform();
143 if (!rTransform) return false;
145 rTransform->scale = factor;
146 if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
151 bool translate(float x, float y)
154 if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true;
156 if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true;
157 rTransform = new RenderTransform();
158 if (!rTransform) return false;
162 if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform;
167 bool transform(const Matrix& m)
170 rTransform = new RenderTransform();
171 if (!rTransform) return false;
173 rTransform->override(m);
174 flag |= RenderUpdateFlag::Transform;
179 bool bounds(float* x, float* y, float* w, float* h) const
181 return smethod->bounds(x, y, w, h);
184 RenderRegion bounds(RenderMethod& renderer) const
186 return smethod->bounds(renderer);
189 bool dispose(RenderMethod& renderer)
191 if (cmpTarget) cmpTarget->pImpl->dispose(renderer);
192 return smethod->dispose(renderer);
195 void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
197 if (flag & RenderUpdateFlag::Transform) {
198 if (!rTransform) return nullptr;
199 if (!rTransform->update()) {
201 rTransform = nullptr;
205 /* 1. Composition Pre Processing */
206 void *cmpData = nullptr;
207 RenderRegion viewport;
208 bool cmpFastTrack = false;
211 /* If transform has no rotation factors && ClipPath is a simple rectangle,
212 we can avoid regular ClipPath sequence but use viewport for performance */
213 if (cmpMethod == CompositeMethod::ClipPath) {
214 RenderRegion viewport2;
215 if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, viewport2))) {
216 viewport = renderer.viewport();
217 viewport2.merge(viewport);
218 renderer.viewport(viewport2);
223 cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag);
224 if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
229 void *edata = nullptr;
230 auto newFlag = static_cast<RenderUpdateFlag>(pFlag | flag);
231 flag = RenderUpdateFlag::None;
232 opacity = (opacity * this->opacity) / 255;
234 if (rTransform && pTransform) {
235 RenderTransform outTransform(pTransform, rTransform);
236 edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
238 auto outTransform = pTransform ? pTransform : rTransform;
239 edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
242 /* 3. Composition Post Processing */
243 if (cmpFastTrack) renderer.viewport(viewport);
244 else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop();
249 bool render(RenderMethod& renderer)
251 Compositor* cmp = nullptr;
253 /* Note: only ClipPath is processed in update() step.
254 Create a composition image. */
255 if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) {
256 auto region = cmpTarget->pImpl->bounds(renderer);
257 if (region.w == 0 || region.h == 0) return false;
258 cmp = renderer.target(region);
259 renderer.beginComposite(cmp, CompositeMethod::None, 255);
260 cmpTarget->pImpl->render(renderer);
263 if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity);
265 auto ret = smethod->render(renderer);
267 if (cmp) renderer.endComposite(cmp);
274 auto ret = smethod->duplicate();
275 if (!ret) return nullptr;
277 //duplicate Transform
279 ret->pImpl->rTransform = new RenderTransform();
280 if (ret->pImpl->rTransform) {
281 *ret->pImpl->rTransform = *rTransform;
282 ret->pImpl->flag |= RenderUpdateFlag::Transform;
286 ret->pImpl->opacity = opacity;
288 if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate();
290 ret->pImpl->cmpMethod = cmpMethod;
295 bool composite(Paint* target, CompositeMethod method)
297 if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false;
298 if (cmpTarget) delete(cmpTarget);
307 struct PaintMethod : StrategyMethod
311 PaintMethod(T* _inst) : inst(_inst) {}
314 bool bounds(float* x, float* y, float* w, float* h) const override
316 return inst->bounds(x, y, w, h);
319 RenderRegion bounds(RenderMethod& renderer) const override
321 return inst->bounds(renderer);
324 bool dispose(RenderMethod& renderer) override
326 return inst->dispose(renderer);
329 void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag) override
331 return inst->update(renderer, transform, opacity, clips, flag);
334 bool render(RenderMethod& renderer) override
336 return inst->render(renderer);
339 Paint* duplicate() override
341 return inst->duplicate();
346 #endif //_TVG_PAINT_H_