95d629d1f6ea238985b4576e78f69aa817c22b5a
[platform/core/graphics/tizenvg.git] / src / loaders / tvg / tvgTvgLoader.cpp
1 /*
2  * Copyright (c) 2021 - 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 #include <memory.h>
23 #include <fstream>
24 #include "tvgLoader.h"
25 #include "tvgTvgLoader.h"
26 #include "tvgLzw.h"
27
28
29 /************************************************************************/
30 /* Internal Class Implementation                                        */
31 /************************************************************************/
32
33
34 void TvgLoader::clear()
35 {
36     if (copy) free((char*)data);
37     ptr = data = nullptr;
38     size = 0;
39     copy = false;
40
41     if (interpreter) {
42         delete(interpreter);
43         interpreter = nullptr;
44     }
45 }
46
47
48 /* WARNING: Header format shall not change! */
49 bool TvgLoader::readHeader()
50 {
51     if (!ptr) return false;
52
53     //Make sure the size is large enough to hold the header
54     if (size < TVG_HEADER_SIZE) return false;
55
56     //1. Signature
57     if (memcmp(ptr, TVG_HEADER_SIGNATURE, TVG_HEADER_SIGNATURE_LENGTH)) return false;
58     ptr += TVG_HEADER_SIGNATURE_LENGTH;
59
60     //2. Version
61     char version[TVG_HEADER_VERSION_LENGTH + 1];
62     memcpy(version, ptr, TVG_HEADER_VERSION_LENGTH);
63     version[TVG_HEADER_VERSION_LENGTH - 1] = '\0';
64     ptr += TVG_HEADER_VERSION_LENGTH;
65     this->version = atoi(version);
66     if (this->version > THORVG_VERSION_NUMBER()) {
67         TVGLOG("TVG", "This TVG file expects a higher version(%d) of ThorVG symbol(%d)", this->version, THORVG_VERSION_NUMBER());
68     }
69
70     //3. View Size
71     READ_FLOAT(&w, ptr);
72     ptr += SIZE(float);
73     READ_FLOAT(&h, ptr);
74     ptr += SIZE(float);
75
76     //4. Reserved
77     if (*ptr & TVG_HEAD_FLAG_COMPRESSED) compressed = true;
78     ptr += TVG_HEADER_RESERVED_LENGTH;
79
80     //5. Compressed Size if any
81     if (compressed) {
82         auto p = ptr;
83
84         //TVG_HEADER_UNCOMPRESSED_SIZE
85         memcpy(&uncompressedSize, p, sizeof(uint32_t));
86         p += SIZE(uint32_t);
87
88         //TVG_HEADER_COMPRESSED_SIZE
89         memcpy(&compressedSize, p, sizeof(uint32_t));
90         p += SIZE(uint32_t);
91
92         //TVG_HEADER_COMPRESSED_SIZE_BITS
93         memcpy(&compressedSizeBits, p, sizeof(uint32_t));
94     }
95
96     ptr += TVG_HEADER_COMPRESS_SIZE;
97
98     //Decide the proper Tvg Binary Interpreter based on the current file version
99     if (this->version >= 0) interpreter = new TvgBinInterpreter;
100
101     return true;
102 }
103
104
105 /************************************************************************/
106 /* External Class Implementation                                        */
107 /************************************************************************/
108
109 TvgLoader::~TvgLoader()
110 {
111     close();
112 }
113
114
115 bool TvgLoader::open(const string &path)
116 {
117     clear();
118
119     ifstream f;
120     f.open(path, ifstream::in | ifstream::binary | ifstream::ate);
121
122     if (!f.is_open()) return false;
123
124     size = f.tellg();
125     f.seekg(0, ifstream::beg);
126
127     copy = true;
128     data = (char*)malloc(size);
129     if (!data) {
130         clear();
131         f.close();
132         return false;
133     }
134
135     if (!f.read((char*)data, size))
136     {
137         clear();
138         f.close();
139         return false;
140     }
141
142     f.close();
143
144     ptr = data;
145
146     return readHeader();
147 }
148
149
150 bool TvgLoader::open(const char *data, uint32_t size, bool copy)
151 {
152     clear();
153
154     if (copy) {
155         this->data = (char*)malloc(size);
156         if (!this->data) return false;
157         memcpy((char*)this->data, data, size);
158     } else this->data = data;
159
160     this->ptr = this->data;
161     this->size = size;
162     this->copy = copy;
163
164     return readHeader();
165 }
166
167
168 bool TvgLoader::resize(Paint* paint, float w, float h)
169 {
170     if (!paint) return false;
171
172     auto sx = w / this->w;
173     auto sy = h / this->h;
174
175     //Scale
176     auto scale = sx < sy ? sx : sy;
177     paint->scale(scale);
178
179     //Align
180     float tx = 0, ty = 0;
181     auto sw = this->w * scale;
182     auto sh = this->h * scale;
183     if (sw > sh) ty -= (h - sh) * 0.5f;
184     else tx -= (w - sw) * 0.5f;
185     paint->translate(-tx, -ty);
186
187     return true;
188 }
189
190
191 bool TvgLoader::read()
192 {
193     if (!ptr || size == 0) return false;
194
195     TaskScheduler::request(this);
196
197     return true;
198 }
199
200
201 bool TvgLoader::close()
202 {
203     this->done();
204     clear();
205     return true;
206 }
207
208
209 void TvgLoader::run(unsigned tid)
210 {
211     if (root) root.reset();
212
213     auto data = const_cast<char*>(ptr);
214
215     if (compressed) {
216         data = (char*) lzwDecode((uint8_t*) data, compressedSize, compressedSizeBits, uncompressedSize);
217         root = interpreter->run(data, data + uncompressedSize);
218         free(data);
219     } else {
220         root = interpreter->run(data, this->data + size);
221     }
222
223     if (!root) clear();
224 }
225
226
227 unique_ptr<Paint> TvgLoader::paint()
228 {
229     this->done();
230     if (root) return move(root);
231     return nullptr;
232 }