xref: /OK3568_Linux_fs/external/rk_pcba_test/pcba_minui/minui/resources.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 <unistd.h>
19 #include <string.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 
malloc_surface(size_t data_size)39 static gr_surface malloc_surface(size_t data_size) {
40     unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);
41     if (temp == NULL) return NULL;
42     gr_surface surface = (gr_surface) temp;
43     surface->data = temp + sizeof(GRSurface) +
44         (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
45     return surface;
46 }
47 
open_png(const char * name,png_structp * png_ptr,png_infop * info_ptr,png_uint_32 * width,png_uint_32 * height,png_byte * channels)48 static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr,
49                     png_uint_32* width, png_uint_32* height, png_byte* channels) {
50     char resPath[256];
51     unsigned char header[8];
52     int result = 0;
53 
54     snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
55     resPath[sizeof(resPath)-1] = '\0';
56     FILE* fp = fopen(resPath, "rb");
57     if (fp == NULL) {
58         result = -1;
59         goto exit;
60     }
61 
62     size_t bytesRead = fread(header, 1, sizeof(header), fp);
63     if (bytesRead != sizeof(header)) {
64         result = -2;
65         goto exit;
66     }
67 
68     if (png_sig_cmp(header, 0, sizeof(header))) {
69         result = -3;
70         goto exit;
71     }
72 
73     *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
74     if (!*png_ptr) {
75         result = -4;
76         goto exit;
77     }
78 
79     *info_ptr = png_create_info_struct(*png_ptr);
80     if (!*info_ptr) {
81         result = -5;
82         goto exit;
83     }
84 
85     if (setjmp(png_jmpbuf(*png_ptr))) {
86         result = -6;
87         goto exit;
88     }
89 
90     png_init_io(*png_ptr, fp);
91     png_set_sig_bytes(*png_ptr, sizeof(header));
92     png_read_info(*png_ptr, *info_ptr);
93 
94     int color_type, bit_depth;
95     png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
96             &color_type, NULL, NULL, NULL);
97 
98     *channels = png_get_channels(*png_ptr, *info_ptr);
99 
100     if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
101         // 8-bit RGB images: great, nothing to do.
102     } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
103         // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
104         png_set_expand_gray_1_2_4_to_8(*png_ptr);
105     } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
106         // paletted images: expand to 8-bit RGB.  Note that we DON'T
107         // currently expand the tRNS chunk (if any) to an alpha
108         // channel, because minui doesn't support alpha channels in
109         // general.
110         png_set_palette_to_rgb(*png_ptr);
111         *channels = 3;
112     } else {
113         fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
114                 bit_depth, *channels, color_type);
115         result = -7;
116         goto exit;
117     }
118 
119     return result;
120 
121   exit:
122     if (result < 0) {
123         png_destroy_read_struct(png_ptr, info_ptr, NULL);
124     }
125     if (fp != NULL) {
126         fclose(fp);
127     }
128 
129     return result;
130 }
131 
132 // "display" surfaces are transformed into the framebuffer's required
133 // pixel format (currently only RGBX is supported) at load time, so
134 // gr_blit() can be nothing more than a memcpy() for each row.  The
135 // next two functions are the only ones that know anything about the
136 // framebuffer pixel format; they need to be modified if the
137 // framebuffer format changes (but nothing else should).
138 
139 // Allocate and return a gr_surface sufficient for storing an image of
140 // the indicated size in the framebuffer pixel format.
init_display_surface(png_uint_32 width,png_uint_32 height)141 static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) {
142     gr_surface surface;
143 
144     surface = malloc_surface(width * height * 4);
145     if (surface == NULL) return NULL;
146 
147     surface->width = width;
148     surface->height = height;
149     surface->row_bytes = width * 4;
150     surface->pixel_bytes = 4;
151 
152     return surface;
153 }
154 
155 // Copy 'input_row' to 'output_row', transforming it to the
156 // framebuffer pixel format.  The input format depends on the value of
157 // 'channels':
158 //
159 //   1 - input is 8-bit grayscale
160 //   3 - input is 24-bit RGB
161 //   4 - input is 32-bit RGBA/RGBX
162 //
163 // 'width' is the number of pixels in the row.
transform_rgb_to_draw(unsigned char * input_row,unsigned char * output_row,int channels,int width)164 static void transform_rgb_to_draw(unsigned char* input_row,
165                                   unsigned char* output_row,
166                                   int channels, int width) {
167     int x;
168     unsigned char* ip = input_row;
169     unsigned char* op = output_row;
170 
171     switch (channels) {
172         case 1:
173             // expand gray level to RGBX
174             for (x = 0; x < width; ++x) {
175                 *op++ = *ip;
176                 *op++ = *ip;
177                 *op++ = *ip;
178                 *op++ = 0xff;
179                 ip++;
180             }
181             break;
182 
183         case 3:
184             // expand RGBA to RGBX
185             for (x = 0; x < width; ++x) {
186                 *op++ = *ip++;
187                 *op++ = *ip++;
188                 *op++ = *ip++;
189                 *op++ = 0xff;
190             }
191             break;
192 
193         case 4:
194             // copy RGBA to RGBX
195             memcpy(output_row, input_row, width*4);
196             break;
197     }
198 }
199 
res_create_display_surface(const char * name,gr_surface * pSurface)200 int res_create_display_surface(const char* name, gr_surface* pSurface) {
201     gr_surface surface = NULL;
202     int result = 0;
203     png_structp png_ptr = NULL;
204     png_infop info_ptr = NULL;
205     png_uint_32 width, height;
206     png_byte channels;
207 
208     *pSurface = NULL;
209 
210     result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
211     if (result < 0) return result;
212 
213     surface = init_display_surface(width, height);
214     if (surface == NULL) {
215         result = -8;
216         goto exit;
217     }
218 
219     unsigned char* p_row = malloc(width * 4);
220     unsigned int y;
221     for (y = 0; y < height; ++y) {
222         png_read_row(png_ptr, p_row, NULL);
223         transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
224     }
225     free(p_row);
226 
227     *pSurface = surface;
228 
229   exit:
230     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
231     if (result < 0 && surface != NULL) free(surface);
232     return result;
233 }
234 
res_create_multi_display_surface(const char * name,int * frames,gr_surface ** pSurface)235 int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) {
236     gr_surface* surface = NULL;
237     int result = 0;
238     png_structp png_ptr = NULL;
239     png_infop info_ptr = NULL;
240     png_uint_32 width, height;
241     png_byte channels;
242     int i;
243 
244     *pSurface = NULL;
245     *frames = -1;
246 
247     result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
248     if (result < 0) return result;
249 
250     *frames = 1;
251     png_textp text;
252     int num_text;
253     if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
254         for (i = 0; i < num_text; ++i) {
255             if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
256                 *frames = atoi(text[i].text);
257                 break;
258             }
259         }
260         printf("  found frames = %d\n", *frames);
261     }
262 
263     if (height % *frames != 0) {
264         printf("bad height (%d) for frame count (%d)\n", height, *frames);
265         result = -9;
266         goto exit;
267     }
268 
269     surface = malloc(*frames * sizeof(gr_surface));
270     if (surface == NULL) {
271         result = -8;
272         goto exit;
273     }
274     for (i = 0; i < *frames; ++i) {
275         surface[i] = init_display_surface(width, height / *frames);
276         if (surface[i] == NULL) {
277             result = -8;
278             goto exit;
279         }
280     }
281 
282     unsigned char* p_row = malloc(width * 4);
283     unsigned int y;
284     for (y = 0; y < height; ++y) {
285         png_read_row(png_ptr, p_row, NULL);
286         int frame = y % *frames;
287         unsigned char* out_row = surface[frame]->data +
288             (y / *frames) * surface[frame]->row_bytes;
289         transform_rgb_to_draw(p_row, out_row, channels, width);
290     }
291     free(p_row);
292 
293     *pSurface = (gr_surface*) surface;
294 
295 exit:
296     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
297 
298     if (result < 0) {
299         if (surface) {
300             for (i = 0; i < *frames; ++i) {
301                 if (surface[i]) free(surface[i]);
302             }
303             free(surface);
304         }
305     }
306     return result;
307 }
308 
res_create_alpha_surface(const char * name,gr_surface * pSurface)309 int res_create_alpha_surface(const char* name, gr_surface* pSurface) {
310     gr_surface surface = NULL;
311     int result = 0;
312     png_structp png_ptr = NULL;
313     png_infop info_ptr = NULL;
314     png_uint_32 width, height;
315     png_byte channels;
316 
317     *pSurface = NULL;
318 
319     result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
320     if (result < 0) return result;
321 
322     if (channels != 1) {
323         result = -7;
324         goto exit;
325     }
326 
327     surface = malloc_surface(width * height);
328     if (surface == NULL) {
329         result = -8;
330         goto exit;
331     }
332     surface->width = width;
333     surface->height = height;
334     surface->row_bytes = width;
335     surface->pixel_bytes = 1;
336 
337     unsigned char* p_row;
338     unsigned int y;
339     for (y = 0; y < height; ++y) {
340         p_row = surface->data + y * surface->row_bytes;
341         png_read_row(png_ptr, p_row, NULL);
342     }
343 
344     *pSurface = surface;
345 
346   exit:
347     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
348     if (result < 0 && surface != NULL) free(surface);
349     return result;
350 }
351 
matches_locale(const char * loc,const char * locale)352 static int matches_locale(const char* loc, const char* locale) {
353     if (locale == NULL) return 0;
354 
355     if (strcmp(loc, locale) == 0) return 1;
356 
357     // if loc does *not* have an underscore, and it matches the start
358     // of locale, and the next character in locale *is* an underscore,
359     // that's a match.  For instance, loc == "en" matches locale ==
360     // "en_US".
361 
362     int i;
363     for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
364     if (loc[i] == '_') return 0;
365 
366     return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
367 }
368 
res_create_localized_alpha_surface(const char * name,const char * locale,gr_surface * pSurface)369 int res_create_localized_alpha_surface(const char* name,
370                                        const char* locale,
371                                        gr_surface* pSurface) {
372     gr_surface surface = NULL;
373     int result = 0;
374     png_structp png_ptr = NULL;
375     png_infop info_ptr = NULL;
376     png_uint_32 width, height;
377     png_byte channels;
378 
379     *pSurface = NULL;
380 
381     if (locale == NULL) {
382         surface = malloc_surface(0);
383         surface->width = 0;
384         surface->height = 0;
385         surface->row_bytes = 0;
386         surface->pixel_bytes = 1;
387         goto exit;
388     }
389 
390     result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
391     if (result < 0) return result;
392 
393     if (channels != 1) {
394         result = -7;
395         goto exit;
396     }
397 
398     unsigned char* row = malloc(width);
399     png_uint_32 y;
400     for (y = 0; y < height; ++y) {
401         png_read_row(png_ptr, row, NULL);
402         int w = (row[1] << 8) | row[0];
403         int h = (row[3] << 8) | row[2];
404         int len = row[4];
405         char* loc = (char*)row+5;
406 
407         if (y+1+h >= height || matches_locale(loc, locale)) {
408             printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
409 
410             surface = malloc_surface(w*h);
411             if (surface == NULL) {
412                 result = -8;
413                 goto exit;
414             }
415             surface->width = w;
416             surface->height = h;
417             surface->row_bytes = w;
418             surface->pixel_bytes = 1;
419 
420             int i;
421             for (i = 0; i < h; ++i, ++y) {
422                 png_read_row(png_ptr, row, NULL);
423                 memcpy(surface->data + i*w, row, w);
424             }
425 
426             *pSurface = (gr_surface) surface;
427             break;
428         } else {
429             int i;
430             for (i = 0; i < h; ++i, ++y) {
431                 png_read_row(png_ptr, row, NULL);
432             }
433         }
434     }
435 
436 exit:
437     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
438     if (result < 0 && surface != NULL) free(surface);
439     return result;
440 }
441 
res_free_surface(gr_surface surface)442 void res_free_surface(gr_surface surface) {
443     free(surface);
444 }
445