2fb74311bf27892e60b40afb0cc9c438ad4eccc7
[platform/core/graphics/tizenvg.git] / src / wasm / thorvgwasm.cpp
1 /*
2  * Copyright (c) 2020 - 2022 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
23 #include <thorvg.h>
24 #include "tvgIteratorAccessor.h"
25
26 #include <emscripten/bind.h>
27
28 using namespace emscripten;
29 using namespace std;
30 using namespace tvg;
31
32 class __attribute__((visibility("default"))) ThorvgWasm : public IteratorAccessor
33 {
34 public:
35     static unique_ptr<ThorvgWasm> create()
36     {
37         return unique_ptr<ThorvgWasm>(new ThorvgWasm());
38     }
39
40     string getError()
41     {
42         return mErrorMsg;
43     }
44
45     bool load(string data, string mimetype, int width, int height)
46     {
47         mErrorMsg = "None";
48
49         if (!mSwCanvas) {
50              mErrorMsg = "Canvas is NULL";
51              return false;
52         }
53
54         if (data.empty()) {
55             mErrorMsg = "Data is empty";
56             return false;
57         }
58
59         mPicture = Picture::gen().release();
60         if (!mPicture) {
61             mErrorMsg = "Picture get failed";
62             return false;
63         }
64
65         mSwCanvas->clear();
66
67         if (mPicture->load(data.c_str(), data.size(), mimetype, false) != Result::Success) {
68             /* mPicture is not handled as unique_ptr yet, so delete here */
69             delete(mPicture);
70             mPicture = nullptr;
71
72             mErrorMsg = "Load failed";
73             return false;
74         }
75
76         mPicture->size(&mOriginalSize[0], &mOriginalSize[1]);
77
78         /* need to reset size to calculate scale in Picture.size internally
79            before calling updateSize */
80         mWidth = 0;
81         mHeight = 0;
82
83         updateSize(width, height);
84
85         if (mSwCanvas->push(unique_ptr<Picture>(mPicture)) != Result::Success) {
86             mErrorMsg = "Push failed";
87             return false;
88         }
89
90         return true;
91     }
92
93     bool update(int width, int height, bool force)
94     {
95         mErrorMsg = "None";
96
97         if (!mSwCanvas || !mPicture) {
98             mErrorMsg = "Invalid Conditions";
99             return false;
100         }
101
102         if (!force && mWidth == width && mHeight == height) {
103             return true;
104         }
105
106         updateSize(width, height);
107
108         if (mSwCanvas->update(mPicture) != Result::Success) {
109             mErrorMsg = "Update failed";
110             return false;
111         }
112         return true;
113     }
114
115     val render()
116     {
117         mErrorMsg = "None";
118
119         if (!mSwCanvas) {
120             mErrorMsg = "Canvas is NULL";
121             return val(typed_memory_view<uint8_t>(0, nullptr));
122         }
123
124         if (mSwCanvas->draw() != Result::Success) {
125             mErrorMsg = "Draw failed";
126             return val(typed_memory_view<uint8_t>(0, nullptr));
127         }
128
129         mSwCanvas->sync();
130
131         //Change ARGB into ABGR and unpremultiply
132         unpremultiplyBuffer();
133
134         return val(typed_memory_view(mWidth * mHeight * 4, mBuffer.get()));
135     }
136
137     val originalSize()
138     {
139         return val(typed_memory_view(2, mOriginalSize));
140     }
141
142     bool saveTvg(bool compress)
143     {
144         mErrorMsg = "None";
145
146         auto saver = tvg::Saver::gen();
147         auto duplicate = unique_ptr<tvg::Picture>(static_cast<tvg::Picture*>(mPicture->duplicate()));
148         if (!saver || !duplicate) {
149             mErrorMsg = "Saving initialization failed";
150             return false;
151         }
152         if (saver->save(move(duplicate), "file.tvg", compress) != tvg::Result::Success) {
153             mErrorMsg = "Tvg saving failed";
154             return false;
155         }
156         saver->sync();
157
158         return true;
159     }
160
161     val layers()
162     {
163         //returns an array of a structure Layer: [id] [depth] [type] [composite]
164         mLayers.reset();
165         sublayers(&mLayers, mPicture, 0);
166
167         return val(typed_memory_view(mLayers.count * sizeof(Layer) / sizeof(uint32_t), (uint32_t *)(mLayers.data)));
168     }
169
170     bool setOpacity(uint32_t paintId, uint8_t opacity)
171     {
172         const Paint* paint = findPaintById(mPicture, paintId, nullptr);
173         if (!paint) return false;
174         const_cast<Paint*>(paint)->opacity(opacity);
175         return true;
176     }
177
178     val bounds(uint32_t paintId)
179     {
180         Array<const Paint *> parents;
181         const Paint* paint = findPaintById(mPicture, paintId, &parents);
182         if (!paint) return val(typed_memory_view<float>(0, nullptr));
183         paint->bounds(&mBounds[0], &mBounds[1], &mBounds[2], &mBounds[3]);
184         
185         float points[8] = { //clockwise points
186             mBounds[0], mBounds[1], //(x1, y1)
187             mBounds[0] + mBounds[2], mBounds[1], //(x2, y1)
188             mBounds[0] + mBounds[2], mBounds[1] + mBounds[3], //(x2, y2)
189             mBounds[0], mBounds[1] + mBounds[3], //(x1, y2)
190         };
191         
192         for (auto paint = parents.data; paint < (parents.data + parents.count); ++paint) {
193             auto m = const_cast<Paint*>(*paint)->transform();
194             for (int i = 0; i<8; i += 2) {
195                 float x = points[i] * m.e11 + points[i+1] * m.e12 + m.e13;
196                 points[i+1] = points[i] * m.e21 + points[i+1] * m.e22 + m.e23;
197                 points[i] = x;
198             }
199         }
200         
201         mBounds[0] = points[0];//x(p1)
202         mBounds[1] = points[3];//y(p2)
203         mBounds[2] = points[4] - mBounds[0];//x(p3)
204         mBounds[3] = points[7] - mBounds[1];//y(p4)
205
206         return val(typed_memory_view(4, mBounds));
207     }
208
209 private:
210     explicit ThorvgWasm()
211     {
212         mErrorMsg = "None";
213
214         Initializer::init(CanvasEngine::Sw, 0);
215         mSwCanvas = SwCanvas::gen();
216         if (!mSwCanvas) {
217             mErrorMsg = "Canvas get failed";
218             return;
219         }
220     }
221
222     void unpremultiplyBuffer() {
223         for (uint32_t y = 0; y < mHeight; y++) {
224             auto buffer = (uint32_t *) mBuffer.get() + mWidth * y;
225             for (uint32_t x = 0; x < mWidth; ++x) {
226                 uint8_t a = buffer[x] >> 24;
227                 if (a == 255) {
228                     uint8_t b = (buffer[x] & 0xff);
229                     uint8_t r = ((buffer[x] >> 16) & 0xff);
230                     buffer[x] = (buffer[x] & 0xff00ff00) | (b << 16) | (r);
231
232                 } else if (a == 0) {
233                     buffer[x] = 0x00ffffff;
234
235                 } else {
236                     uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
237                     uint16_t g = ((buffer[x]) & 0xff00) / a;
238                     uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
239                     if (b > 0xff) b = 0xff;
240                     if (g > 0xff) g = 0xff;
241                     if (r > 0xff) r = 0xff;
242                     buffer[x] = (a << 24) | (b << 16) | (g << 8) | (r);
243                 }
244             }
245         }
246     }
247
248     void updateSize(int width, int height)
249     {
250         if (!mSwCanvas) return;
251         if (mWidth == width && mHeight == height) return;
252
253         mWidth = width;
254         mHeight = height;
255         mBuffer = make_unique<uint8_t[]>(mWidth * mHeight * 4);
256         mSwCanvas->target((uint32_t *)mBuffer.get(), mWidth, mWidth, mHeight, SwCanvas::ARGB8888);
257
258         if (mPicture) mPicture->size(width, height);
259     }
260
261     struct Layer
262     {
263         uint32_t paint; //cast of a paint pointer
264         uint32_t depth;
265         uint32_t type;
266         uint32_t composite;
267         uint32_t opacity;
268     };
269     void sublayers(Array<Layer>* layers, const Paint* paint, uint32_t depth)
270     {
271         //paint
272         if (paint->identifier() != Shape::identifier()) {
273             auto it = this->iterator(paint);
274             if (it->count() > 0) {
275                 layers->reserve(layers->count + it->count());
276                 it->begin();
277                 while (auto child = it->next()) {
278                     uint32_t type = child->identifier();
279                     uint32_t opacity = child->opacity();
280                     layers->push({.paint = reinterpret_cast<uint32_t>(child), .depth = depth + 1, .type = type, .composite = static_cast<uint32_t>(CompositeMethod::None), .opacity = opacity});
281                     sublayers(layers, child, depth + 1);
282                 }
283             }
284         }
285         //composite
286         const Paint* compositeTarget = nullptr;
287         CompositeMethod composite = paint->composite(&compositeTarget);
288         if (compositeTarget && composite != CompositeMethod::None) {
289             uint32_t type = compositeTarget->identifier();
290             uint32_t opacity = compositeTarget->opacity();
291             layers->push({.paint = reinterpret_cast<uint32_t>(compositeTarget), .depth = depth, .type = type, .composite = static_cast<uint32_t>(composite), .opacity = opacity});
292             sublayers(layers, compositeTarget, depth);
293         }
294     }
295
296     const Paint* findPaintById(const Paint* parent, uint32_t paintId, Array<const Paint *>* parents) {
297         //validate paintId is correct and exists in the picture
298         if (reinterpret_cast<uint32_t>(parent) == paintId) {
299             if (parents) parents->push(parent);
300             return parent;
301         }
302         //paint
303         if (parent->identifier() != Shape::identifier()) {
304             auto it = this->iterator(parent);
305             if (it->count() > 0) {
306                 it->begin();
307                 while (auto child = it->next()) {
308                     if (auto paint = findPaintById(child, paintId, parents)) {
309                         if (parents) parents->push(parent);
310                         return paint;
311                     }
312                 }
313             }
314         }
315         //composite
316         const Paint* compositeTarget = nullptr;
317         CompositeMethod composite = parent->composite(&compositeTarget);
318         if (compositeTarget && composite != CompositeMethod::None) {
319             if (auto paint = findPaintById(compositeTarget, paintId, parents)) {
320                 if (parents) parents->push(parent);
321                 return paint;
322             }
323         }
324         return nullptr;
325     }
326
327 private:
328     string                 mErrorMsg;
329     unique_ptr< SwCanvas > mSwCanvas = nullptr;
330     Picture*               mPicture = nullptr;
331     unique_ptr<uint8_t[]>  mBuffer = nullptr;
332
333     uint32_t               mWidth{0};
334     uint32_t               mHeight{0};
335
336     Array<Layer>           mLayers;
337     float                  mBounds[4];
338     float                  mOriginalSize[2];
339 };
340
341 //Binding code
342 EMSCRIPTEN_BINDINGS(thorvg_bindings) {
343   class_<ThorvgWasm>("ThorvgWasm")
344     .constructor(&ThorvgWasm::create)
345     .function("getError", &ThorvgWasm::getError, allow_raw_pointers())
346     .function("load", &ThorvgWasm::load)
347     .function("update", &ThorvgWasm::update)
348     .function("render", &ThorvgWasm::render)
349     .function("originalSize", &ThorvgWasm::originalSize)
350
351     .function("saveTvg", &ThorvgWasm::saveTvg)
352
353     .function("layers", &ThorvgWasm::layers)
354     .function("bounds", &ThorvgWasm::bounds)
355     .function("setOpacity", &ThorvgWasm::setOpacity);
356 }