1 /*
2  * Copyright (c) 2020 - 2024 the ThorVG project. 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 
23 #include "../../lv_conf_internal.h"
24 #if LV_USE_THORVG_INTERNAL
25 
26 #include "tvgPaint.h"
27 #include "tvgPicture.h"
28 
29 /************************************************************************/
30 /* Internal Class Implementation                                        */
31 /************************************************************************/
32 
load()33 RenderUpdateFlag Picture::Impl::load()
34 {
35     if (loader) {
36         if (paint) {
37             loader->sync();
38         } else {
39             paint = loader->paint();
40             if (paint) {
41                 if (w != loader->w || h != loader->h) {
42                     if (!resizing) {
43                         w = loader->w;
44                         h = loader->h;
45                     }
46                     loader->resize(paint, w, h);
47                     resizing = false;
48                 }
49                 return RenderUpdateFlag::None;
50             }
51         }
52         if (!surface) {
53             if ((surface = loader->bitmap())) {
54                 return RenderUpdateFlag::Image;
55             }
56         }
57     }
58     return RenderUpdateFlag::None;
59 }
60 
61 
needComposition(uint8_t opacity)62 bool Picture::Impl::needComposition(uint8_t opacity)
63 {
64     //In this case, paint(scene) would try composition itself.
65     if (opacity < 255) return false;
66 
67     //Composition test
68     const Paint* target;
69     auto method = picture->composite(&target);
70     if (!target || method == tvg::CompositeMethod::ClipPath) return false;
71     if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false;
72 
73     return true;
74 }
75 
76 
render(RenderMethod * renderer)77 bool Picture::Impl::render(RenderMethod* renderer)
78 {
79     bool ret = false;
80     renderer->blend(PP(picture)->blendMethod);
81 
82     if (surface) return renderer->renderImage(rd);
83     else if (paint) {
84         RenderCompositor* cmp = nullptr;
85         if (needComp) {
86             cmp = renderer->target(bounds(renderer), renderer->colorSpace());
87             renderer->beginComposite(cmp, CompositeMethod::None, 255);
88         }
89         ret = paint->pImpl->render(renderer);
90         if (cmp) renderer->endComposite(cmp);
91     }
92     return ret;
93 }
94 
95 
size(float w,float h)96 bool Picture::Impl::size(float w, float h)
97 {
98     this->w = w;
99     this->h = h;
100     resizing = true;
101     return true;
102 }
103 
104 
bounds(RenderMethod * renderer)105 RenderRegion Picture::Impl::bounds(RenderMethod* renderer)
106 {
107     if (rd) return renderer->region(rd);
108     if (paint) return paint->pImpl->bounds(renderer);
109     return {0, 0, 0, 0};
110 }
111 
112 
load(ImageLoader * loader)113 Result Picture::Impl::load(ImageLoader* loader)
114 {
115     //Same resource has been loaded.
116     if (this->loader == loader) {
117         this->loader->sharing--;  //make it sure the reference counting.
118         return Result::Success;
119     } else if (this->loader) {
120         LoaderMgr::retrieve(this->loader);
121     }
122 
123     this->loader = loader;
124 
125     if (!loader->read()) return Result::Unknown;
126 
127     this->w = loader->w;
128     this->h = loader->h;
129 
130     return Result::Success;
131 }
132 
133 
134 
135 /************************************************************************/
136 /* External Class Implementation                                        */
137 /************************************************************************/
138 
Picture()139 Picture::Picture() : pImpl(new Impl(this))
140 {
141 }
142 
143 
~Picture()144 Picture::~Picture()
145 {
146     delete(pImpl);
147 }
148 
149 
gen()150 unique_ptr<Picture> Picture::gen() noexcept
151 {
152     return unique_ptr<Picture>(new Picture);
153 }
154 
155 
identifier()156 TVG_DEPRECATED uint32_t Picture::identifier() noexcept
157 {
158     return (uint32_t) Type::Picture;
159 }
160 
161 
type() const162 Type Picture::type() const noexcept
163 {
164     return Type::Picture;
165 }
166 
167 
load(const std::string & path)168 Result Picture::load(const std::string& path) noexcept
169 {
170     if (path.empty()) return Result::InvalidArguments;
171 
172     return pImpl->load(path);
173 }
174 
175 
load(const char * data,uint32_t size,const string & mimeType,bool copy)176 Result Picture::load(const char* data, uint32_t size, const string& mimeType, bool copy) noexcept
177 {
178     if (!data || size <= 0) return Result::InvalidArguments;
179 
180     return pImpl->load(data, size, mimeType, copy);
181 }
182 
183 
load(const char * data,uint32_t size,bool copy)184 TVG_DEPRECATED Result Picture::load(const char* data, uint32_t size, bool copy) noexcept
185 {
186     return load(data, size, "", copy);
187 }
188 
189 
load(uint32_t * data,uint32_t w,uint32_t h,bool copy)190 Result Picture::load(uint32_t* data, uint32_t w, uint32_t h, bool copy) noexcept
191 {
192     if (!data || w <= 0 || h <= 0) return Result::InvalidArguments;
193 
194     return pImpl->load(data, w, h, copy);
195 }
196 
197 
size(float w,float h)198 Result Picture::size(float w, float h) noexcept
199 {
200     if (pImpl->size(w, h)) return Result::Success;
201     return Result::InsufficientCondition;
202 }
203 
204 
size(float * w,float * h) const205 Result Picture::size(float* w, float* h) const noexcept
206 {
207     if (!pImpl->loader) return Result::InsufficientCondition;
208     if (w) *w = pImpl->w;
209     if (h) *h = pImpl->h;
210     return Result::Success;
211 }
212 
213 
paint(uint32_t id)214 const Paint* Picture::paint(uint32_t id) noexcept
215 {
216     struct Value
217     {
218         uint32_t id;
219         const Paint* ret;
220     } value = {id, nullptr};
221 
222     auto cb = [](const tvg::Paint* paint, void* data) -> bool
223     {
224         auto p = static_cast<Value*>(data);
225         if (p->id == paint->id) {
226             p->ret = paint;
227             return false;
228         }
229         return true;
230     };
231 
232     tvg::Accessor::gen()->set(this, cb, &value);
233     return value.ret;
234 }
235 
236 #endif /* LV_USE_THORVG_INTERNAL */
237 
238