Files
android_bootable_recovery/minui/resources.c
T
Doug Zongker 39cf417e17 remove pixelflinger from recovery
Recovery now draws directly to the framebuffer by rolling its own
graphics code, rather than depending on libpixelflinger.

The recovery UI is modified slightly to eliminate operations that are
slow with the software implementation: when the text display / menu is
turned on, it now appears on a black background instead of a dimmed
version of the recovery icon.

There's probably substantial room for optimization of the graphics
operations.

Bug: 12131110
Change-Id: Iab6520e0a7aaec39e2ce39377c10aef82ae0c595
2014-03-11 11:10:00 -07:00

470 lines
12 KiB
C

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <png.h>
#include "minui.h"
extern char* locale;
#define SURFACE_DATA_ALIGNMENT 8
static gr_surface malloc_surface(size_t data_size) {
unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);
if (temp == NULL) return NULL;
gr_surface surface = (gr_surface) temp;
surface->data = temp + sizeof(GRSurface) +
(SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
return surface;
}
int res_create_surface(const char* name, gr_surface* pSurface) {
char resPath[256];
gr_surface surface = NULL;
int result = 0;
unsigned char header[8];
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
*pSurface = NULL;
snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
resPath[sizeof(resPath)-1] = '\0';
FILE* fp = fopen(resPath, "rb");
if (fp == NULL) {
result = -1;
goto exit;
}
size_t bytesRead = fread(header, 1, sizeof(header), fp);
if (bytesRead != sizeof(header)) {
result = -2;
goto exit;
}
if (png_sig_cmp(header, 0, sizeof(header))) {
result = -3;
goto exit;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
result = -4;
goto exit;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
result = -5;
goto exit;
}
if (setjmp(png_jmpbuf(png_ptr))) {
result = -6;
goto exit;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, sizeof(header));
png_read_info(png_ptr, info_ptr);
int color_type, bit_depth;
size_t width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
&color_type, NULL, NULL, NULL);
int channels = png_get_channels(png_ptr, info_ptr);
if (!(bit_depth <= 8 &&
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
(channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
color_type == PNG_COLOR_TYPE_GRAY))))) {
return -7;
goto exit;
}
size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
surface = malloc_surface(stride * height);
if (surface == NULL) {
result = -8;
goto exit;
}
unsigned char* pData = surface->data;
surface->width = width;
surface->height = height;
surface->row_bytes = stride;
surface->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4);
int alpha = (channels == 4);
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY) {
alpha = 1;
}
unsigned int y;
if (channels == 3 || (channels == 1 && !alpha)) {
for (y = 0; y < height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
int x;
for(x = width - 1; x >= 0; x--) {
int sx = x * 3;
int dx = x * 4;
unsigned char r = pRow[sx];
unsigned char g = pRow[sx + 1];
unsigned char b = pRow[sx + 2];
unsigned char a = 0xff;
pRow[dx ] = r; // r
pRow[dx + 1] = g; // g
pRow[dx + 2] = b; // b
pRow[dx + 3] = a;
}
}
} else {
for (y = 0; y < height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
}
}
*pSurface = (gr_surface) surface;
exit:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (fp != NULL) {
fclose(fp);
}
if (result < 0) {
if (surface) {
free(surface);
}
}
return result;
}
int res_create_multi_surface(const char* name, int* frames, gr_surface** pSurface) {
char resPath[256];
int result = 0;
unsigned char header[8];
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
int i;
gr_surface* surface = NULL;
*pSurface = NULL;
*frames = -1;
snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
resPath[sizeof(resPath)-1] = '\0';
FILE* fp = fopen(resPath, "rb");
if (fp == NULL) {
result = -1;
goto exit;
}
size_t bytesRead = fread(header, 1, sizeof(header), fp);
if (bytesRead != sizeof(header)) {
result = -2;
goto exit;
}
if (png_sig_cmp(header, 0, sizeof(header))) {
result = -3;
goto exit;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
result = -4;
goto exit;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
result = -5;
goto exit;
}
if (setjmp(png_jmpbuf(png_ptr))) {
result = -6;
goto exit;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, sizeof(header));
png_read_info(png_ptr, info_ptr);
int color_type, bit_depth;
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
&color_type, NULL, NULL, NULL);
int channels = png_get_channels(png_ptr, info_ptr);
if (!(bit_depth <= 8 &&
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
(channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
color_type == PNG_COLOR_TYPE_GRAY))))) {
return -7;
goto exit;
}
*frames = 1;
png_textp text;
int num_text;
if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
for (i = 0; i < num_text; ++i) {
if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
*frames = atoi(text[i].text);
break;
}
}
printf(" found frames = %d\n", *frames);
}
if (height % *frames != 0) {
printf("bad height (%d) for frame count (%d)\n", height, *frames);
result = -9;
goto exit;
}
size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
size_t pixelSize = stride * height / *frames;
surface = malloc(*frames * sizeof(gr_surface));
if (surface == NULL) {
result = -8;
goto exit;
}
for (i = 0; i < *frames; ++i) {
surface[i] = malloc_surface(pixelSize);
surface[i]->width = width;
surface[i]->height = height / *frames;
surface[i]->row_bytes = stride;
surface[i]->pixel_bytes = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4);
}
int alpha = (channels == 4);
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY) {
alpha = 1;
}
png_uint_32 y;
if (channels == 3 || (channels == 1 && !alpha)) {
for (y = 0; y < height; ++y) {
int fy = y / *frames;
int fr = y % *frames;
unsigned char* pRow = surface[fr]->data + fy * stride;
png_read_row(png_ptr, pRow, NULL);
int x;
for(x = width - 1; x >= 0; x--) {
int sx = x * 3;
int dx = x * 4;
unsigned char r = pRow[sx];
unsigned char g = pRow[sx + 1];
unsigned char b = pRow[sx + 2];
unsigned char a = 0xff;
pRow[dx ] = r; // r
pRow[dx + 1] = g; // g
pRow[dx + 2] = b; // b
pRow[dx + 3] = a;
}
}
} else {
for (y = 0; y < height; ++y) {
int fy = y / *frames;
int fr = y % *frames;
unsigned char* pRow = surface[fr]->data + fy * stride;
png_read_row(png_ptr, pRow, NULL);
}
}
*pSurface = (gr_surface*) surface;
exit:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (fp != NULL) {
fclose(fp);
}
if (result < 0) {
if (surface) {
for (i = 0; i < *frames; ++i) {
if (surface[i]) free(surface[i]);
}
free(surface);
}
}
return result;
}
static int matches_locale(const char* loc) {
if (locale == NULL) return 0;
if (strcmp(loc, locale) == 0) return 1;
// if loc does *not* have an underscore, and it matches the start
// of locale, and the next character in locale *is* an underscore,
// that's a match. For instance, loc == "en" matches locale ==
// "en_US".
int i;
for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
if (loc[i] == '_') return 0;
return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
}
int res_create_localized_surface(const char* name, gr_surface* pSurface) {
char resPath[256];
gr_surface surface = NULL;
int result = 0;
unsigned char header[8];
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
*pSurface = NULL;
snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
resPath[sizeof(resPath)-1] = '\0';
FILE* fp = fopen(resPath, "rb");
if (fp == NULL) {
result = -1;
goto exit;
}
size_t bytesRead = fread(header, 1, sizeof(header), fp);
if (bytesRead != sizeof(header)) {
result = -2;
goto exit;
}
if (png_sig_cmp(header, 0, sizeof(header))) {
result = -3;
goto exit;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
result = -4;
goto exit;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
result = -5;
goto exit;
}
if (setjmp(png_jmpbuf(png_ptr))) {
result = -6;
goto exit;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, sizeof(header));
png_read_info(png_ptr, info_ptr);
int color_type, bit_depth;
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
&color_type, NULL, NULL, NULL);
int channels = png_get_channels(png_ptr, info_ptr);
if (!(bit_depth <= 8 &&
(channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) {
return -7;
goto exit;
}
png_set_expand(png_ptr);
unsigned char* row = malloc(width);
png_uint_32 y;
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, row, NULL);
int w = (row[1] << 8) | row[0];
int h = (row[3] << 8) | row[2];
int len = row[4];
char* loc = (char*)row+5;
if (y+1+h >= height || matches_locale(loc)) {
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
surface = malloc_surface(w*h);
if (surface == NULL) {
result = -8;
goto exit;
}
unsigned char* pData = surface->data;
surface->width = w;
surface->height = h;
surface->row_bytes = w;
surface->pixel_bytes = 1;
int i;
for (i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row, NULL);
memcpy(pData + i*w, row, w);
}
*pSurface = (gr_surface) surface;
break;
} else {
int i;
for (i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row, NULL);
}
}
}
exit:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (fp != NULL) {
fclose(fp);
}
if (result < 0) {
if (surface) {
free(surface);
}
}
return result;
}
void res_free_surface(gr_surface surface) {
free(surface);
}