/* * Copyright (C) Texas Instruments - http://www.ti.com/ * * 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 #include #include #include #include #include #include #include #include #include "hwc_dev.h" #include "dock_image.h" static struct dock_image_state { void *buffer; /* start of fb for hdmi */ uint32_t buffer_size; /* size of fb for hdmi */ uint32_t max_width; uint32_t max_height; image_info_t image; } dock_image; static void free_png_image(image_info_t *img) { memset(img, 0, sizeof(*img)); } static int load_png_image(char *path, image_info_t *img) { void *ptr = NULL; png_bytepp row_pointers = NULL; FILE *fd = fopen(path, "rb"); if (!fd) { ALOGE("failed to open PNG file %s: (%d)", path, errno); return -EINVAL; } const int SIZE_PNG_HEADER = 8; uint8_t header[SIZE_PNG_HEADER]; fread(header, 1, SIZE_PNG_HEADER, fd); if (png_sig_cmp(header, 0, SIZE_PNG_HEADER)) { ALOGE("%s is not a PNG file", path); goto fail; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto fail_alloc; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto fail_alloc; if (setjmp(png_jmpbuf(png_ptr))) goto fail_alloc; png_init_io(png_ptr, fd); png_set_sig_bytes(png_ptr, SIZE_PNG_HEADER); png_set_user_limits(png_ptr, dock_image.max_width, dock_image.max_height); png_read_info(png_ptr, info_ptr); uint8_t bit_depth = png_get_bit_depth(png_ptr, info_ptr); uint32_t width = png_get_image_width(png_ptr, info_ptr); uint32_t height = png_get_image_height(png_ptr, info_ptr); uint8_t color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 128, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY: if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); } else { png_set_filler(png_ptr, 128, PNG_FILLER_AFTER); } /* fall through */ case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB: png_set_filler(png_ptr, 128, PNG_FILLER_AFTER); /* fall through */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_bgr(png_ptr); break; default: ALOGE("unsupported PNG color: %x", color_type); goto fail_alloc; } if (bit_depth == 16) png_set_strip_16(png_ptr); const uint32_t bpp = 4; img->size = ALIGN(width * height * bpp, 4096); if ((uint32_t)img->size > dock_image.buffer_size) { ALOGE("image does not fit into framebuffer area (%d > %d)", img->size, dock_image.buffer_size); goto fail_alloc; } img->ptr = dock_image.buffer; row_pointers = calloc(height, sizeof(*row_pointers)); if (!row_pointers) { ALOGE("failed to allocate row pointers"); goto fail_alloc; } uint32_t i; for (i = 0; i < height; i++) row_pointers[i] = img->ptr + i * width * bpp; png_set_rows(png_ptr, info_ptr, row_pointers); png_read_update_info(png_ptr, info_ptr); img->rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); free(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fd); img->width = width; img->height = height; return 0; fail_alloc: free_png_image(img); free(row_pointers); if (!png_ptr || !info_ptr) ALOGE("failed to allocate PNG structures"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fail: fclose(fd); return -EINVAL; } int init_dock_image(omap_hwc_device_t *hwc_dev, uint32_t max_width, uint32_t max_height) { int err = 0; struct fb_fix_screeninfo fix; if (ioctl(hwc_dev->fb_fd, FBIOGET_FSCREENINFO, &fix)) { ALOGE("failed to get fb info (%d)", errno); err = -errno; goto done; } dock_image.buffer_size = fix.smem_len; dock_image.buffer = mmap(NULL, fix.smem_len, PROT_WRITE, MAP_SHARED, hwc_dev->fb_fd, 0); if (dock_image.buffer == MAP_FAILED) { ALOGE("failed to map fb memory"); err = -errno; goto done; } dock_image.max_width = max_width; dock_image.max_height = max_height; done: return err; } void load_dock_image() { if (!dock_image.image.rowbytes) { char value[PROPERTY_VALUE_MAX]; property_get("persist.hwc.dock_image", value, "/vendor/res/images/dock/dock.png"); load_png_image(value, &dock_image.image); } } image_info_t *get_dock_image() { return &dock_image.image; }