diff options
author | Elliott Hughes | 2015-04-10 15:12:05 -0500 |
---|---|---|
committer | Elliott Hughes | 2015-04-10 15:42:55 -0500 |
commit | 07cfb8fe799901948afd6af05ef4674173713bcb (patch) | |
tree | dbb3c6ea45cb910397cec50054460d46c99b454f /minui/resources.cpp | |
parent | 5d1630a926a02ca13a66eb1e385eabba16b04cfc (diff) | |
download | platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.tar.gz platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.tar.xz platform-bootable-recovery-07cfb8fe799901948afd6af05ef4674173713bcb.zip |
Switch minui over to C++.
Change-Id: I59e08a304ae514a3fdb6fab58721f11670bc1b01
Diffstat (limited to 'minui/resources.cpp')
-rw-r--r-- | minui/resources.cpp | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/minui/resources.cpp b/minui/resources.cpp new file mode 100644 index 00000000..fa413b60 --- /dev/null +++ b/minui/resources.cpp | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <unistd.h> | ||
20 | |||
21 | #include <fcntl.h> | ||
22 | #include <stdio.h> | ||
23 | |||
24 | #include <sys/ioctl.h> | ||
25 | #include <sys/mman.h> | ||
26 | #include <sys/types.h> | ||
27 | |||
28 | #include <linux/fb.h> | ||
29 | #include <linux/kd.h> | ||
30 | |||
31 | #include <png.h> | ||
32 | |||
33 | #include "minui.h" | ||
34 | |||
35 | extern char* locale; | ||
36 | |||
37 | #define SURFACE_DATA_ALIGNMENT 8 | ||
38 | |||
39 | static gr_surface malloc_surface(size_t data_size) { | ||
40 | size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT; | ||
41 | unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size)); | ||
42 | if (temp == NULL) return NULL; | ||
43 | gr_surface surface = (gr_surface) temp; | ||
44 | surface->data = temp + sizeof(GRSurface) + | ||
45 | (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); | ||
46 | return surface; | ||
47 | } | ||
48 | |||
49 | static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, | ||
50 | png_uint_32* width, png_uint_32* height, png_byte* channels) { | ||
51 | char resPath[256]; | ||
52 | unsigned char header[8]; | ||
53 | int result = 0; | ||
54 | int color_type, bit_depth; | ||
55 | size_t bytesRead; | ||
56 | |||
57 | snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); | ||
58 | resPath[sizeof(resPath)-1] = '\0'; | ||
59 | FILE* fp = fopen(resPath, "rb"); | ||
60 | if (fp == NULL) { | ||
61 | result = -1; | ||
62 | goto exit; | ||
63 | } | ||
64 | |||
65 | bytesRead = fread(header, 1, sizeof(header), fp); | ||
66 | if (bytesRead != sizeof(header)) { | ||
67 | result = -2; | ||
68 | goto exit; | ||
69 | } | ||
70 | |||
71 | if (png_sig_cmp(header, 0, sizeof(header))) { | ||
72 | result = -3; | ||
73 | goto exit; | ||
74 | } | ||
75 | |||
76 | *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | ||
77 | if (!*png_ptr) { | ||
78 | result = -4; | ||
79 | goto exit; | ||
80 | } | ||
81 | |||
82 | *info_ptr = png_create_info_struct(*png_ptr); | ||
83 | if (!*info_ptr) { | ||
84 | result = -5; | ||
85 | goto exit; | ||
86 | } | ||
87 | |||
88 | if (setjmp(png_jmpbuf(*png_ptr))) { | ||
89 | result = -6; | ||
90 | goto exit; | ||
91 | } | ||
92 | |||
93 | png_init_io(*png_ptr, fp); | ||
94 | png_set_sig_bytes(*png_ptr, sizeof(header)); | ||
95 | png_read_info(*png_ptr, *info_ptr); | ||
96 | |||
97 | png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, | ||
98 | &color_type, NULL, NULL, NULL); | ||
99 | |||
100 | *channels = png_get_channels(*png_ptr, *info_ptr); | ||
101 | |||
102 | if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { | ||
103 | // 8-bit RGB images: great, nothing to do. | ||
104 | } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { | ||
105 | // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. | ||
106 | png_set_expand_gray_1_2_4_to_8(*png_ptr); | ||
107 | } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { | ||
108 | // paletted images: expand to 8-bit RGB. Note that we DON'T | ||
109 | // currently expand the tRNS chunk (if any) to an alpha | ||
110 | // channel, because minui doesn't support alpha channels in | ||
111 | // general. | ||
112 | png_set_palette_to_rgb(*png_ptr); | ||
113 | *channels = 3; | ||
114 | } else { | ||
115 | fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", | ||
116 | bit_depth, *channels, color_type); | ||
117 | result = -7; | ||
118 | goto exit; | ||
119 | } | ||
120 | |||
121 | return result; | ||
122 | |||
123 | exit: | ||
124 | if (result < 0) { | ||
125 | png_destroy_read_struct(png_ptr, info_ptr, NULL); | ||
126 | } | ||
127 | if (fp != NULL) { | ||
128 | fclose(fp); | ||
129 | } | ||
130 | |||
131 | return result; | ||
132 | } | ||
133 | |||
134 | // "display" surfaces are transformed into the framebuffer's required | ||
135 | // pixel format (currently only RGBX is supported) at load time, so | ||
136 | // gr_blit() can be nothing more than a memcpy() for each row. The | ||
137 | // next two functions are the only ones that know anything about the | ||
138 | // framebuffer pixel format; they need to be modified if the | ||
139 | // framebuffer format changes (but nothing else should). | ||
140 | |||
141 | // Allocate and return a gr_surface sufficient for storing an image of | ||
142 | // the indicated size in the framebuffer pixel format. | ||
143 | static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { | ||
144 | gr_surface surface; | ||
145 | |||
146 | surface = malloc_surface(width * height * 4); | ||
147 | if (surface == NULL) return NULL; | ||
148 | |||
149 | surface->width = width; | ||
150 | surface->height = height; | ||
151 | surface->row_bytes = width * 4; | ||
152 | surface->pixel_bytes = 4; | ||
153 | |||
154 | return surface; | ||
155 | } | ||
156 | |||
157 | // Copy 'input_row' to 'output_row', transforming it to the | ||
158 | // framebuffer pixel format. The input format depends on the value of | ||
159 | // 'channels': | ||
160 | // | ||
161 | // 1 - input is 8-bit grayscale | ||
162 | // 3 - input is 24-bit RGB | ||
163 | // 4 - input is 32-bit RGBA/RGBX | ||
164 | // | ||
165 | // 'width' is the number of pixels in the row. | ||
166 | static void transform_rgb_to_draw(unsigned char* input_row, | ||
167 | unsigned char* output_row, | ||
168 | int channels, int width) { | ||
169 | int x; | ||
170 | unsigned char* ip = input_row; | ||
171 | unsigned char* op = output_row; | ||
172 | |||
173 | switch (channels) { | ||
174 | case 1: | ||
175 | // expand gray level to RGBX | ||
176 | for (x = 0; x < width; ++x) { | ||
177 | *op++ = *ip; | ||
178 | *op++ = *ip; | ||
179 | *op++ = *ip; | ||
180 | *op++ = 0xff; | ||
181 | ip++; | ||
182 | } | ||
183 | break; | ||
184 | |||
185 | case 3: | ||
186 | // expand RGBA to RGBX | ||
187 | for (x = 0; x < width; ++x) { | ||
188 | *op++ = *ip++; | ||
189 | *op++ = *ip++; | ||
190 | *op++ = *ip++; | ||
191 | *op++ = 0xff; | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case 4: | ||
196 | // copy RGBA to RGBX | ||
197 | memcpy(output_row, input_row, width*4); | ||
198 | break; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | int res_create_display_surface(const char* name, gr_surface* pSurface) { | ||
203 | gr_surface surface = NULL; | ||
204 | int result = 0; | ||
205 | png_structp png_ptr = NULL; | ||
206 | png_infop info_ptr = NULL; | ||
207 | png_uint_32 width, height; | ||
208 | png_byte channels; | ||
209 | unsigned char* p_row; | ||
210 | unsigned int y; | ||
211 | |||
212 | *pSurface = NULL; | ||
213 | |||
214 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); | ||
215 | if (result < 0) return result; | ||
216 | |||
217 | surface = init_display_surface(width, height); | ||
218 | if (surface == NULL) { | ||
219 | result = -8; | ||
220 | goto exit; | ||
221 | } | ||
222 | |||
223 | #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) | ||
224 | png_set_bgr(png_ptr); | ||
225 | #endif | ||
226 | |||
227 | p_row = reinterpret_cast<unsigned char*>(malloc(width * 4)); | ||
228 | for (y = 0; y < height; ++y) { | ||
229 | png_read_row(png_ptr, p_row, NULL); | ||
230 | transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width); | ||
231 | } | ||
232 | free(p_row); | ||
233 | |||
234 | *pSurface = surface; | ||
235 | |||
236 | exit: | ||
237 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||
238 | if (result < 0 && surface != NULL) free(surface); | ||
239 | return result; | ||
240 | } | ||
241 | |||
242 | int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { | ||
243 | gr_surface* surface = NULL; | ||
244 | int result = 0; | ||
245 | png_structp png_ptr = NULL; | ||
246 | png_infop info_ptr = NULL; | ||
247 | png_uint_32 width, height; | ||
248 | png_byte channels; | ||
249 | int i; | ||
250 | png_textp text; | ||
251 | int num_text; | ||
252 | unsigned char* p_row; | ||
253 | unsigned int y; | ||
254 | |||
255 | *pSurface = NULL; | ||
256 | *frames = -1; | ||
257 | |||
258 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); | ||
259 | if (result < 0) return result; | ||
260 | |||
261 | *frames = 1; | ||
262 | if (png_get_text(png_ptr, info_ptr, &text, &num_text)) { | ||
263 | for (i = 0; i < num_text; ++i) { | ||
264 | if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) { | ||
265 | *frames = atoi(text[i].text); | ||
266 | break; | ||
267 | } | ||
268 | } | ||
269 | printf(" found frames = %d\n", *frames); | ||
270 | } | ||
271 | |||
272 | if (height % *frames != 0) { | ||
273 | printf("bad height (%d) for frame count (%d)\n", height, *frames); | ||
274 | result = -9; | ||
275 | goto exit; | ||
276 | } | ||
277 | |||
278 | surface = reinterpret_cast<gr_surface*>(malloc(*frames * sizeof(gr_surface))); | ||
279 | if (surface == NULL) { | ||
280 | result = -8; | ||
281 | goto exit; | ||
282 | } | ||
283 | for (i = 0; i < *frames; ++i) { | ||
284 | surface[i] = init_display_surface(width, height / *frames); | ||
285 | if (surface[i] == NULL) { | ||
286 | result = -8; | ||
287 | goto exit; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) | ||
292 | png_set_bgr(png_ptr); | ||
293 | #endif | ||
294 | |||
295 | p_row = reinterpret_cast<unsigned char*>(malloc(width * 4)); | ||
296 | for (y = 0; y < height; ++y) { | ||
297 | png_read_row(png_ptr, p_row, NULL); | ||
298 | int frame = y % *frames; | ||
299 | unsigned char* out_row = surface[frame]->data + | ||
300 | (y / *frames) * surface[frame]->row_bytes; | ||
301 | transform_rgb_to_draw(p_row, out_row, channels, width); | ||
302 | } | ||
303 | free(p_row); | ||
304 | |||
305 | *pSurface = (gr_surface*) surface; | ||
306 | |||
307 | exit: | ||
308 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||
309 | |||
310 | if (result < 0) { | ||
311 | if (surface) { | ||
312 | for (i = 0; i < *frames; ++i) { | ||
313 | if (surface[i]) free(surface[i]); | ||
314 | } | ||
315 | free(surface); | ||
316 | } | ||
317 | } | ||
318 | return result; | ||
319 | } | ||
320 | |||
321 | int res_create_alpha_surface(const char* name, gr_surface* pSurface) { | ||
322 | gr_surface surface = NULL; | ||
323 | int result = 0; | ||
324 | png_structp png_ptr = NULL; | ||
325 | png_infop info_ptr = NULL; | ||
326 | png_uint_32 width, height; | ||
327 | png_byte channels; | ||
328 | |||
329 | *pSurface = NULL; | ||
330 | |||
331 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); | ||
332 | if (result < 0) return result; | ||
333 | |||
334 | if (channels != 1) { | ||
335 | result = -7; | ||
336 | goto exit; | ||
337 | } | ||
338 | |||
339 | surface = malloc_surface(width * height); | ||
340 | if (surface == NULL) { | ||
341 | result = -8; | ||
342 | goto exit; | ||
343 | } | ||
344 | surface->width = width; | ||
345 | surface->height = height; | ||
346 | surface->row_bytes = width; | ||
347 | surface->pixel_bytes = 1; | ||
348 | |||
349 | #if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) | ||
350 | png_set_bgr(png_ptr); | ||
351 | #endif | ||
352 | |||
353 | unsigned char* p_row; | ||
354 | unsigned int y; | ||
355 | for (y = 0; y < height; ++y) { | ||
356 | p_row = surface->data + y * surface->row_bytes; | ||
357 | png_read_row(png_ptr, p_row, NULL); | ||
358 | } | ||
359 | |||
360 | *pSurface = surface; | ||
361 | |||
362 | exit: | ||
363 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||
364 | if (result < 0 && surface != NULL) free(surface); | ||
365 | return result; | ||
366 | } | ||
367 | |||
368 | static int matches_locale(const char* loc, const char* locale) { | ||
369 | if (locale == NULL) return 0; | ||
370 | |||
371 | if (strcmp(loc, locale) == 0) return 1; | ||
372 | |||
373 | // if loc does *not* have an underscore, and it matches the start | ||
374 | // of locale, and the next character in locale *is* an underscore, | ||
375 | // that's a match. For instance, loc == "en" matches locale == | ||
376 | // "en_US". | ||
377 | |||
378 | int i; | ||
379 | for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i); | ||
380 | if (loc[i] == '_') return 0; | ||
381 | |||
382 | return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); | ||
383 | } | ||
384 | |||
385 | int res_create_localized_alpha_surface(const char* name, | ||
386 | const char* locale, | ||
387 | gr_surface* pSurface) { | ||
388 | gr_surface surface = NULL; | ||
389 | int result = 0; | ||
390 | png_structp png_ptr = NULL; | ||
391 | png_infop info_ptr = NULL; | ||
392 | png_uint_32 width, height; | ||
393 | png_byte channels; | ||
394 | unsigned char* row; | ||
395 | png_uint_32 y; | ||
396 | |||
397 | *pSurface = NULL; | ||
398 | |||
399 | if (locale == NULL) { | ||
400 | surface = malloc_surface(0); | ||
401 | surface->width = 0; | ||
402 | surface->height = 0; | ||
403 | surface->row_bytes = 0; | ||
404 | surface->pixel_bytes = 1; | ||
405 | goto exit; | ||
406 | } | ||
407 | |||
408 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); | ||
409 | if (result < 0) return result; | ||
410 | |||
411 | if (channels != 1) { | ||
412 | result = -7; | ||
413 | goto exit; | ||
414 | } | ||
415 | |||
416 | row = reinterpret_cast<unsigned char*>(malloc(width)); | ||
417 | for (y = 0; y < height; ++y) { | ||
418 | png_read_row(png_ptr, row, NULL); | ||
419 | int w = (row[1] << 8) | row[0]; | ||
420 | int h = (row[3] << 8) | row[2]; | ||
421 | int len = row[4]; | ||
422 | char* loc = (char*)row+5; | ||
423 | |||
424 | if (y+1+h >= height || matches_locale(loc, locale)) { | ||
425 | printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); | ||
426 | |||
427 | surface = malloc_surface(w*h); | ||
428 | if (surface == NULL) { | ||
429 | result = -8; | ||
430 | goto exit; | ||
431 | } | ||
432 | surface->width = w; | ||
433 | surface->height = h; | ||
434 | surface->row_bytes = w; | ||
435 | surface->pixel_bytes = 1; | ||
436 | |||
437 | int i; | ||
438 | for (i = 0; i < h; ++i, ++y) { | ||
439 | png_read_row(png_ptr, row, NULL); | ||
440 | memcpy(surface->data + i*w, row, w); | ||
441 | } | ||
442 | |||
443 | *pSurface = (gr_surface) surface; | ||
444 | break; | ||
445 | } else { | ||
446 | int i; | ||
447 | for (i = 0; i < h; ++i, ++y) { | ||
448 | png_read_row(png_ptr, row, NULL); | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | exit: | ||
454 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||
455 | if (result < 0 && surface != NULL) free(surface); | ||
456 | return result; | ||
457 | } | ||
458 | |||
459 | void res_free_surface(gr_surface surface) { | ||
460 | free(surface); | ||
461 | } | ||