• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 #include <fcntl.h>
21 #include <stdio.h>
22 
23 #include <sys/ioctl.h>
24 #include <sys/mman.h>
25 #include <sys/types.h>
26 
27 #include <linux/fb.h>
28 #include <linux/kd.h>
29 
30 #include <pixelflinger/pixelflinger.h>
31 
32 #include <png.h>
33 
34 #include "minui.h"
35 
36 extern char* locale;
37 
38 // libpng gives "undefined reference to 'pow'" errors, and I have no
39 // idea how to convince the build system to link with -lm.  We don't
40 // need this functionality (it's used for gamma adjustment) so provide
41 // a dummy implementation to satisfy the linker.
pow(double x,double y)42 double pow(double x, double y) {
43     return x * y;
44 }
45 
res_create_surface(const char * name,gr_surface * pSurface)46 int res_create_surface(const char* name, gr_surface* pSurface) {
47     char resPath[256];
48     GGLSurface* surface = NULL;
49     int result = 0;
50     unsigned char header[8];
51     png_structp png_ptr = NULL;
52     png_infop info_ptr = NULL;
53 
54     *pSurface = NULL;
55 
56     snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
57     resPath[sizeof(resPath)-1] = '\0';
58     FILE* fp = fopen(resPath, "rb");
59     if (fp == NULL) {
60         result = -1;
61         goto exit;
62     }
63 
64     size_t bytesRead = fread(header, 1, sizeof(header), fp);
65     if (bytesRead != sizeof(header)) {
66         result = -2;
67         goto exit;
68     }
69 
70     if (png_sig_cmp(header, 0, sizeof(header))) {
71         result = -3;
72         goto exit;
73     }
74 
75     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
76     if (!png_ptr) {
77         result = -4;
78         goto exit;
79     }
80 
81     info_ptr = png_create_info_struct(png_ptr);
82     if (!info_ptr) {
83         result = -5;
84         goto exit;
85     }
86 
87     if (setjmp(png_jmpbuf(png_ptr))) {
88         result = -6;
89         goto exit;
90     }
91 
92     png_init_io(png_ptr, fp);
93     png_set_sig_bytes(png_ptr, sizeof(header));
94     png_read_info(png_ptr, info_ptr);
95 
96     int color_type = info_ptr->color_type;
97     int bit_depth = info_ptr->bit_depth;
98     int channels = info_ptr->channels;
99     if (!(bit_depth == 8 &&
100           ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
101            (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
102            (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
103                               color_type == PNG_COLOR_TYPE_GRAY))))) {
104         return -7;
105         goto exit;
106     }
107 
108     size_t width = info_ptr->width;
109     size_t height = info_ptr->height;
110     size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
111     size_t pixelSize = stride * height;
112 
113     surface = malloc(sizeof(GGLSurface) + pixelSize);
114     if (surface == NULL) {
115         result = -8;
116         goto exit;
117     }
118     unsigned char* pData = (unsigned char*) (surface + 1);
119     surface->version = sizeof(GGLSurface);
120     surface->width = width;
121     surface->height = height;
122     surface->stride = width; /* Yes, pixels, not bytes */
123     surface->data = pData;
124     surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 :
125         ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8));
126 
127     int alpha = 0;
128     if (color_type == PNG_COLOR_TYPE_PALETTE) {
129         png_set_palette_to_rgb(png_ptr);
130     }
131     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
132         png_set_tRNS_to_alpha(png_ptr);
133         alpha = 1;
134     }
135     if (color_type == PNG_COLOR_TYPE_GRAY) {
136         alpha = 1;
137     }
138 
139     unsigned int y;
140     if (channels == 3 || (channels == 1 && !alpha)) {
141         for (y = 0; y < height; ++y) {
142             unsigned char* pRow = pData + y * stride;
143             png_read_row(png_ptr, pRow, NULL);
144 
145             int x;
146             for(x = width - 1; x >= 0; x--) {
147                 int sx = x * 3;
148                 int dx = x * 4;
149                 unsigned char r = pRow[sx];
150                 unsigned char g = pRow[sx + 1];
151                 unsigned char b = pRow[sx + 2];
152                 unsigned char a = 0xff;
153                 pRow[dx    ] = r; // r
154                 pRow[dx + 1] = g; // g
155                 pRow[dx + 2] = b; // b
156                 pRow[dx + 3] = a;
157             }
158         }
159     } else {
160         for (y = 0; y < height; ++y) {
161             unsigned char* pRow = pData + y * stride;
162             png_read_row(png_ptr, pRow, NULL);
163         }
164     }
165 
166     *pSurface = (gr_surface) surface;
167 
168 exit:
169     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
170 
171     if (fp != NULL) {
172         fclose(fp);
173     }
174     if (result < 0) {
175         if (surface) {
176             free(surface);
177         }
178     }
179     return result;
180 }
181 
matches_locale(const char * loc)182 static int matches_locale(const char* loc) {
183     if (locale == NULL) return 0;
184 
185     if (strcmp(loc, locale) == 0) return 1;
186 
187     // if loc does *not* have an underscore, and it matches the start
188     // of locale, and the next character in locale *is* an underscore,
189     // that's a match.  For instance, loc == "en" matches locale ==
190     // "en_US".
191 
192     int i;
193     for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
194     if (loc[i] == '_') return 0;
195 
196     return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
197 }
198 
res_create_localized_surface(const char * name,gr_surface * pSurface)199 int res_create_localized_surface(const char* name, gr_surface* pSurface) {
200     char resPath[256];
201     GGLSurface* surface = NULL;
202     int result = 0;
203     unsigned char header[8];
204     png_structp png_ptr = NULL;
205     png_infop info_ptr = NULL;
206 
207     *pSurface = NULL;
208 
209     snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
210     resPath[sizeof(resPath)-1] = '\0';
211     FILE* fp = fopen(resPath, "rb");
212     if (fp == NULL) {
213         result = -1;
214         goto exit;
215     }
216 
217     size_t bytesRead = fread(header, 1, sizeof(header), fp);
218     if (bytesRead != sizeof(header)) {
219         result = -2;
220         goto exit;
221     }
222 
223     if (png_sig_cmp(header, 0, sizeof(header))) {
224         result = -3;
225         goto exit;
226     }
227 
228     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
229     if (!png_ptr) {
230         result = -4;
231         goto exit;
232     }
233 
234     info_ptr = png_create_info_struct(png_ptr);
235     if (!info_ptr) {
236         result = -5;
237         goto exit;
238     }
239 
240     if (setjmp(png_jmpbuf(png_ptr))) {
241         result = -6;
242         goto exit;
243     }
244 
245     png_init_io(png_ptr, fp);
246     png_set_sig_bytes(png_ptr, sizeof(header));
247     png_read_info(png_ptr, info_ptr);
248 
249     size_t width = info_ptr->width;
250     size_t height = info_ptr->height;
251     size_t stride = 4 * width;
252 
253     int color_type = info_ptr->color_type;
254     int bit_depth = info_ptr->bit_depth;
255     int channels = info_ptr->channels;
256 
257     if (!(bit_depth == 8 &&
258           (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) {
259         return -7;
260         goto exit;
261     }
262 
263     unsigned char* row = malloc(width);
264     int y;
265     for (y = 0; y < height; ++y) {
266         png_read_row(png_ptr, row, NULL);
267         int w = (row[1] << 8) | row[0];
268         int h = (row[3] << 8) | row[2];
269         int len = row[4];
270         char* loc = row+5;
271 
272         if (y+1+h >= height || matches_locale(loc)) {
273             printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
274 
275             surface = malloc(sizeof(GGLSurface));
276             if (surface == NULL) {
277                 result = -8;
278                 goto exit;
279             }
280             unsigned char* pData = malloc(w*h);
281 
282             surface->version = sizeof(GGLSurface);
283             surface->width = w;
284             surface->height = h;
285             surface->stride = w; /* Yes, pixels, not bytes */
286             surface->data = pData;
287             surface->format = GGL_PIXEL_FORMAT_A_8;
288 
289             int i;
290             for (i = 0; i < h; ++i, ++y) {
291                 png_read_row(png_ptr, row, NULL);
292                 memcpy(pData + i*w, row, w);
293             }
294 
295             *pSurface = (gr_surface) surface;
296             break;
297         } else {
298             int i;
299             for (i = 0; i < h; ++i, ++y) {
300                 png_read_row(png_ptr, row, NULL);
301             }
302         }
303     }
304 
305 exit:
306     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
307 
308     if (fp != NULL) {
309         fclose(fp);
310     }
311     if (result < 0) {
312         if (surface) {
313             free(surface);
314         }
315     }
316     return result;
317 }
318 
res_free_surface(gr_surface surface)319 void res_free_surface(gr_surface surface) {
320     GGLSurface* pSurface = (GGLSurface*) surface;
321     if (pSurface) {
322         free(pSurface);
323     }
324 }
325