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 #ifndef _TVG_PICTURE_H_
27 #define _TVG_PICTURE_H_
28 
29 #include <string>
30 #include "tvgPaint.h"
31 #include "tvgLoader.h"
32 
33 
34 struct PictureIterator : Iterator
35 {
36     Paint* paint = nullptr;
37     Paint* ptr = nullptr;
38 
PictureIteratorPictureIterator39     PictureIterator(Paint* p) : paint(p) {}
40 
nextPictureIterator41     const Paint* next() override
42     {
43         if (!ptr) ptr = paint;
44         else ptr = nullptr;
45         return ptr;
46     }
47 
countPictureIterator48     uint32_t count() override
49     {
50         if (paint) return 1;
51         else return 0;
52     }
53 
beginPictureIterator54     void begin() override
55     {
56         ptr = nullptr;
57     }
58 };
59 
60 
61 struct Picture::Impl
62 {
63     ImageLoader* loader = nullptr;
64 
65     Paint* paint = nullptr;           //vector picture uses
66     RenderSurface* surface = nullptr; //bitmap picture uses
67     RenderData rd = nullptr;          //engine data
68     float w = 0, h = 0;
69     Picture* picture = nullptr;
70     bool resizing = false;
71     bool needComp = false;            //need composition
72 
73     bool needComposition(uint8_t opacity);
74     bool render(RenderMethod* renderer);
75     bool size(float w, float h);
76     RenderRegion bounds(RenderMethod* renderer);
77     Result load(ImageLoader* ploader);
78 
ImplImpl79     Impl(Picture* p) : picture(p)
80     {
81     }
82 
~ImplImpl83     ~Impl()
84     {
85         LoaderMgr::retrieve(loader);
86         if (surface) {
87             if (auto renderer = PP(picture)->renderer) {
88                 renderer->dispose(rd);
89             }
90         }
91         delete(paint);
92     }
93 
updateImpl94     RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)
95     {
96         auto flag = static_cast<RenderUpdateFlag>(pFlag | load());
97 
98         if (surface) {
99             if (flag == RenderUpdateFlag::None) return rd;
100 
101             //Overriding Transformation by the desired image size
102             auto sx = w / loader->w;
103             auto sy = h / loader->h;
104             auto scale = sx < sy ? sx : sy;
105             auto m = transform * Matrix{scale, 0, 0, 0, scale, 0, 0, 0, 1};
106 
107             rd = renderer->prepare(surface, rd, m, clips, opacity, flag);
108         } else if (paint) {
109             if (resizing) {
110                 loader->resize(paint, w, h);
111                 resizing = false;
112             }
113             needComp = needComposition(opacity) ? true : false;
114             rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
115         }
116         return rd;
117     }
118 
boundsImpl119     bool bounds(float* x, float* y, float* w, float* h, bool stroking)
120     {
121         if (x) *x = 0;
122         if (y) *y = 0;
123         if (w) *w = this->w;
124         if (h) *h = this->h;
125         return true;
126     }
127 
loadImpl128     Result load(const string& path)
129     {
130         if (paint || surface) return Result::InsufficientCondition;
131 
132         bool invalid;  //Invalid Path
133         auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(path, &invalid));
134         if (!loader) {
135             if (invalid) return Result::InvalidArguments;
136             return Result::NonSupport;
137         }
138         return load(loader);
139     }
140 
loadImpl141     Result load(const char* data, uint32_t size, const string& mimeType, bool copy)
142     {
143         if (paint || surface) return Result::InsufficientCondition;
144         auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, size, mimeType, copy));
145         if (!loader) return Result::NonSupport;
146         return load(loader);
147     }
148 
loadImpl149     Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy)
150     {
151         if (paint || surface) return Result::InsufficientCondition;
152 
153         auto loader = static_cast<ImageLoader*>(LoaderMgr::loader(data, w, h, copy));
154         if (!loader) return Result::FailedAllocation;
155 
156         return load(loader);
157     }
158 
duplicateImpl159     Paint* duplicate(Paint* ret)
160     {
161         if (ret) TVGERR("RENDERER", "TODO: duplicate()");
162 
163         load();
164 
165         auto picture = Picture::gen().release();
166         auto dup = picture->pImpl;
167 
168         if (paint) dup->paint = paint->duplicate();
169 
170         if (loader) {
171             dup->loader = loader;
172             ++dup->loader->sharing;
173             PP(picture)->renderFlag |= RenderUpdateFlag::Image;
174         }
175 
176         dup->surface = surface;
177         dup->w = w;
178         dup->h = h;
179         dup->resizing = resizing;
180 
181         return picture;
182     }
183 
iteratorImpl184     Iterator* iterator()
185     {
186         load();
187         return new PictureIterator(paint);
188     }
189 
dataImpl190     uint32_t* data(uint32_t* w, uint32_t* h)
191     {
192         //Try it, If not loaded yet.
193         load();
194 
195         if (loader) {
196             if (w) *w = static_cast<uint32_t>(loader->w);
197             if (h) *h = static_cast<uint32_t>(loader->h);
198         } else {
199             if (w) *w = 0;
200             if (h) *h = 0;
201         }
202         if (surface) return surface->buf32;
203         else return nullptr;
204     }
205 
206     RenderUpdateFlag load();
207 };
208 
209 #endif //_TVG_PICTURE_H_
210 
211 #endif /* LV_USE_THORVG_INTERNAL */
212 
213