diff options
Diffstat (limited to 'widget/gonk/libdisplay/BootAnimation.cpp')
-rw-r--r-- | widget/gonk/libdisplay/BootAnimation.cpp | 726 |
1 files changed, 0 insertions, 726 deletions
diff --git a/widget/gonk/libdisplay/BootAnimation.cpp b/widget/gonk/libdisplay/BootAnimation.cpp deleted file mode 100644 index c275179fc..000000000 --- a/widget/gonk/libdisplay/BootAnimation.cpp +++ /dev/null @@ -1,726 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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 <algorithm> -#include <endian.h> -#include <fcntl.h> -#include <pthread.h> -#include <string> -#include <sys/mman.h> -#include <sys/stat.h> -#include <vector> -#include "mozilla/FileUtils.h" -#include "png.h" - -#include "android/log.h" -#include "GonkDisplay.h" -#include "hardware/gralloc.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) - -using namespace mozilla; -using namespace std; - -static pthread_t sAnimationThread; -static bool sRunAnimation; - -/* See http://www.pkware.com/documents/casestudies/APPNOTE.TXT */ -struct local_file_header { - uint32_t signature; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(uncompressed_size); - } - - uint32_t GetSize() const - { - /* XXX account for data descriptor */ - return sizeof(local_file_header) + letoh16(filename_size) + - letoh16(extra_field_size) + GetDataSize(); - } - - const char * GetData() const - { - return data + letoh16(filename_size) + letoh16(extra_field_size); - } -} __attribute__((__packed__)); - -struct data_descriptor { - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; -} __attribute__((__packed__)); - -struct cdir_entry { - uint32_t signature; - uint16_t creator_version; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - uint16_t file_comment_size; - uint16_t disk_num; - uint16_t internal_attr; - uint32_t external_attr; - uint32_t offset; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(compressed_size); - } - - uint32_t GetSize() const - { - return sizeof(cdir_entry) + letoh16(filename_size) + - letoh16(extra_field_size) + letoh16(file_comment_size); - } - - bool Valid() const - { - return signature == htole32(0x02014b50); - } -} __attribute__((__packed__)); - -struct cdir_end { - uint32_t signature; - uint16_t disk_num; - uint16_t cdir_disk; - uint16_t disk_entries; - uint16_t cdir_entries; - uint32_t cdir_size; - uint32_t cdir_offset; - uint16_t comment_size; - char comment[0]; - - bool Valid() const - { - return signature == htole32(0x06054b50); - } -} __attribute__((__packed__)); - -/* We don't have access to libjar and the zip reader in android - * doesn't quite fit what we want to do. */ -class ZipReader { - const char *mBuf; - const cdir_end *mEnd; - const char *mCdir_limit; - uint32_t mBuflen; - -public: - ZipReader() : mBuf(nullptr) {} - ~ZipReader() { - if (mBuf) - munmap((void *)mBuf, mBuflen); - } - - bool OpenArchive(const char *path) - { - int fd; - do { - fd = open(path, O_RDONLY); - } while (fd == -1 && errno == EINTR); - if (fd == -1) - return false; - - struct stat sb; - if (fstat(fd, &sb) == -1 || sb.st_size < sizeof(cdir_end)) { - close(fd); - return false; - } - - mBuflen = sb.st_size; - mBuf = (char *)mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - - if (!mBuf) { - return false; - } - - madvise(mBuf, sb.st_size, MADV_SEQUENTIAL); - - mEnd = (cdir_end *)(mBuf + mBuflen - sizeof(cdir_end)); - while (!mEnd->Valid() && - (char *)mEnd > mBuf) { - mEnd = (cdir_end *)((char *)mEnd - 1); - } - - mCdir_limit = mBuf + letoh32(mEnd->cdir_offset) + letoh32(mEnd->cdir_size); - - if (!mEnd->Valid() || mCdir_limit > (char *)mEnd) { - munmap((void *)mBuf, mBuflen); - mBuf = nullptr; - return false; - } - - return true; - } - - /* Pass null to get the first cdir entry */ - const cdir_entry * GetNextEntry(const cdir_entry *prev) - { - const cdir_entry *entry; - if (prev) - entry = (cdir_entry *)((char *)prev + prev->GetSize()); - else - entry = (cdir_entry *)(mBuf + letoh32(mEnd->cdir_offset)); - - if (((char *)entry + entry->GetSize()) > mCdir_limit || - !entry->Valid()) - return nullptr; - return entry; - } - - string GetEntryName(const cdir_entry *entry) - { - uint16_t len = letoh16(entry->filename_size); - - string name; - name.append(entry->data, len); - return name; - } - - const local_file_header * GetLocalEntry(const cdir_entry *entry) - { - const local_file_header * data = - (local_file_header *)(mBuf + letoh32(entry->offset)); - if (((char *)data + data->GetSize()) > (char *)mEnd) - return nullptr; - return data; - } -}; - -struct AnimationFrame { - char path[256]; - png_color_16 bgcolor; - char *buf; - const local_file_header *file; - uint32_t width; - uint32_t height; - uint16_t bytepp; - bool has_bgcolor; - - AnimationFrame() : buf(nullptr) {} - AnimationFrame(const AnimationFrame &frame) : buf(nullptr) { - strncpy(path, frame.path, sizeof(path)); - file = frame.file; - } - ~AnimationFrame() - { - if (buf) - free(buf); - } - - bool operator<(const AnimationFrame &other) const - { - return strcmp(path, other.path) < 0; - } - - void ReadPngFrame(int outputFormat); -}; - -struct AnimationPart { - int32_t count; - int32_t pause; - // If you alter the size of the path, change ReadFromString() as well. - char path[256]; - vector<AnimationFrame> frames; - - bool - ReadFromString(const char* aLine) - { - MOZ_ASSERT(aLine); - // this 255 value must be in sync with AnimationPart::path. - return sscanf(aLine, "p %d %d %255s", &count, &pause, path) == 3; - } -}; - -struct RawReadState { - const char *start; - uint32_t offset; - uint32_t length; -}; - -static void -RawReader(png_structp png_ptr, png_bytep data, png_size_t length) -{ - RawReadState *state = (RawReadState *)png_get_io_ptr(png_ptr); - if (length > (state->length - state->offset)) - png_error(png_ptr, "PNG read overrun"); - - memcpy(data, state->start + state->offset, length); - state->offset += length; -} - -static void -TransformTo565(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - uint16_t *outbuf = (uint16_t *)data; - uint8_t *inbuf = (uint8_t *)data; - for (uint32_t i = 0; i < row_info->rowbytes; i += 3) { - *outbuf++ = ((inbuf[i] & 0xF8) << 8) | - ((inbuf[i + 1] & 0xFC) << 3) | - ((inbuf[i + 2] ) >> 3); - } -} - -static uint16_t -GetFormatBPP(int aFormat) -{ - uint16_t bpp = 0; - - switch (aFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - bpp = 4; - break; - case HAL_PIXEL_FORMAT_RGB_888: - bpp = 3; - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", aFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - bpp = 2; - break; - } - - return bpp; -} - -void -AnimationFrame::ReadPngFrame(int outputFormat) -{ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - static const png_byte unused_chunks[] = - { 99, 72, 82, 77, '\0', /* cHRM */ - 104, 73, 83, 84, '\0', /* hIST */ - 105, 67, 67, 80, '\0', /* iCCP */ - 105, 84, 88, 116, '\0', /* iTXt */ - 111, 70, 70, 115, '\0', /* oFFs */ - 112, 67, 65, 76, '\0', /* pCAL */ - 115, 67, 65, 76, '\0', /* sCAL */ - 112, 72, 89, 115, '\0', /* pHYs */ - 115, 66, 73, 84, '\0', /* sBIT */ - 115, 80, 76, 84, '\0', /* sPLT */ - 116, 69, 88, 116, '\0', /* tEXt */ - 116, 73, 77, 69, '\0', /* tIME */ - 122, 84, 88, 116, '\0'}; /* zTXt */ - static const png_byte tRNS_chunk[] = - {116, 82, 78, 83, '\0'}; /* tRNS */ -#endif - - png_structp pngread = png_create_read_struct(PNG_LIBPNG_VER_STRING, - nullptr, nullptr, nullptr); - - if (!pngread) - return; - - png_infop pnginfo = png_create_info_struct(pngread); - - if (!pnginfo) { - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - if (setjmp(png_jmpbuf(pngread))) { - // libpng reported an error and longjumped here. Clean up and return. - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - RawReadState state; - state.start = file->GetData(); - state.length = file->GetDataSize(); - state.offset = 0; - - png_set_read_fn(pngread, &state, RawReader); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - /* Ignore unused chunks */ - png_set_keep_unknown_chunks(pngread, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - - /* Ignore the tRNS chunk if we only want opaque output */ - if (outputFormat == HAL_PIXEL_FORMAT_RGB_888 || - outputFormat == HAL_PIXEL_FORMAT_RGB_565) { - png_set_keep_unknown_chunks(pngread, 1, tRNS_chunk, 1); - } -#endif - - png_read_info(pngread, pnginfo); - - png_color_16p colorp; - has_bgcolor = (PNG_INFO_bKGD == png_get_bKGD(pngread, pnginfo, &colorp)); - bgcolor = has_bgcolor ? *colorp : png_color_16(); - width = png_get_image_width(pngread, pnginfo); - height = png_get_image_height(pngread, pnginfo); - - LOG("Decoded %s: %d x %d frame with bgcolor? %s (%#x, %#x, %#x; gray:%#x)", - path, width, height, has_bgcolor ? "yes" : "no", - bgcolor.red, bgcolor.green, bgcolor.blue, bgcolor.gray); - - bytepp = GetFormatBPP(outputFormat); - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - png_set_bgr(pngread); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - png_set_filler(pngread, 0xFF, PNG_FILLER_AFTER); - break; - case HAL_PIXEL_FORMAT_RGB_888: - png_set_strip_alpha(pngread); - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", outputFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - png_set_strip_alpha(pngread); - png_set_read_user_transform_fn(pngread, TransformTo565); - break; - } - - // An extra row is added to give libpng enough space when - // decoding 3/4 bytepp inputs for 2 bytepp output surfaces - buf = (char *)malloc(width * (height + 1) * bytepp); - - vector<char *> rows(height + 1); - uint32_t stride = width * bytepp; - for (uint32_t i = 0; i < height; i++) { - rows[i] = buf + (stride * i); - } - rows[height] = nullptr; - png_set_strip_16(pngread); - png_set_palette_to_rgb(pngread); - png_set_gray_to_rgb(pngread); - png_read_image(pngread, (png_bytepp)&rows.front()); - png_destroy_read_struct(&pngread, &pnginfo, nullptr); -} - -/** - * Return a wchar_t that when used to |wmemset()| an image buffer will - * fill it with the color defined by |color16|. The packed wchar_t - * may comprise one or two pixels depending on |outputFormat|. - */ -static wchar_t -AsBackgroundFill(const png_color_16& color16, int outputFormat) -{ - static_assert(sizeof(wchar_t) == sizeof(uint32_t), - "TODO: support 2-byte wchar_t"); - union { - uint32_t r8g8b8; - struct { - uint8_t b8; - uint8_t g8; - uint8_t r8; - uint8_t x8; - }; - } color; - color.b8 = color16.blue; - color.g8 = color16.green; - color.r8 = color16.red; - color.x8 = 0xFF; - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_BGRA_8888: - swap(color.r8, color.b8); - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_RGB_565: { - // NB: we could do a higher-quality downsample here, but we - // want the results to be a pixel-perfect match with the fast - // downsample in TransformTo565(). - uint16_t color565 = ((color.r8 & 0xF8) << 8) | - ((color.g8 & 0xFC) << 3) | - ((color.b8 ) >> 3); - return (color565 << 16) | color565; - } - default: - LOGW("Unhandled pixel format %d; falling back on black", outputFormat); - return 0; - } -} - -void -ShowSolidColorFrame(GonkDisplay *aDisplay, - const gralloc_module_t *grallocModule, - int32_t aFormat) -{ - LOGW("Show solid color frame for bootAnim"); - - ANativeWindowBuffer *buffer = aDisplay->DequeueBuffer(); - void *mappedAddress = nullptr; - - if (!buffer) { - LOGW("Failed to get an ANativeWindowBuffer"); - return; - } - - if (!grallocModule->lock(grallocModule, buffer->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, buffer->width, buffer->height, &mappedAddress)) { - // Just show a black solid color frame. - memset(mappedAddress, 0, buffer->height * buffer->stride * GetFormatBPP(aFormat)); - grallocModule->unlock(grallocModule, buffer->handle); - } - - aDisplay->QueueBuffer(buffer); -} - -static void * -AnimationThread(void *) -{ - GonkDisplay *display = GetGonkDisplay(); - int32_t format = display->surfaceformat; - - const hw_module_t *module = nullptr; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) { - LOGW("Could not get gralloc module"); - return nullptr; - } - const gralloc_module_t *grmodule = - reinterpret_cast<gralloc_module_t const*>(module); - - ZipReader reader; - if (!reader.OpenArchive("/system/media/bootanimation.zip")) { - LOGW("Could not open boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - const cdir_entry *entry = nullptr; - const local_file_header *file = nullptr; - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (!name.compare("desc.txt")) { - file = reader.GetLocalEntry(entry); - break; - } - } - - if (!file) { - LOGW("Could not find desc.txt in boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - string descCopy; - descCopy.append(file->GetData(), entry->GetDataSize()); - int32_t width, height, fps; - const char *line = descCopy.c_str(); - const char *end; - bool headerRead = true; - vector<AnimationPart> parts; - bool animPlayed = false; - - /* - * bootanimation.zip - * - * This is the boot animation file format that Android uses. - * It's a zip file with a directories containing png frames - * and a desc.txt that describes how they should be played. - * - * desc.txt contains two types of lines - * 1. [width] [height] [fps] - * There is one of these lines per bootanimation. - * If the width and height are smaller than the screen, - * the frames are centered on a black background. - * XXX: Currently we stretch instead of centering the frame. - * 2. p [count] [pause] [path] - * This describes one animation part. - * Each animation part is played in sequence. - * An animation part contains all the files/frames in the - * directory specified in [path] - * [count] indicates the number of times this part repeats. - * [pause] indicates the number of frames that this part - * should pause for after playing the full sequence but - * before repeating. - */ - - do { - end = strstr(line, "\n"); - - AnimationPart part; - if (headerRead && - sscanf(line, "%d %d %d", &width, &height, &fps) == 3) { - headerRead = false; - } else if (part.ReadFromString(line)) { - parts.push_back(part); - } - } while (end && *(line = end + 1)); - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - entry = nullptr; - char search[256]; - snprintf(search, sizeof(search), "%s/", part.path); - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (name.find(search) || - !entry->GetDataSize() || - name.length() >= 256) - continue; - - part.frames.resize(part.frames.size() + 1); - AnimationFrame &frame = part.frames.back(); - strcpy(frame.path, name.c_str()); - frame.file = reader.GetLocalEntry(entry); - } - - sort(part.frames.begin(), part.frames.end()); - } - - long int frameDelayUs = 1000000 / fps; - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - - int32_t j = 0; - while (sRunAnimation && (!part.count || j++ < part.count)) { - for (uint32_t k = 0; k < part.frames.size(); k++) { - struct timeval tv1, tv2; - gettimeofday(&tv1, nullptr); - AnimationFrame &frame = part.frames[k]; - if (!frame.buf) { - frame.ReadPngFrame(format); - } - - ANativeWindowBuffer *buf = display->DequeueBuffer(); - if (!buf) { - LOGW("Failed to get an ANativeWindowBuffer"); - break; - } - - void *vaddr; - if (grmodule->lock(grmodule, buf->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, width, height, &vaddr)) { - LOGW("Failed to lock buffer_handle_t"); - display->QueueBuffer(buf); - break; - } - - if (frame.has_bgcolor) { - wchar_t bgfill = AsBackgroundFill(frame.bgcolor, format); - wmemset((wchar_t*)vaddr, bgfill, - (buf->height * buf->stride * frame.bytepp) / sizeof(wchar_t)); - } - - if ((uint32_t)buf->height == frame.height && (uint32_t)buf->stride == frame.width) { - memcpy(vaddr, frame.buf, - frame.width * frame.height * frame.bytepp); - } else if ((uint32_t)buf->height >= frame.height && - (uint32_t)buf->width >= frame.width) { - int startx = (buf->width - frame.width) / 2; - int starty = (buf->height - frame.height) / 2; - - int src_stride = frame.width * frame.bytepp; - int dst_stride = buf->stride * frame.bytepp; - - char *src = frame.buf; - char *dst = (char *) vaddr + starty * dst_stride + startx * frame.bytepp; - - for (uint32_t i = 0; i < frame.height; i++) { - memcpy(dst, src, src_stride); - src += src_stride; - dst += dst_stride; - } - } - grmodule->unlock(grmodule, buf->handle); - - gettimeofday(&tv2, nullptr); - - timersub(&tv2, &tv1, &tv2); - - if (tv2.tv_usec < frameDelayUs) { - usleep(frameDelayUs - tv2.tv_usec); - } else { - LOGW("Frame delay is %ld us but decoding took %ld us", - frameDelayUs, tv2.tv_usec); - } - - animPlayed = true; - display->QueueBuffer(buf); - - if (part.count && j >= part.count) { - free(frame.buf); - frame.buf = nullptr; - } - } - usleep(frameDelayUs * part.pause); - } - } - - if (!animPlayed) { - ShowSolidColorFrame(display, grmodule, format); - } - - return nullptr; -} - -namespace mozilla { - -__attribute__ ((visibility ("default"))) -void -StartBootAnimation() -{ - GetGonkDisplay(); // Ensure GonkDisplay exist - sRunAnimation = true; - pthread_create(&sAnimationThread, nullptr, AnimationThread, nullptr); -} - -__attribute__ ((visibility ("default"))) -void -StopBootAnimation() -{ - if (sRunAnimation) { - sRunAnimation = false; - pthread_join(sAnimationThread, nullptr); - GetGonkDisplay()->NotifyBootAnimationStopped(); - } -} - -} // namespace mozilla |