• 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     size_t width = info_ptr->width;
97     size_t height = info_ptr->height;
98     size_t stride = 4 * width;
99     size_t pixelSize = stride * height;
100 
101     int color_type = info_ptr->color_type;
102     int bit_depth = info_ptr->bit_depth;
103     int channels = info_ptr->channels;
104     if (!(bit_depth == 8 &&
105           ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
106            (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
107            (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
108         return -7;
109         goto exit;
110     }
111 
112     surface = malloc(sizeof(GGLSurface) + pixelSize);
113     if (surface == NULL) {
114         result = -8;
115         goto exit;
116     }
117     unsigned char* pData = (unsigned char*) (surface + 1);
118     surface->version = sizeof(GGLSurface);
119     surface->width = width;
120     surface->height = height;
121     surface->stride = width; /* Yes, pixels, not bytes */
122     surface->data = pData;
123     surface->format = (channels == 3) ?
124             GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
125 
126     int alpha = 0;
127     if (color_type == PNG_COLOR_TYPE_PALETTE) {
128         png_set_palette_to_rgb(png_ptr);
129     }
130     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
131         png_set_tRNS_to_alpha(png_ptr);
132         alpha = 1;
133     }
134 
135     unsigned int y;
136     if (channels == 3 || (channels == 1 && !alpha)) {
137         for (y = 0; y < height; ++y) {
138             unsigned char* pRow = pData + y * stride;
139             png_read_row(png_ptr, pRow, NULL);
140 
141             int x;
142             for(x = width - 1; x >= 0; x--) {
143                 int sx = x * 3;
144                 int dx = x * 4;
145                 unsigned char r = pRow[sx];
146                 unsigned char g = pRow[sx + 1];
147                 unsigned char b = pRow[sx + 2];
148                 unsigned char a = 0xff;
149                 pRow[dx    ] = r; // r
150                 pRow[dx + 1] = g; // g
151                 pRow[dx + 2] = b; // b
152                 pRow[dx + 3] = a;
153             }
154         }
155     } else {
156         for (y = 0; y < height; ++y) {
157             unsigned char* pRow = pData + y * stride;
158             png_read_row(png_ptr, pRow, NULL);
159         }
160     }
161 
162     *pSurface = (gr_surface) surface;
163 
164 exit:
165     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
166 
167     if (fp != NULL) {
168         fclose(fp);
169     }
170     if (result < 0) {
171         if (surface) {
172             free(surface);
173         }
174     }
175     return result;
176 }
177 
matches_locale(const char * loc)178 static int matches_locale(const char* loc) {
179     if (locale == NULL) return 0;
180 
181     if (strcmp(loc, locale) == 0) return 1;
182 
183     // if loc does *not* have an underscore, and it matches the start
184     // of locale, and the next character in locale *is* an underscore,
185     // that's a match.  For instance, loc == "en" matches locale ==
186     // "en_US".
187 
188     int i;
189     for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
190     if (loc[i] == '_') return 0;
191 
192     return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
193 }
194 
res_create_localized_surface(const char * name,gr_surface * pSurface)195 int res_create_localized_surface(const char* name, gr_surface* pSurface) {
196     char resPath[256];
197     GGLSurface* surface = NULL;
198     int result = 0;
199     unsigned char header[8];
200     png_structp png_ptr = NULL;
201     png_infop info_ptr = NULL;
202 
203     *pSurface = NULL;
204 
205     snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
206     resPath[sizeof(resPath)-1] = '\0';
207     FILE* fp = fopen(resPath, "rb");
208     if (fp == NULL) {
209         result = -1;
210         goto exit;
211     }
212 
213     size_t bytesRead = fread(header, 1, sizeof(header), fp);
214     if (bytesRead != sizeof(header)) {
215         result = -2;
216         goto exit;
217     }
218 
219     if (png_sig_cmp(header, 0, sizeof(header))) {
220         result = -3;
221         goto exit;
222     }
223 
224     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
225     if (!png_ptr) {
226         result = -4;
227         goto exit;
228     }
229 
230     info_ptr = png_create_info_struct(png_ptr);
231     if (!info_ptr) {
232         result = -5;
233         goto exit;
234     }
235 
236     if (setjmp(png_jmpbuf(png_ptr))) {
237         result = -6;
238         goto exit;
239     }
240 
241     png_init_io(png_ptr, fp);
242     png_set_sig_bytes(png_ptr, sizeof(header));
243     png_read_info(png_ptr, info_ptr);
244 
245     size_t width = info_ptr->width;
246     size_t height = info_ptr->height;
247     size_t stride = 4 * width;
248 
249     int color_type = info_ptr->color_type;
250     int bit_depth = info_ptr->bit_depth;
251     int channels = info_ptr->channels;
252 
253     if (!(bit_depth == 8 &&
254           (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) {
255         return -7;
256         goto exit;
257     }
258 
259     unsigned char* row = malloc(width);
260     int y;
261     for (y = 0; y < height; ++y) {
262         png_read_row(png_ptr, row, NULL);
263         int w = (row[1] << 8) | row[0];
264         int h = (row[3] << 8) | row[2];
265         int len = row[4];
266         char* loc = row+5;
267 
268         if (y+1+h >= height || matches_locale(loc)) {
269             printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
270 
271             surface = malloc(sizeof(GGLSurface));
272             if (surface == NULL) {
273                 result = -8;
274                 goto exit;
275             }
276             unsigned char* pData = malloc(w*h);
277 
278             surface->version = sizeof(GGLSurface);
279             surface->width = w;
280             surface->height = h;
281             surface->stride = w; /* Yes, pixels, not bytes */
282             surface->data = pData;
283             surface->format = GGL_PIXEL_FORMAT_A_8;
284 
285             int i;
286             for (i = 0; i < h; ++i, ++y) {
287                 png_read_row(png_ptr, row, NULL);
288                 memcpy(pData + i*w, row, w);
289             }
290 
291             *pSurface = (gr_surface) surface;
292             break;
293         } else {
294             int i;
295             for (i = 0; i < h; ++i, ++y) {
296                 png_read_row(png_ptr, row, NULL);
297             }
298         }
299     }
300 
301 exit:
302     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
303 
304     if (fp != NULL) {
305         fclose(fp);
306     }
307     if (result < 0) {
308         if (surface) {
309             free(surface);
310         }
311     }
312     return result;
313 }
314 
res_free_surface(gr_surface surface)315 void res_free_surface(gr_surface surface) {
316     GGLSurface* pSurface = (GGLSurface*) surface;
317     if (pSurface) {
318         free(pSurface);
319     }
320 }
321