Home | History | Annotate | Download | only in minui
      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.
     42 double pow(double x, double y) {
     43     return x * y;
     44 }
     45 
     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 
    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 
    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 
    319 void res_free_surface(gr_surface surface) {
    320     GGLSurface* pSurface = (GGLSurface*) surface;
    321     if (pSurface) {
    322         free(pSurface);
    323     }
    324 }
    325