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     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 
    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 
    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 
    315 void res_free_surface(gr_surface surface) {
    316     GGLSurface* pSurface = (GGLSurface*) surface;
    317     if (pSurface) {
    318         free(pSurface);
    319     }
    320 }
    321