diff options
-rw-r--r-- | minui/graphics.c | 2 | ||||
-rw-r--r-- | minui/minui.h | 38 | ||||
-rw-r--r-- | minui/resources.c | 440 | ||||
-rw-r--r-- | recovery.cpp | 2 | ||||
-rw-r--r-- | screen_ui.cpp | 14 | ||||
-rw-r--r-- | screen_ui.h | 1 |
6 files changed, 253 insertions, 244 deletions
diff --git a/minui/graphics.c b/minui/graphics.c index f8ffa894..32b3361e 100644 --- a/minui/graphics.c +++ b/minui/graphics.c | |||
@@ -269,7 +269,7 @@ static void gr_init_font(void) | |||
269 | { | 269 | { |
270 | gr_font = calloc(sizeof(*gr_font), 1); | 270 | gr_font = calloc(sizeof(*gr_font), 1); |
271 | 271 | ||
272 | int res = res_create_surface("font", &(gr_font->texture)); | 272 | int res = res_create_alpha_surface("font", &(gr_font->texture)); |
273 | if (res == 0) { | 273 | if (res == 0) { |
274 | // The font image should be a 96x2 array of character images. The | 274 | // The font image should be a 96x2 array of character images. The |
275 | // columns are the printable ASCII characters 0x20 - 0x7f. The | 275 | // columns are the printable ASCII characters 0x20 - 0x7f. The |
diff --git a/minui/minui.h b/minui/minui.h index 328da1e6..d8d53fa2 100644 --- a/minui/minui.h +++ b/minui/minui.h | |||
@@ -80,10 +80,40 @@ void ev_dispatch(void); | |||
80 | 80 | ||
81 | // Resources | 81 | // Resources |
82 | 82 | ||
83 | // Returns 0 if no error, else negative. | 83 | // res_create_*_surface() functions return 0 if no error, else |
84 | int res_create_surface(const char* name, gr_surface* pSurface); | 84 | // negative. |
85 | int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurface); | 85 | // |
86 | int res_create_localized_surface(const char* name, gr_surface* pSurface); | 86 | // A "display" surface is one that is intended to be drawn to the |
87 | // screen with gr_blit(). An "alpha" surface is a grayscale image | ||
88 | // interpreted as an alpha mask used to render text in the current | ||
89 | // color (with gr_text() or gr_texticon()). | ||
90 | // | ||
91 | // All these functions load PNG images from "/res/images/${name}.png". | ||
92 | |||
93 | // Load a single display surface from a PNG image. | ||
94 | int res_create_display_surface(const char* name, gr_surface* pSurface); | ||
95 | |||
96 | // Load an array of display surfaces from a single PNG image. The PNG | ||
97 | // should have a 'Frames' text chunk whose value is the number of | ||
98 | // frames this image represents. The pixel data itself is interlaced | ||
99 | // by row. | ||
100 | int res_create_multi_display_surface(const char* name, | ||
101 | int* frames, gr_surface** pSurface); | ||
102 | |||
103 | // Load a single alpha surface from a grayscale PNG image. | ||
104 | int res_create_alpha_surface(const char* name, gr_surface* pSurface); | ||
105 | |||
106 | // Load part of a grayscale PNG image that is the first match for the | ||
107 | // given locale. The image is expected to be a composite of multiple | ||
108 | // translations of the same text, with special added rows that encode | ||
109 | // the subimages' size and intended locale in the pixel data. See | ||
110 | // development/tools/recovery_l10n for an app that will generate these | ||
111 | // specialized images from Android resources. | ||
112 | int res_create_localized_alpha_surface(const char* name, const char* locale, | ||
113 | gr_surface* pSurface); | ||
114 | |||
115 | // Free a surface allocated by any of the res_create_*_surface() | ||
116 | // functions. | ||
87 | void res_free_surface(gr_surface surface); | 117 | void res_free_surface(gr_surface surface); |
88 | 118 | ||
89 | #ifdef __cplusplus | 119 | #ifdef __cplusplus |
diff --git a/minui/resources.c b/minui/resources.c index a6528b35..69fd14be 100644 --- a/minui/resources.c +++ b/minui/resources.c | |||
@@ -44,15 +44,11 @@ static gr_surface malloc_surface(size_t data_size) { | |||
44 | return surface; | 44 | return surface; |
45 | } | 45 | } |
46 | 46 | ||
47 | int res_create_surface(const char* name, gr_surface* pSurface) { | 47 | static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, |
48 | png_uint_32* width, png_uint_32* height, png_byte* channels) { | ||
48 | char resPath[256]; | 49 | char resPath[256]; |
49 | gr_surface surface = NULL; | ||
50 | int result = 0; | ||
51 | unsigned char header[8]; | 50 | unsigned char header[8]; |
52 | png_structp png_ptr = NULL; | 51 | int result = 0; |
53 | png_infop info_ptr = NULL; | ||
54 | |||
55 | *pSurface = NULL; | ||
56 | 52 | ||
57 | snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); | 53 | snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); |
58 | resPath[sizeof(resPath)-1] = '\0'; | 54 | resPath[sizeof(resPath)-1] = '\0'; |
@@ -73,170 +69,182 @@ int res_create_surface(const char* name, gr_surface* pSurface) { | |||
73 | goto exit; | 69 | goto exit; |
74 | } | 70 | } |
75 | 71 | ||
76 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | 72 | *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
77 | if (!png_ptr) { | 73 | if (!*png_ptr) { |
78 | result = -4; | 74 | result = -4; |
79 | goto exit; | 75 | goto exit; |
80 | } | 76 | } |
81 | 77 | ||
82 | info_ptr = png_create_info_struct(png_ptr); | 78 | *info_ptr = png_create_info_struct(*png_ptr); |
83 | if (!info_ptr) { | 79 | if (!*info_ptr) { |
84 | result = -5; | 80 | result = -5; |
85 | goto exit; | 81 | goto exit; |
86 | } | 82 | } |
87 | 83 | ||
88 | if (setjmp(png_jmpbuf(png_ptr))) { | 84 | if (setjmp(png_jmpbuf(*png_ptr))) { |
89 | result = -6; | 85 | result = -6; |
90 | goto exit; | 86 | goto exit; |
91 | } | 87 | } |
92 | 88 | ||
93 | png_init_io(png_ptr, fp); | 89 | png_init_io(*png_ptr, fp); |
94 | png_set_sig_bytes(png_ptr, sizeof(header)); | 90 | png_set_sig_bytes(*png_ptr, sizeof(header)); |
95 | png_read_info(png_ptr, info_ptr); | 91 | png_read_info(*png_ptr, *info_ptr); |
96 | 92 | ||
97 | int color_type, bit_depth; | 93 | int color_type, bit_depth; |
98 | png_uint_32 width, height; | 94 | png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, |
99 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, | ||
100 | &color_type, NULL, NULL, NULL); | 95 | &color_type, NULL, NULL, NULL); |
101 | 96 | ||
102 | int channels = png_get_channels(png_ptr, info_ptr); | 97 | *channels = png_get_channels(*png_ptr, *info_ptr); |
103 | 98 | ||
104 | if (!(bit_depth <= 8 && | 99 | if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { |
105 | ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || | 100 | // 8-bit RGB images: great, nothing to do. |
106 | (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || | 101 | } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { |
107 | color_type == PNG_COLOR_TYPE_GRAY))))) { | 102 | // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. |
108 | return -7; | 103 | png_set_expand_gray_1_2_4_to_8(*png_ptr); |
104 | } else if (bit_depth == 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { | ||
105 | // paletted images: expand to 8-bit RGB. Note that we DON'T | ||
106 | // currently expand the tRNS chunk (if any) to an alpha | ||
107 | // channel, because minui doesn't support alpha channels in | ||
108 | // general. | ||
109 | png_set_palette_to_rgb(*png_ptr); | ||
110 | *channels = 3; | ||
111 | } else { | ||
112 | fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", | ||
113 | bit_depth, (int) channels, color_type); | ||
114 | result = -7; | ||
109 | goto exit; | 115 | goto exit; |
110 | } | 116 | } |
111 | 117 | ||
112 | size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; | 118 | return result; |
113 | 119 | ||
114 | surface = malloc_surface(stride * height); | 120 | exit: |
115 | if (surface == NULL) { | 121 | if (result < 0) { |
116 | result = -8; | 122 | png_destroy_read_struct(png_ptr, info_ptr, NULL); |
117 | goto exit; | 123 | } |
124 | if (fp != NULL) { | ||
125 | fclose(fp); | ||
118 | } | 126 | } |
119 | unsigned char* pData = surface->data; | 127 | |
128 | return result; | ||
129 | } | ||
130 | |||
131 | // "display" surfaces are transformed into the framebuffer's required | ||
132 | // pixel format (currently only RGBX is supported) at load time, so | ||
133 | // gr_blit() can be nothing more than a memcpy() for each row. The | ||
134 | // next two functions are the only ones that know anything about the | ||
135 | // framebuffer pixel format; they need to be modified if the | ||
136 | // framebuffer format changes (but nothing else should). | ||
137 | |||
138 | // Allocate and return a gr_surface sufficient for storing an image of | ||
139 | // the indicated size in the framebuffer pixel format. | ||
140 | static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { | ||
141 | gr_surface surface; | ||
142 | |||
143 | surface = malloc_surface(width * height * 4); | ||
144 | if (surface == NULL) return NULL; | ||
145 | |||
120 | surface->width = width; | 146 | surface->width = width; |
121 | surface->height = height; | 147 | surface->height = height; |
122 | surface->row_bytes = stride; | 148 | surface->row_bytes = width * 4; |
123 | surface->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); | 149 | surface->pixel_bytes = 4; |
124 | 150 | ||
125 | int alpha = (channels == 4); | 151 | return surface; |
126 | png_set_expand(png_ptr); | 152 | } |
127 | if (color_type == PNG_COLOR_TYPE_GRAY) { | ||
128 | alpha = 1; | ||
129 | } | ||
130 | 153 | ||
131 | unsigned int y; | 154 | // Copy 'input_row' to 'output_row', transforming it to the |
132 | if (channels == 3 || (channels == 1 && !alpha)) { | 155 | // framebuffer pixel format. The input format depends on the value of |
133 | for (y = 0; y < height; ++y) { | 156 | // 'channels': |
134 | unsigned char* pRow = pData + y * stride; | 157 | // |
135 | png_read_row(png_ptr, pRow, NULL); | 158 | // 1 - input is 8-bit grayscale |
136 | 159 | // 3 - input is 24-bit RGB | |
137 | int x; | 160 | // 4 - input is 32-bit RGBA/RGBX |
138 | for(x = width - 1; x >= 0; x--) { | 161 | // |
139 | int sx = x * 3; | 162 | // 'width' is the number of pixels in the row. |
140 | int dx = x * 4; | 163 | static void transform_rgb_to_draw(unsigned char* input_row, |
141 | unsigned char r = pRow[sx]; | 164 | unsigned char* output_row, |
142 | unsigned char g = pRow[sx + 1]; | 165 | int channels, int width) { |
143 | unsigned char b = pRow[sx + 2]; | 166 | int x; |
144 | unsigned char a = 0xff; | 167 | unsigned char* ip = input_row; |
145 | pRow[dx ] = r; // r | 168 | unsigned char* op = output_row; |
146 | pRow[dx + 1] = g; // g | 169 | |
147 | pRow[dx + 2] = b; // b | 170 | switch (channels) { |
148 | pRow[dx + 3] = a; | 171 | case 1: |
172 | // expand gray level to RGBX | ||
173 | for (x = 0; x < width; ++x) { | ||
174 | *op++ = *ip; | ||
175 | *op++ = *ip; | ||
176 | *op++ = *ip; | ||
177 | *op++ = 0xff; | ||
178 | ip++; | ||
149 | } | 179 | } |
150 | } | 180 | break; |
151 | } else { | ||
152 | for (y = 0; y < height; ++y) { | ||
153 | unsigned char* pRow = pData + y * stride; | ||
154 | png_read_row(png_ptr, pRow, NULL); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | *pSurface = (gr_surface) surface; | ||
159 | 181 | ||
160 | exit: | 182 | case 3: |
161 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | 183 | // expand RGBA to RGBX |
184 | for (x = 0; x < width; ++x) { | ||
185 | *op++ = *ip++; | ||
186 | *op++ = *ip++; | ||
187 | *op++ = *ip++; | ||
188 | *op++ = 0xff; | ||
189 | } | ||
190 | break; | ||
162 | 191 | ||
163 | if (fp != NULL) { | 192 | case 4: |
164 | fclose(fp); | 193 | // copy RGBA to RGBX |
165 | } | 194 | memcpy(output_row, input_row, width*4); |
166 | if (result < 0) { | 195 | break; |
167 | if (surface) { | ||
168 | free(surface); | ||
169 | } | ||
170 | } | 196 | } |
171 | return result; | ||
172 | } | 197 | } |
173 | 198 | ||
174 | int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurface) { | 199 | int res_create_display_surface(const char* name, gr_surface* pSurface) { |
175 | char resPath[256]; | 200 | gr_surface surface = NULL; |
176 | int result = 0; | 201 | int result = 0; |
177 | unsigned char header[8]; | ||
178 | png_structp png_ptr = NULL; | 202 | png_structp png_ptr = NULL; |
179 | png_infop info_ptr = NULL; | 203 | png_infop info_ptr = NULL; |
180 | int i; | 204 | png_uint_32 width, height; |
181 | gr_surface* surface = NULL; | 205 | png_byte channels; |
182 | 206 | ||
183 | *pSurface = NULL; | 207 | *pSurface = NULL; |
184 | *frames = -1; | ||
185 | 208 | ||
186 | snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); | 209 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); |
187 | resPath[sizeof(resPath)-1] = '\0'; | 210 | if (result < 0) return result; |
188 | FILE* fp = fopen(resPath, "rb"); | ||
189 | if (fp == NULL) { | ||
190 | result = -1; | ||
191 | goto exit; | ||
192 | } | ||
193 | |||
194 | size_t bytesRead = fread(header, 1, sizeof(header), fp); | ||
195 | if (bytesRead != sizeof(header)) { | ||
196 | result = -2; | ||
197 | goto exit; | ||
198 | } | ||
199 | |||
200 | if (png_sig_cmp(header, 0, sizeof(header))) { | ||
201 | result = -3; | ||
202 | goto exit; | ||
203 | } | ||
204 | 211 | ||
205 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | 212 | surface = init_display_surface(width, height); |
206 | if (!png_ptr) { | 213 | if (surface == NULL) { |
207 | result = -4; | 214 | result = -8; |
208 | goto exit; | 215 | goto exit; |
209 | } | 216 | } |
210 | 217 | ||
211 | info_ptr = png_create_info_struct(png_ptr); | 218 | unsigned char* p_row = malloc(width * 4); |
212 | if (!info_ptr) { | 219 | unsigned int y; |
213 | result = -5; | 220 | for (y = 0; y < height; ++y) { |
214 | goto exit; | 221 | png_read_row(png_ptr, p_row, NULL); |
222 | transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width); | ||
215 | } | 223 | } |
224 | free(p_row); | ||
216 | 225 | ||
217 | if (setjmp(png_jmpbuf(png_ptr))) { | 226 | *pSurface = surface; |
218 | result = -6; | ||
219 | goto exit; | ||
220 | } | ||
221 | 227 | ||
222 | png_init_io(png_ptr, fp); | 228 | exit: |
223 | png_set_sig_bytes(png_ptr, sizeof(header)); | 229 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
224 | png_read_info(png_ptr, info_ptr); | 230 | if (result < 0 && surface != NULL) free(surface); |
231 | return result; | ||
232 | } | ||
225 | 233 | ||
226 | int color_type, bit_depth; | 234 | int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { |
235 | gr_surface* surface = NULL; | ||
236 | int result = 0; | ||
237 | png_structp png_ptr = NULL; | ||
238 | png_infop info_ptr = NULL; | ||
227 | png_uint_32 width, height; | 239 | png_uint_32 width, height; |
228 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, | 240 | png_byte channels; |
229 | &color_type, NULL, NULL, NULL); | 241 | int i; |
230 | 242 | ||
231 | int channels = png_get_channels(png_ptr, info_ptr); | 243 | *pSurface = NULL; |
244 | *frames = -1; | ||
232 | 245 | ||
233 | if (!(bit_depth <= 8 && | 246 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); |
234 | ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || | 247 | if (result < 0) return result; |
235 | (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE || | ||
236 | color_type == PNG_COLOR_TYPE_GRAY))))) { | ||
237 | return -7; | ||
238 | goto exit; | ||
239 | } | ||
240 | 248 | ||
241 | *frames = 1; | 249 | *frames = 1; |
242 | png_textp text; | 250 | png_textp text; |
@@ -257,67 +265,35 @@ int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurfac | |||
257 | goto exit; | 265 | goto exit; |
258 | } | 266 | } |
259 | 267 | ||
260 | size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width; | ||
261 | size_t pixelSize = stride * height / *frames; | ||
262 | |||
263 | surface = malloc(*frames * sizeof(gr_surface)); | 268 | surface = malloc(*frames * sizeof(gr_surface)); |
264 | if (surface == NULL) { | 269 | if (surface == NULL) { |
265 | result = -8; | 270 | result = -8; |
266 | goto exit; | 271 | goto exit; |
267 | } | 272 | } |
268 | for (i = 0; i < *frames; ++i) { | 273 | for (i = 0; i < *frames; ++i) { |
269 | surface[i] = malloc_surface(pixelSize); | 274 | surface[i] = init_display_surface(width, height / *frames); |
270 | surface[i]->width = width; | 275 | if (surface[i] == NULL) { |
271 | surface[i]->height = height / *frames; | 276 | result = -8; |
272 | surface[i]->row_bytes = stride; | 277 | goto exit; |
273 | surface[i]->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4); | 278 | } |
274 | } | ||
275 | |||
276 | int alpha = (channels == 4); | ||
277 | png_set_expand(png_ptr); | ||
278 | if (color_type == PNG_COLOR_TYPE_GRAY) { | ||
279 | alpha = 1; | ||
280 | } | 279 | } |
281 | 280 | ||
282 | png_uint_32 y; | 281 | unsigned char* p_row = malloc(width * 4); |
283 | if (channels == 3 || (channels == 1 && !alpha)) { | 282 | unsigned int y; |
284 | for (y = 0; y < height; ++y) { | 283 | for (y = 0; y < height; ++y) { |
285 | int fy = y / *frames; | 284 | png_read_row(png_ptr, p_row, NULL); |
286 | int fr = y % *frames; | 285 | int frame = y % *frames; |
287 | unsigned char* pRow = surface[fr]->data + fy * stride; | 286 | unsigned char* out_row = surface[frame]->data + |
288 | png_read_row(png_ptr, pRow, NULL); | 287 | (y / *frames) * surface[frame]->row_bytes; |
289 | 288 | transform_rgb_to_draw(p_row, out_row, channels, width); | |
290 | int x; | ||
291 | for(x = width - 1; x >= 0; x--) { | ||
292 | int sx = x * 3; | ||
293 | int dx = x * 4; | ||
294 | unsigned char r = pRow[sx]; | ||
295 | unsigned char g = pRow[sx + 1]; | ||
296 | unsigned char b = pRow[sx + 2]; | ||
297 | unsigned char a = 0xff; | ||
298 | pRow[dx ] = r; // r | ||
299 | pRow[dx + 1] = g; // g | ||
300 | pRow[dx + 2] = b; // b | ||
301 | pRow[dx + 3] = a; | ||
302 | } | ||
303 | } | ||
304 | } else { | ||
305 | for (y = 0; y < height; ++y) { | ||
306 | int fy = y / *frames; | ||
307 | int fr = y % *frames; | ||
308 | unsigned char* pRow = surface[fr]->data + fy * stride; | ||
309 | png_read_row(png_ptr, pRow, NULL); | ||
310 | } | ||
311 | } | 289 | } |
290 | free(p_row); | ||
312 | 291 | ||
313 | *pSurface = (gr_surface*) surface; | 292 | *pSurface = (gr_surface*) surface; |
314 | 293 | ||
315 | exit: | 294 | exit: |
316 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | 295 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
317 | 296 | ||
318 | if (fp != NULL) { | ||
319 | fclose(fp); | ||
320 | } | ||
321 | if (result < 0) { | 297 | if (result < 0) { |
322 | if (surface) { | 298 | if (surface) { |
323 | for (i = 0; i < *frames; ++i) { | 299 | for (i = 0; i < *frames; ++i) { |
@@ -329,7 +305,50 @@ exit: | |||
329 | return result; | 305 | return result; |
330 | } | 306 | } |
331 | 307 | ||
332 | static int matches_locale(const char* loc) { | 308 | int res_create_alpha_surface(const char* name, gr_surface* pSurface) { |
309 | gr_surface surface = NULL; | ||
310 | int result = 0; | ||
311 | png_structp png_ptr = NULL; | ||
312 | png_infop info_ptr = NULL; | ||
313 | png_uint_32 width, height; | ||
314 | png_byte channels; | ||
315 | |||
316 | *pSurface = NULL; | ||
317 | |||
318 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); | ||
319 | if (result < 0) return result; | ||
320 | |||
321 | if (channels != 1) { | ||
322 | result = -7; | ||
323 | goto exit; | ||
324 | } | ||
325 | |||
326 | surface = malloc_surface(width * height); | ||
327 | if (surface == NULL) { | ||
328 | result = -8; | ||
329 | goto exit; | ||
330 | } | ||
331 | surface->width = width; | ||
332 | surface->height = height; | ||
333 | surface->row_bytes = width; | ||
334 | surface->pixel_bytes = 1; | ||
335 | |||
336 | unsigned char* p_row; | ||
337 | unsigned int y; | ||
338 | for (y = 0; y < height; ++y) { | ||
339 | p_row = surface->data + y * surface->row_bytes; | ||
340 | png_read_row(png_ptr, p_row, NULL); | ||
341 | } | ||
342 | |||
343 | *pSurface = surface; | ||
344 | |||
345 | exit: | ||
346 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||
347 | if (result < 0 && surface != NULL) free(surface); | ||
348 | return result; | ||
349 | } | ||
350 | |||
351 | static int matches_locale(const char* loc, const char* locale) { | ||
333 | if (locale == NULL) return 0; | 352 | if (locale == NULL) return 0; |
334 | 353 | ||
335 | if (strcmp(loc, locale) == 0) return 1; | 354 | if (strcmp(loc, locale) == 0) return 1; |
@@ -346,70 +365,35 @@ static int matches_locale(const char* loc) { | |||
346 | return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); | 365 | return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); |
347 | } | 366 | } |
348 | 367 | ||
349 | int res_create_localized_surface(const char* name, gr_surface* pSurface) { | 368 | int res_create_localized_alpha_surface(const char* name, |
350 | char resPath[256]; | 369 | const char* locale, |
370 | gr_surface* pSurface) { | ||
351 | gr_surface surface = NULL; | 371 | gr_surface surface = NULL; |
352 | int result = 0; | 372 | int result = 0; |
353 | unsigned char header[8]; | ||
354 | png_structp png_ptr = NULL; | 373 | png_structp png_ptr = NULL; |
355 | png_infop info_ptr = NULL; | 374 | png_infop info_ptr = NULL; |
375 | png_uint_32 width, height; | ||
376 | png_byte channels; | ||
356 | 377 | ||
357 | *pSurface = NULL; | 378 | *pSurface = NULL; |
358 | 379 | ||
359 | snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); | 380 | if (locale == NULL) { |
360 | resPath[sizeof(resPath)-1] = '\0'; | 381 | surface = malloc_surface(0); |
361 | FILE* fp = fopen(resPath, "rb"); | 382 | surface->width = 0; |
362 | if (fp == NULL) { | 383 | surface->height = 0; |
363 | result = -1; | 384 | surface->row_bytes = 0; |
364 | goto exit; | 385 | surface->pixel_bytes = 1; |
365 | } | ||
366 | |||
367 | size_t bytesRead = fread(header, 1, sizeof(header), fp); | ||
368 | if (bytesRead != sizeof(header)) { | ||
369 | result = -2; | ||
370 | goto exit; | ||
371 | } | ||
372 | |||
373 | if (png_sig_cmp(header, 0, sizeof(header))) { | ||
374 | result = -3; | ||
375 | goto exit; | ||
376 | } | ||
377 | |||
378 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | ||
379 | if (!png_ptr) { | ||
380 | result = -4; | ||
381 | goto exit; | ||
382 | } | ||
383 | |||
384 | info_ptr = png_create_info_struct(png_ptr); | ||
385 | if (!info_ptr) { | ||
386 | result = -5; | ||
387 | goto exit; | ||
388 | } | ||
389 | |||
390 | if (setjmp(png_jmpbuf(png_ptr))) { | ||
391 | result = -6; | ||
392 | goto exit; | 386 | goto exit; |
393 | } | 387 | } |
394 | 388 | ||
395 | png_init_io(png_ptr, fp); | 389 | result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); |
396 | png_set_sig_bytes(png_ptr, sizeof(header)); | 390 | if (result < 0) return result; |
397 | png_read_info(png_ptr, info_ptr); | ||
398 | |||
399 | int color_type, bit_depth; | ||
400 | png_uint_32 width, height; | ||
401 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, | ||
402 | &color_type, NULL, NULL, NULL); | ||
403 | int channels = png_get_channels(png_ptr, info_ptr); | ||
404 | 391 | ||
405 | if (!(bit_depth <= 8 && | 392 | if (channels != 1) { |
406 | (channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) { | 393 | result = -7; |
407 | return -7; | ||
408 | goto exit; | 394 | goto exit; |
409 | } | 395 | } |
410 | 396 | ||
411 | png_set_expand(png_ptr); | ||
412 | |||
413 | unsigned char* row = malloc(width); | 397 | unsigned char* row = malloc(width); |
414 | png_uint_32 y; | 398 | png_uint_32 y; |
415 | for (y = 0; y < height; ++y) { | 399 | for (y = 0; y < height; ++y) { |
@@ -419,7 +403,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { | |||
419 | int len = row[4]; | 403 | int len = row[4]; |
420 | char* loc = (char*)row+5; | 404 | char* loc = (char*)row+5; |
421 | 405 | ||
422 | if (y+1+h >= height || matches_locale(loc)) { | 406 | if (y+1+h >= height || matches_locale(loc, locale)) { |
423 | printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); | 407 | printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); |
424 | 408 | ||
425 | surface = malloc_surface(w*h); | 409 | surface = malloc_surface(w*h); |
@@ -427,8 +411,6 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { | |||
427 | result = -8; | 411 | result = -8; |
428 | goto exit; | 412 | goto exit; |
429 | } | 413 | } |
430 | unsigned char* pData = surface->data; | ||
431 | |||
432 | surface->width = w; | 414 | surface->width = w; |
433 | surface->height = h; | 415 | surface->height = h; |
434 | surface->row_bytes = w; | 416 | surface->row_bytes = w; |
@@ -437,7 +419,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { | |||
437 | int i; | 419 | int i; |
438 | for (i = 0; i < h; ++i, ++y) { | 420 | for (i = 0; i < h; ++i, ++y) { |
439 | png_read_row(png_ptr, row, NULL); | 421 | png_read_row(png_ptr, row, NULL); |
440 | memcpy(pData + i*w, row, w); | 422 | memcpy(surface->data + i*w, row, w); |
441 | } | 423 | } |
442 | 424 | ||
443 | *pSurface = (gr_surface) surface; | 425 | *pSurface = (gr_surface) surface; |
@@ -452,15 +434,7 @@ int res_create_localized_surface(const char* name, gr_surface* pSurface) { | |||
452 | 434 | ||
453 | exit: | 435 | exit: |
454 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | 436 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
455 | 437 | if (result < 0 && surface != NULL) free(surface); | |
456 | if (fp != NULL) { | ||
457 | fclose(fp); | ||
458 | } | ||
459 | if (result < 0) { | ||
460 | if (surface) { | ||
461 | free(surface); | ||
462 | } | ||
463 | } | ||
464 | return result; | 438 | return result; |
465 | } | 439 | } |
466 | 440 | ||
diff --git a/recovery.cpp b/recovery.cpp index 448f315b..e956ed71 100644 --- a/recovery.cpp +++ b/recovery.cpp | |||
@@ -974,8 +974,8 @@ main(int argc, char **argv) { | |||
974 | ui = device->GetUI(); | 974 | ui = device->GetUI(); |
975 | gCurrentUI = ui; | 975 | gCurrentUI = ui; |
976 | 976 | ||
977 | ui->Init(); | ||
978 | ui->SetLocale(locale); | 977 | ui->SetLocale(locale); |
978 | ui->Init(); | ||
979 | ui->SetBackground(RecoveryUI::NONE); | 979 | ui->SetBackground(RecoveryUI::NONE); |
980 | if (show_text) ui->ShowText(true); | 980 | if (show_text) ui->ShowText(true); |
981 | 981 | ||
diff --git a/screen_ui.cpp b/screen_ui.cpp index 589c935d..656f7244 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp | |||
@@ -52,6 +52,7 @@ static double now() { | |||
52 | ScreenRecoveryUI::ScreenRecoveryUI() : | 52 | ScreenRecoveryUI::ScreenRecoveryUI() : |
53 | currentIcon(NONE), | 53 | currentIcon(NONE), |
54 | installingFrame(0), | 54 | installingFrame(0), |
55 | locale(NULL), | ||
55 | rtl_locale(false), | 56 | rtl_locale(false), |
56 | progressBarType(EMPTY), | 57 | progressBarType(EMPTY), |
57 | progressScopeStart(0), | 58 | progressScopeStart(0), |
@@ -306,21 +307,21 @@ void ScreenRecoveryUI::progress_loop() { | |||
306 | } | 307 | } |
307 | 308 | ||
308 | void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) { | 309 | void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) { |
309 | int result = res_create_surface(filename, surface); | 310 | int result = res_create_display_surface(filename, surface); |
310 | if (result < 0) { | 311 | if (result < 0) { |
311 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); | 312 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); |
312 | } | 313 | } |
313 | } | 314 | } |
314 | 315 | ||
315 | void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, gr_surface** surface) { | 316 | void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, gr_surface** surface) { |
316 | int result = res_create_multi_surface(filename, frames, surface); | 317 | int result = res_create_multi_display_surface(filename, frames, surface); |
317 | if (result < 0) { | 318 | if (result < 0) { |
318 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); | 319 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); |
319 | } | 320 | } |
320 | } | 321 | } |
321 | 322 | ||
322 | void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, gr_surface* surface) { | 323 | void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, gr_surface* surface) { |
323 | int result = res_create_localized_surface(filename, surface); | 324 | int result = res_create_localized_alpha_surface(filename, locale, surface); |
324 | if (result < 0) { | 325 | if (result < 0) { |
325 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); | 326 | LOGE("missing bitmap %s\n(Code %d)\n", filename, result); |
326 | } | 327 | } |
@@ -360,8 +361,9 @@ void ScreenRecoveryUI::Init() | |||
360 | RecoveryUI::Init(); | 361 | RecoveryUI::Init(); |
361 | } | 362 | } |
362 | 363 | ||
363 | void ScreenRecoveryUI::SetLocale(const char* locale) { | 364 | void ScreenRecoveryUI::SetLocale(const char* new_locale) { |
364 | if (locale) { | 365 | if (new_locale) { |
366 | this->locale = new_locale; | ||
365 | char* lang = strdup(locale); | 367 | char* lang = strdup(locale); |
366 | for (char* p = lang; *p; ++p) { | 368 | for (char* p = lang; *p; ++p) { |
367 | if (*p == '_') { | 369 | if (*p == '_') { |
@@ -380,6 +382,8 @@ void ScreenRecoveryUI::SetLocale(const char* locale) { | |||
380 | rtl_locale = true; | 382 | rtl_locale = true; |
381 | } | 383 | } |
382 | free(lang); | 384 | free(lang); |
385 | } else { | ||
386 | new_locale = NULL; | ||
383 | } | 387 | } |
384 | } | 388 | } |
385 | 389 | ||
diff --git a/screen_ui.h b/screen_ui.h index ada006d1..14b91385 100644 --- a/screen_ui.h +++ b/screen_ui.h | |||
@@ -64,6 +64,7 @@ class ScreenRecoveryUI : public RecoveryUI { | |||
64 | private: | 64 | private: |
65 | Icon currentIcon; | 65 | Icon currentIcon; |
66 | int installingFrame; | 66 | int installingFrame; |
67 | const char* locale; | ||
67 | bool rtl_locale; | 68 | bool rtl_locale; |
68 | 69 | ||
69 | pthread_mutex_t updateMutex; | 70 | pthread_mutex_t updateMutex; |