From 92a50c838d8ca2ae4027fd77b71db12fb52d86e3 Mon Sep 17 00:00:00 2001 From: "chaos.proton@gmail.com" Date: Fri, 20 Jul 2012 12:37:56 +0000 Subject: sync with RTGUI c074ff2898b9e Full log is in GitHub. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2222 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- components/rtgui/common/blit.c | 66 ++ components/rtgui/common/dc.c | 4 +- components/rtgui/common/dc_client.c | 6 +- components/rtgui/common/dc_hw.c | 6 +- components/rtgui/common/framebuffer_driver.c | 7 +- components/rtgui/common/image.c | 5 +- components/rtgui/common/image_bmp.c | 1291 +++++++++++++++----------- components/rtgui/common/image_jpg.c | 479 ++++++++++ components/rtgui/common/image_png.c | 56 +- components/rtgui/common/pixel_driver.c | 55 +- components/rtgui/common/rtgui_app.c | 380 ++++++++ components/rtgui/common/rtgui_system.c | 419 ++++++++- 12 files changed, 2192 insertions(+), 582 deletions(-) create mode 100644 components/rtgui/common/rtgui_app.c (limited to 'components/rtgui/common') diff --git a/components/rtgui/common/blit.c b/components/rtgui/common/blit.c index a9b0b36749..1d84fc3a00 100644 --- a/components/rtgui/common/blit.c +++ b/components/rtgui/common/blit.c @@ -1,3 +1,9 @@ +/* + * Change Logs: + * Date Author Notes + * 2012-01-24 onelife add one more blit table which exchanges the + * positions of R and B color components in output + */ #include #include @@ -305,3 +311,63 @@ rtgui_blit_line_func rtgui_blit_line_get(int dst_bpp, int src_bpp) return _blit_table[dst_bpp][src_bpp]; } + + +static void rtgui_blit_line_3_2_inv(rt_uint8_t* dst_ptr, rt_uint8_t* src_ptr, int line) +{ + rt_uint16_t* dst; + + dst = (rt_uint16_t*)dst_ptr; + line = line / 3; + while (line) + { + *dst = (((*src_ptr << 8) & 0x0000F800) | + ((*(src_ptr + 1) << 3) & 0x000007E0) | + ((*(src_ptr + 2) >> 3) & 0x0000001F)); + + src_ptr += 3; + dst ++; + line --; + } + + return; +} + +void rtgui_blit_line_2_2_inv(rt_uint8_t* dst_ptr, rt_uint8_t* src_ptr, int line) +{ + rt_uint16_t *dst, *src; + + dst = (rt_uint16_t *)dst_ptr; + src = (rt_uint16_t *)src_ptr; + line = line / 2; + while (line) + { + *dst = ((*src << 11) & 0xF800) | (*src & 0x07E0) | ((*src >> 11) & 0x001F); + src ++; + dst ++; + line --; + } +} + +static const rtgui_blit_line_func _blit_table_inv[5][5] = +{ + /* 0_0, 1_0, 2_0, 3_0, 4_0 */ + {RT_NULL, RT_NULL, RT_NULL, RT_NULL, RT_NULL }, + /* 0_1, 1_1, 2_1, 3_1, 4_1 */ + {RT_NULL, rtgui_blit_line_direct, rtgui_blit_line_2_1, rtgui_blit_line_3_1, rtgui_blit_line_4_1 }, + /* 0_2, 1_2, 2_2, 3_2, 4_2 */ + {RT_NULL, rtgui_blit_line_1_2, rtgui_blit_line_2_2_inv, rtgui_blit_line_3_2_inv, rtgui_blit_line_4_2 }, + /* 0_3, 1_3, 2_3, 3_3, 4_3 */ + {RT_NULL, rtgui_blit_line_1_3, rtgui_blit_line_2_3, rtgui_blit_line_direct, rtgui_blit_line_4_3 }, + /* 0_4, 1_4, 2_4, 3_4, 4_4 */ + {RT_NULL, rtgui_blit_line_1_4, rtgui_blit_line_2_4, rtgui_blit_line_3_4, rtgui_blit_line_direct }, +}; + +rtgui_blit_line_func rtgui_blit_line_get_inv(int dst_bpp, int src_bpp) +{ + RT_ASSERT(dst_bpp>0 && dst_bpp < 5); + RT_ASSERT(src_bpp>0 && src_bpp < 5); + + return _blit_table_inv[dst_bpp][src_bpp]; +} + diff --git a/components/rtgui/common/dc.c b/components/rtgui/common/dc.c index fa8b85225a..97e6fcaf5c 100644 --- a/components/rtgui/common/dc.c +++ b/components/rtgui/common/dc.c @@ -138,12 +138,12 @@ void rtgui_dc_draw_vertical_line(struct rtgui_dc* dc, int x, int y1, int y2) color = RTGUI_DC_FC(dc); RTGUI_DC_FC(dc) = dark_grey; - rtgui_dc_draw_hline(dc, x, y1, y2); + rtgui_dc_draw_vline(dc, x, y1, y2); x ++; RTGUI_DC_FC(dc) = high_light; - rtgui_dc_draw_hline(dc, x, y1, y2); + rtgui_dc_draw_vline(dc, x, y1, y2); /* restore color */ RTGUI_DC_FC(dc) = color; diff --git a/components/rtgui/common/dc_client.c b/components/rtgui/common/dc_client.c index 22d2887095..154eb359bd 100644 --- a/components/rtgui/common/dc_client.c +++ b/components/rtgui/common/dc_client.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include @@ -139,7 +139,7 @@ struct rtgui_dc* rtgui_dc_client_create(rtgui_widget_t* owner) #endif } } - else if (RTGUI_IS_APPLICATION(owner->toplevel)) + else if (RTGUI_IS_APP(owner->toplevel)) { RT_ASSERT(0); } @@ -207,7 +207,7 @@ static rt_bool_t rtgui_dc_client_fini(struct rtgui_dc* dc) #endif } } - else if (RTGUI_IS_APPLICATION(owner->toplevel) || + else if (RTGUI_IS_APP(owner->toplevel) || RTGUI_IS_WIN(owner->toplevel)) { rtgui_toplevel_t* top = RTGUI_TOPLEVEL(owner->toplevel); diff --git a/components/rtgui/common/dc_hw.c b/components/rtgui/common/dc_hw.c index 2895797974..db226fd152 100644 --- a/components/rtgui/common/dc_hw.c +++ b/components/rtgui/common/dc_hw.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -117,7 +117,7 @@ struct rtgui_dc* rtgui_dc_hw_create(rtgui_widget_t* owner) #endif } } - else if (RTGUI_IS_APPLICATION(owner->toplevel) || + else if (RTGUI_IS_APP(owner->toplevel) || RTGUI_IS_WIN(owner->toplevel)) { rtgui_toplevel_t* top = RTGUI_TOPLEVEL(owner->toplevel); @@ -184,7 +184,7 @@ static rt_bool_t rtgui_dc_hw_fini(struct rtgui_dc* dc) #endif } } - else if (RTGUI_IS_APPLICATION(owner->toplevel) || + else if (RTGUI_IS_APP(owner->toplevel) || RTGUI_IS_WIN(owner->toplevel)) { rtgui_toplevel_t* top = RTGUI_TOPLEVEL(owner->toplevel); diff --git a/components/rtgui/common/framebuffer_driver.c b/components/rtgui/common/framebuffer_driver.c index 04c21c42a5..3d46732ebb 100644 --- a/components/rtgui/common/framebuffer_driver.c +++ b/components/rtgui/common/framebuffer_driver.c @@ -1,3 +1,8 @@ +/* + * Change Logs: + * Date Author Notes + * 2012-01-24 onelife fix a bug in framebuffer_draw_raw_hline + */ #include #include @@ -108,7 +113,7 @@ static void framebuffer_draw_raw_hline(rt_uint8_t *pixels, int x1, int x2, int y rt_uint8_t *dst; dst = GET_PIXEL(rtgui_graphic_get_device(), x1, y, rt_uint8_t); - rt_memcpy(dst, pixels, (x2 - x1) * (rtgui_graphic_get_device()->bits_per_pixel/8)); + rt_memcpy(dst, pixels, (x2 - x1 + 1) * (rtgui_graphic_get_device()->bits_per_pixel/8)); } const struct rtgui_graphic_driver_ops _framebuffer_rgb565_ops = diff --git a/components/rtgui/common/image.c b/components/rtgui/common/image.c index 1ae57e0ece..358ba2bff5 100644 --- a/components/rtgui/common/image.c +++ b/components/rtgui/common/image.c @@ -10,6 +10,7 @@ * Change Logs: * Date Author Notes * 2009-10-16 Bernard first version + * 2012-01-24 onelife add TJpgDec (Tiny JPEG Decompressor) support */ #include #include @@ -27,7 +28,7 @@ #ifdef RTGUI_IMAGE_BMP #include #endif -#ifdef RTGUI_IMAGE_JPEG +#if (defined(RTGUI_IMAGE_JPEG) || defined(RTGUI_IMAGE_TJPGD)) #include #endif #ifdef RTGUI_IMAGE_PNG @@ -50,7 +51,7 @@ void rtgui_system_image_init(void) rtgui_image_bmp_init(); #endif -#ifdef RTGUI_IMAGE_JPEG +#if (defined(RTGUI_IMAGE_JPEG) || defined(RTGUI_IMAGE_TJPGD)) rtgui_image_jpeg_init(); #endif diff --git a/components/rtgui/common/image_bmp.c b/components/rtgui/common/image_bmp.c index 1c7c108217..2374c7537b 100644 --- a/components/rtgui/common/image_bmp.c +++ b/components/rtgui/common/image_bmp.c @@ -1,3 +1,10 @@ +/* + * Change Logs: + * Date Author Notes + * 2012-01-24 onelife Reimplement to improve efficiency and add + * features. The new decoder uses configurable fixed size working buffer and + * provides scaledown function. + */ #include #include #include @@ -5,6 +12,10 @@ #include #include +#ifdef RTGUI_USING_DFS_FILERW +#include +#endif + #ifdef RTGUI_IMAGE_BMP /* Compression encodings for BMP files */ #ifndef BI_RGB @@ -14,57 +25,32 @@ #define BI_BITFIELDS 3 #endif -#define hw_driver (rtgui_graphic_driver_get_default()) +#define BMP_WORKING_BUFFER_SIZE (384) /* In multiple of 12 and bigger than 48 */ +#define BMP_MAX_SCALING_FACTOR (10) // TODO: find the max value! +#define hw_driver (rtgui_graphic_driver_get_default()) struct rtgui_image_bmp { rt_bool_t is_loaded; - - rt_uint32_t Rmask; - rt_uint32_t Gmask; - rt_uint32_t Bmask; - - rt_size_t pixel_offset; - - rt_uint8_t byte_per_pixel; - rt_uint8_t pad; - rt_uint8_t ExpandBMP; - rt_uint8_t *pixels; - rt_uint8_t *line_pixels; - rt_uint32_t pitch; - struct rtgui_filerw* filerw; + rt_uint32_t w, h; + rt_uint32_t pixel_offset; + rt_uint32_t pitch; rt_uint8_t scale; + rt_uint8_t bit_per_pixel; + rt_uint8_t pad; }; -struct rtgui_image_bmp_header -{ - /* The Win32 BMP file header (14 bytes) */ - char magic[2]; - rt_uint32_t bfSize; - rt_uint16_t bfReserved1; - rt_uint16_t bfReserved2; - rt_uint32_t bfOffBits; - - /* The Win32 BITMAPINFOHEADER struct (40 bytes) */ - rt_uint32_t biSize; - rt_int32_t biWidth; - rt_int32_t biHeight; - rt_uint16_t biPlanes; - rt_uint16_t biBitCount; - rt_uint32_t biCompression; - rt_uint32_t biSizeImage; - rt_int32_t biXPelsPerMeter; - rt_int32_t biYPelsPerMeter; - rt_uint32_t biClrUsed; - rt_uint32_t biClrImportant; -}; - +/* static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file, + rt_uint32_t *width, rt_uint32_t *height); +static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, + struct rtgui_filerw* file, rt_uint8_t scale, rt_bool_t load); */ static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file); static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load); static void rtgui_image_bmp_unload(struct rtgui_image* image); static void rtgui_image_bmp_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* rect); + struct rtgui_image_engine rtgui_image_bmp_engine = { "bmp", @@ -75,342 +61,429 @@ struct rtgui_image_engine rtgui_image_bmp_engine = rtgui_image_bmp_blit }; -rt_inline rt_uint32_t rtgui_filerw_read32(struct rtgui_filerw* src) -{ - rt_uint32_t value; - rtgui_filerw_read(src, &value, (sizeof value), 1); - return value; -} - -rt_inline rt_uint16_t rtgui_filerw_read16(struct rtgui_filerw* src) -{ - rt_uint16_t value; - rtgui_filerw_read(src, &value, (sizeof value), 1); - return value; - -} - static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file) +//static rt_bool_t rtgui_image_bmp_check(struct rtgui_filerw* file, +// rt_uint32_t *width, rt_uint32_t *height) { - char magic[2]; - rt_bool_t is_bmp; - rt_off_t start; - - if ( !file ) return 0; - - start = rtgui_filerw_tell(file); - - /* move to the beginning of file */ - rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET); - - is_bmp = RT_FALSE; - if ( rtgui_filerw_read(file, magic, 1, sizeof(magic)) == sizeof(magic) ) - { - if (magic[0] == 'B' && - magic[1] == 'M') + rt_uint8_t buffer[18]; + rt_bool_t is_bmp = RT_FALSE; + + do + { + if (!file ) + { + break; + } + + /* Prepare to decode */ + if (rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET) < 0) + { + break; + } + if (rtgui_filerw_read(file, (void *)buffer, 18, 1) != 18) + { + break; + } + /* Read file type */ + if (buffer[0] != 'B' || buffer[1] != 'M') { - is_bmp = RT_TRUE; + break; } - } - - rtgui_filerw_seek(file, start, RTGUI_FILE_SEEK_SET); - return(is_bmp); + /* Read BMP header size */ + if (*(rt_uint32_t *)&buffer[14] == 12) + { /* Bitmap Header Version 2.x */ + if (rtgui_filerw_read(file, (void *)buffer, 8, 1) != 8) + { + break; + } + /* Read image size */ +// *width = (rt_uint32_t)*(rt_uint16_t *)&buffer[0]; +// *height = (rt_uint32_t)*(rt_uint16_t *)&buffer[2]; + is_bmp = RT_TRUE; + } + else + { /* Bitmap Header Version bigger than 2.x */ + if (rtgui_filerw_read(file, (void *)buffer, 8, 1) != 8) + { + break; + } + /* Read image size */ +// *width = *(rt_uint32_t *)&buffer[0]; +// *height = *(rt_uint32_t *)&buffer[4]; + is_bmp = RT_TRUE; + } + } while(0); + + return is_bmp; } -static struct rtgui_image_palette* rtgui_image_bmp_load_palette(struct rtgui_image_bmp_header* header, struct rtgui_filerw* src) +static struct rtgui_image_palette* rtgui_image_bmp_load_palette( + struct rtgui_filerw* file, + rt_uint32_t colorsUsed, + rt_bool_t alpha) { /* Load the palette, if any */ - rt_size_t i; - struct rtgui_image_palette* palette; - - if (header->biClrUsed == 0) - header->biClrUsed = 1 << header->biBitCount; - - palette = rtgui_image_palette_create(header->biClrUsed); - if (palette == RT_NULL) return RT_NULL; - - if ( header->biSize == 12 ) - { - rt_uint8_t r, g, b; - for ( i = 0; i < (int)header->biClrUsed; ++i ) - { - rtgui_filerw_read(src, &b, 1, 1); - rtgui_filerw_read(src, &g, 1, 1); - rtgui_filerw_read(src, &r, 1, 1); - palette->colors[i] = RTGUI_RGB(r, g, b); - } - } - else - { - rt_uint8_t r, g, b, a; - for ( i = 0; i < (int)header->biClrUsed; ++i ) - { - rtgui_filerw_read(src, &b, 1, 1); - rtgui_filerw_read(src, &g, 1, 1); - rtgui_filerw_read(src, &r, 1, 1); - rtgui_filerw_read(src, &a, 1, 1); - palette->colors[i] = RTGUI_ARGB(a, r, g, b); - } - } + rt_uint32_t i; + struct rtgui_image_palette *palette; + + palette = rtgui_image_palette_create(colorsUsed); + if (palette == RT_NULL) + { + return RT_NULL; + } + + if (alpha) + { + rt_uint8_t temp[4]; + for (i = 0; i < colorsUsed; i++) + { + if (rtgui_filerw_read(file, (void *)&temp, 1, 4) != 4) + { + rtgui_free(palette); + return RT_NULL; + } + palette->colors[i] = RTGUI_ARGB(temp[3], temp[2], temp[1], temp[0]); + } + } + else + { + rt_uint8_t temp[3]; + for (i = 0; i < colorsUsed; i++) + { + if (rtgui_filerw_read(file, (void *)&temp, 1, 3) != 3) + { + rtgui_free(palette); + return RT_NULL; + } + palette->colors[i] = RTGUI_RGB(temp[2], temp[1], temp[0]); + } + } return palette; } -static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, struct rtgui_filerw* src, rt_bool_t load) +static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load) +//static rt_bool_t rtgui_image_bmp_load(struct rtgui_image* image, +// struct rtgui_filerw* file, rt_uint8_t scale, rt_bool_t load) { - rt_uint32_t Rmask; - rt_uint32_t Gmask; - rt_uint32_t Bmask; - int ExpandBMP, bmpPitch; + rt_uint8_t scale = 2; + rt_uint8_t *wrkBuffer; struct rtgui_image_bmp* bmp; - struct rtgui_image_bmp_header* header; - struct rtgui_image_palette* palette; - - bmp = RT_NULL; - header = RT_NULL; - palette = RT_NULL; - header = (struct rtgui_image_bmp_header*) rtgui_malloc(sizeof(struct rtgui_image_bmp_header)); - if (header == RT_NULL) return RT_FALSE; - - if ( rtgui_filerw_read(src, header->magic, 1, sizeof(header->magic)) == - sizeof(sizeof(header->magic)) ) - { - if (header->magic[0] != 'B' || - header->magic[1] != 'M') - { - goto __exit; - } - } - - header->bfSize = rtgui_filerw_read32(src); - header->bfReserved1 = rtgui_filerw_read16(src); - header->bfReserved2 = rtgui_filerw_read16(src); - header->bfOffBits = rtgui_filerw_read32(src); - - /* Read the Win32 BITMAPINFOHEADER */ - header->biSize = rtgui_filerw_read32(src); - if ( header->biSize == 12 ) - { - header->biWidth = (rt_uint32_t)rtgui_filerw_read16(src); - header->biHeight = (rt_uint32_t)rtgui_filerw_read16(src); - header->biPlanes = rtgui_filerw_read16(src); - header->biBitCount = rtgui_filerw_read16(src); - header->biCompression = BI_RGB; - header->biSizeImage = 0; - header->biXPelsPerMeter = 0; - header->biYPelsPerMeter = 0; - header->biClrUsed = 0; - - header->biClrImportant = 0; - - } - else - { - header->biWidth = rtgui_filerw_read32(src); - header->biHeight = rtgui_filerw_read32(src); - header->biPlanes = rtgui_filerw_read16(src); - header->biBitCount = rtgui_filerw_read16(src); - header->biCompression = rtgui_filerw_read32(src); - header->biSizeImage = rtgui_filerw_read32(src); - header->biXPelsPerMeter = rtgui_filerw_read32(src); - header->biYPelsPerMeter = rtgui_filerw_read32(src); - header->biClrUsed = rtgui_filerw_read32(src); - header->biClrImportant = rtgui_filerw_read32(src); - - } - - /* allocate palette and expand 1 and 4 bit bitmaps to 8 bits per pixel */ - switch (header->biBitCount) - { - case 1: - ExpandBMP = header->biBitCount; - palette = rtgui_image_bmp_load_palette(header, src); - header->biBitCount = 8; - break; - - case 4: - ExpandBMP = header->biBitCount; - palette = rtgui_image_bmp_load_palette(header, src); - header->biBitCount = 8; - break; - - case 8: - palette = rtgui_image_bmp_load_palette(header, src); - ExpandBMP = 0; - break; - - default: - ExpandBMP = 0; - break; - } - - /* We don't support any BMP compression right now */ - Rmask = Gmask = Bmask = 0; - switch (header->biCompression) - { - case BI_RGB: - /* If there are no masks, use the defaults */ - if ( header->bfOffBits == (14 + header->biSize) ) + rt_uint32_t bmpHeaderSize; + rt_uint32_t colorsUsed; + + if (scale > BMP_MAX_SCALING_FACTOR) + { + return RT_FALSE; + } + + do + { + wrkBuffer = (rt_uint8_t *)rt_malloc(BMP_WORKING_BUFFER_SIZE); + if (wrkBuffer == RT_NULL) + { + rt_kprintf("BMP err: no mem\n"); + break; + } + + bmp = (struct rtgui_image_bmp*)rtgui_malloc(sizeof(struct rtgui_image_bmp)); + if (bmp == RT_NULL) + { + break; + } + + /* Prepare to decode */ + if (rtgui_filerw_seek(file, 0, RTGUI_FILE_SEEK_SET) < 0) + { + break; + } + if (rtgui_filerw_read(file, (void *)wrkBuffer, 18, 1) != 18) + { + break; + } + /* Read file type */ + if (wrkBuffer[0] != 'B' || wrkBuffer[1] != 'M') { - /* Default values for the BMP format */ - switch (header->biBitCount) - { - case 15: - case 16: - Rmask = 0x7C00; - Gmask = 0x03E0; - Bmask = 0x001F; - break; - - case 24: - case 32: - Rmask = 0x00FF0000; - Gmask = 0x0000FF00; - Bmask = 0x000000FF; - break; - - default: - break; - } break; } - /* Fall through -- read the RGB masks */ - - case BI_BITFIELDS: - switch (header->biBitCount) - { - case 15: - case 16: - case 32: - Rmask = rtgui_filerw_read32(src); - Gmask = rtgui_filerw_read32(src); - Bmask = rtgui_filerw_read32(src); - break; - - default: - break; - } - break; - - default: - rt_kprintf("Compressed BMP files not supported\n"); - goto __exit; - } - - bmp = (struct rtgui_image_bmp*) rtgui_malloc(sizeof(struct rtgui_image_bmp)); - if (bmp == RT_NULL) - goto __exit; - - /* set image information */ - image->w = header->biWidth; - image->h = header->biHeight; - image->engine = &rtgui_image_bmp_engine; - image->data = bmp; - bmp->filerw = src; - bmp->byte_per_pixel = header->biBitCount/8; - bmp->pitch = image->w * bmp->byte_per_pixel; - bmp->pixel_offset = header->bfOffBits; - bmp->Rmask = Rmask; bmp->Gmask = Gmask; bmp->Bmask = Bmask; - bmp->ExpandBMP = ExpandBMP; - if (palette != RT_NULL) image->palette = palette; - - /* get padding */ - switch (ExpandBMP) - { - case 1: - bmpPitch = (header->biWidth + 7) >> 3; - bmp->pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); - break; - - case 4: - bmpPitch = (header->biWidth + 1) >> 1; - bmp->pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); - break; - - default: - bmp->pad = ((bmp->pitch%4) ? (4-(bmp->pitch%4)) : 0); - break; - } - - if (load == RT_TRUE) - { - rt_uint8_t *bits; - rt_uint32_t i; - - /* load all pixels */ - bmp->pixels = rtgui_malloc(image->h * bmp->pitch); - if (bmp->pixels == RT_NULL) - goto __exit; - - /* Read the pixels. Note that the bmp image is upside down */ - if ( rtgui_filerw_seek(src, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0) - goto __exit; - - bits = bmp->pixels + image->h * bmp->pitch; - while ( bits > bmp->pixels ) - { - bits -= bmp->pitch; - switch (ExpandBMP) - { - case 1: - case 4: - { - rt_uint8_t pixel = 0; - int shift = (8 - ExpandBMP); - for ( i=0; i < image->w; ++i ) - { - if ( i % (8/ExpandBMP) == 0 ) - { - if ( !rtgui_filerw_read(src, &pixel, 1, 1) ) - goto __exit; - - } - *(bits+i) = (pixel>>shift); - pixel <<= ExpandBMP; - } - } - break; - - default: - if ( rtgui_filerw_read(src, bits, 1, bmp->pitch) != bmp->pitch ) goto __exit; - break; - } - - /* Skip padding bytes */ - if ( bmp->pad ) - { - rt_uint8_t padbyte; - for ( i=0; i < bmp->pad; ++i ) - { - rtgui_filerw_read(src, &padbyte, 1, 1); - } - } - } - - rtgui_filerw_close(bmp->filerw); - bmp->line_pixels = RT_NULL; - bmp->filerw = RT_NULL; - bmp->pixel_offset = 0; - } - else - { - bmp->pixels = RT_NULL; - bmp->line_pixels = rtgui_malloc(bmp->pitch); - } - - return RT_TRUE; - -__exit: - rtgui_free(header); - if (palette != RT_NULL) - { - rtgui_free(palette); - image->palette = RT_NULL; - } - - if (bmp != RT_NULL) - rtgui_free(bmp->pixels); +// rt_kprintf("BMP: format ok\n"); + /* Read pixel array offset */ + bmp->pixel_offset = *(rt_uint32_t *)&wrkBuffer[10]; +// rt_kprintf("BMP: bmp->pixel_offset %d\n", bmp->pixel_offset); + /* Read BMP header size */ + bmpHeaderSize = *(rt_uint32_t *)&wrkBuffer[14]; +// rt_kprintf("BMP: bmpHeaderSize %d\n", bmpHeaderSize); + colorsUsed = 0; + if (bmpHeaderSize == 12) + { /* Bitmap Header Version 2.x */ + if (rtgui_filerw_read(file, (void *)wrkBuffer, 8, 1) != 8) + { + break; + } + /* Read image size */ + bmp->w = (rt_uint32_t)*(rt_uint16_t *)&wrkBuffer[0]; + bmp->h = (rt_uint32_t)*(rt_uint16_t *)&wrkBuffer[2]; + /* Read bits per pixel */ + bmp->bit_per_pixel = (rt_uint8_t)*(rt_uint16_t *)&wrkBuffer[6]; + } + else + { /* Bitmap Header Version bigger than 2.x */ + rt_uint32_t compression; + + if (rtgui_filerw_read(file, (void *)wrkBuffer, 36, 1) != 36) + { + break; + } + /* Read image size */ + bmp->w = *(rt_uint32_t *)&wrkBuffer[0]; + bmp->h = *(rt_uint32_t *)&wrkBuffer[4]; + /* Read bits per pixel */ + bmp->bit_per_pixel = (rt_uint8_t)*(rt_uint16_t *)&wrkBuffer[10]; + if (bmp->bit_per_pixel > 32) + { + rt_kprintf("BMP err: unsupported format\n"); + break; + } + /* Read compression method */ + compression = *(rt_uint32_t *)&wrkBuffer[12]; + if (compression != BI_RGB && compression != BI_BITFIELDS) + { + rt_kprintf("BMP err: unsupported format\n"); + break; + } + /* Read number of colors */ + colorsUsed = *(rt_uint32_t *)&wrkBuffer[28]; + } + if (!colorsUsed) + { + colorsUsed = 1 << bmp->bit_per_pixel; + } + + /* Load palette */ + if (bmp->bit_per_pixel <= 8) + { + if (rtgui_filerw_seek(file, 14 + bmpHeaderSize, RTGUI_FILE_SEEK_SET) < 0) + { + break; + } + + image->palette = rtgui_image_bmp_load_palette(file, colorsUsed, + bmpHeaderSize > 12 ? RT_TRUE : RT_FALSE); + if (image->palette == RT_NULL) + { + break; + } + } + + /* Set image information */ + bmp->is_loaded = RT_FALSE; + bmp->scale = scale; + if (bmp->bit_per_pixel == 1) + { + bmp->pitch = (bmp->w + 7) >> 3; + } + else if (bmp->bit_per_pixel == 4) + { + bmp->pitch = (bmp->w + 1) >> 1; + } + else + { + bmp->pitch = bmp->w * (bmp->bit_per_pixel >> 3); + } + bmp->pad = ((bmp->pitch % 4) ? (4 - (bmp->pitch % 4)) : 0); + bmp->pixels = RT_NULL; + bmp->filerw = file; + + image->w = bmp->w >> bmp->scale; + image->h = bmp->h >> bmp->scale; + image->engine = &rtgui_image_bmp_engine; + image->data = bmp; + + /* Start to decode */ + if (load == RT_TRUE) + { + rt_bool_t error = RT_FALSE; + rt_uint8_t *dst; + rt_uint32_t imageWidth; + rt_uint16_t readLength, readIndex, loadIndex; + rt_uint8_t skipLength; + rt_uint16_t y; + rt_uint8_t bytePerPixel; + rt_int8_t scale1, scale2; + + bytePerPixel = bmp->bit_per_pixel / 8; + if (!bytePerPixel) + { + bytePerPixel = 1; + } + imageWidth = image->w * bytePerPixel; /* Scaled width in byte */ + bmp->pixels = rtgui_malloc(image->h * imageWidth); + if (bmp->pixels == RT_NULL) + { + rt_kprintf("BMP err: no mem to load (%d)\n", image->h * imageWidth); + break; + } + + /* Read the pixels. Note that the bmp image is upside down */ + if (rtgui_filerw_seek(file, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0) + { + break; + } + + if (bmp->bit_per_pixel == 1) + { + if (bmp->scale > 3) + { + scale1 = bmp->scale - 3; + scale2 = 3; + } + else + { + scale1 = 0; + scale2 = bmp->scale; + } + } + else if (bmp->bit_per_pixel == 4) + { + if (bmp->scale > 1) + { + scale1 = bmp->scale - 1; + scale2 = 1; + } + else + { + scale1 = 0; + scale2 = bmp->scale; + } + } + + /* Process whole image */ + y = 0; + while (y < image->h) + { + dst = bmp->pixels + (image->h - y - 1) * imageWidth; + readIndex = 0; + skipLength= 0; + + /* Process a line */ + while (readIndex < bmp->pitch) + { + /* Put progress indicator */ + rt_kprintf("\r%lu%%", y * 100UL / image->h); + + /* Read data to buffer */ + readLength = (BMP_WORKING_BUFFER_SIZE > (bmp->pitch - readIndex)) ? \ + (bmp->pitch - readIndex) : BMP_WORKING_BUFFER_SIZE; + if (rtgui_filerw_read(file, (void *)wrkBuffer, 1, readLength) != readLength) + { + rt_kprintf("BMP err: read failed\n"); + error = RT_TRUE; + break; + } + readIndex += readLength; + + /* Process read buffer */ + if (bmp->bit_per_pixel == 1) + { + rt_uint8_t j; + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1) + { + for (j = 0; j < 8; j += 1 << scale2) + { + *(dst++) = (wrkBuffer[loadIndex] & (1 << (7 - j))) >> (7 - j); + } + } + if (scale1 && (readLength % (1 << scale1))) + { + skipLength = (1 << scale1) - readLength % (1 << scale1); + } + } + else if (bmp->bit_per_pixel == 4) + { + rt_uint8_t j; + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1) + { + for (j = 0; j < 8; j += 1 << (2 + scale2)) + { + *(dst++) = (wrkBuffer[loadIndex] & (0x0F << (4 - j))) >> (4 - j); + } + } + if (scale1 && (readLength % (1 << scale1))) + { + skipLength = (1 << scale1) - readLength % (1 << scale1); + } + } + else + { + if (bmp->scale == 0) + { + rt_memcpy((void *)dst, (void *)wrkBuffer, readLength); + dst += readLength; + } + else + { + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += bytePerPixel << bmp->scale) + { + rt_memcpy((void *)dst, (void *)&wrkBuffer[loadIndex], bytePerPixel); + dst += bytePerPixel; + } + if (readLength % (1 << bmp->scale)) + { + skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale); + } + } + } + } + if (error) + { + break; + } + y++; + + /* Skip padding bytes */ + if (bmp->pad) + { + if ( rtgui_filerw_seek(file, bmp->pad, RTGUI_FILE_SEEK_CUR) < 0) + { + error = RT_TRUE; + break; + } + } + + /* Height scale down */ + if (bmp->scale) + { + if (rtgui_filerw_seek(file, (bmp->pitch + bmp->pad) * ((1 << bmp->scale) - 1), + RTGUI_FILE_SEEK_CUR) < 0) + { + error = RT_TRUE; + break; + } + } + } + if (error) + { + break; + } + /* Close file */ + rtgui_filerw_close(bmp->filerw); + bmp->filerw = RT_NULL; + bmp->is_loaded = RT_TRUE; +// rt_kprintf("BMP: load to RAM\n"); + } + + /* Release memory */ + rt_free(wrkBuffer); + return RT_TRUE; + } while(0); + + /* Release memory */ + rt_free(wrkBuffer); + rtgui_free(image->palette); + rtgui_free(bmp->pixels); rtgui_free(bmp); return RT_FALSE; } @@ -421,220 +494,324 @@ static void rtgui_image_bmp_unload(struct rtgui_image* image) if (image != RT_NULL) { - bmp = (struct rtgui_image_bmp*) image->data; + bmp = (struct rtgui_image_bmp*)image->data; - if (bmp->pixels != RT_NULL) rtgui_free(bmp->pixels); - if (bmp->line_pixels != RT_NULL) rtgui_free(bmp->line_pixels); + /* Release memory */ + rtgui_free(bmp->pixels); if (bmp->filerw != RT_NULL) { + /* Close file */ rtgui_filerw_close(bmp->filerw); bmp->filerw = RT_NULL; } - - /* release data */ rtgui_free(bmp); } } static void rtgui_image_bmp_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* dst_rect) { - int y; - rt_uint16_t w, h; + rt_uint16_t w, h; struct rtgui_image_bmp* bmp; - - RT_ASSERT(image != RT_NULL || dc != RT_NULL || dst_rect != RT_NULL); - - /* this dc is not visible */ - if (rtgui_dc_get_visible(dc) != RT_TRUE) return; - - bmp = (struct rtgui_image_bmp*) image->data; - RT_ASSERT(bmp != RT_NULL); - - /* the minimum rect */ - if (image->w < rtgui_rect_width(*dst_rect)) w = image->w; - else w = rtgui_rect_width(*dst_rect); - if (image->h < rtgui_rect_height(*dst_rect)) h = image->h; - else h = rtgui_rect_height(*dst_rect); - - if (bmp->pixels != RT_NULL) - { - rt_uint8_t* ptr; - - /* get pixel pointer */ - ptr = bmp->pixels; - if (bmp->byte_per_pixel == hw_driver->bits_per_pixel/8) - { - for (y = 0; y < h; y ++) - { - dc->engine->blit_line(dc, - dst_rect->x1, dst_rect->x1 + w, - dst_rect->y1 + y, - ptr); - ptr += bmp->pitch; - } - } - else - { - rt_size_t pitch; - rt_uint8_t *line_ptr; - - if (image->palette == RT_NULL) - { - rtgui_blit_line_func blit_line; - line_ptr = (rt_uint8_t*) rtgui_malloc((hw_driver->bits_per_pixel/8) * w); - blit_line = rtgui_blit_line_get(hw_driver->bits_per_pixel/8 , bmp->byte_per_pixel); - pitch = w * bmp->byte_per_pixel; - if (line_ptr != RT_NULL) - { - for (y = 0; y < h; y ++) - { - blit_line(line_ptr, ptr, pitch); - dc->engine->blit_line(dc, - dst_rect->x1, dst_rect->x1 + w, - dst_rect->y1 + y, - line_ptr); - ptr += bmp->pitch; - } - } - rtgui_free(line_ptr); - } - else - { - int x; - rtgui_color_t color; - - /* use palette */ - for (y = 0; y < h; y ++) - { - ptr = bmp->pixels + (y * bmp->pitch); - for (x = 0; x < w; x ++) - { - color = image->palette->colors[*ptr]; ptr ++; - rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color); - } - } - } - } - } - else - { - int offset; - rt_uint8_t *bits; - - /* calculate offset */ - switch (bmp->ExpandBMP) - { - case 1: - offset = (image->h - h) * (image->w/8) * bmp->byte_per_pixel; - break; - - case 4: - offset = (image->h - h) * (image->w/2) * bmp->byte_per_pixel; - break; - - default: - offset = (image->h - h) * image->w * bmp->byte_per_pixel; - break; - } - /* seek to the begin of pixel data */ - rtgui_filerw_seek(bmp->filerw, bmp->pixel_offset + offset, RTGUI_FILE_SEEK_SET); - - if (bmp->ExpandBMP == 1 || bmp->ExpandBMP == 4) - { - int x; - rtgui_color_t color; - /* 1, 4 bit per pixels */ - - /* draw each line */ - for (y = h - 1; y >= 0; y --) - { - /* read pixel data */ - rt_uint8_t pixel = 0; - int shift = (8 - bmp->ExpandBMP); - int i; - - bits = bmp->line_pixels; - for ( i=0; i < image->w; ++i ) - { - if ( i % (8/bmp->ExpandBMP) == 0 ) - { - if ( !rtgui_filerw_read(bmp->filerw, &pixel, 1, 1) ) - return; - } - *(bits+i) = (pixel>>shift); - pixel <<= bmp->ExpandBMP; - } - - /* Skip padding bytes */ - if (bmp->pad) - { - int i; - rt_uint8_t padbyte; - for ( i=0; i < bmp->pad; ++i ) - rtgui_filerw_read(bmp->filerw, &padbyte, 1, 1); - } - - /* use palette */ - bits = bmp->line_pixels; - for (x = 0; x < w; x ++) - { - color = image->palette->colors[*bits]; bits ++; - rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color); - } - } - } - else - { - rt_uint8_t *line_ptr = (rt_uint8_t*) rtgui_malloc((hw_driver->bits_per_pixel/8) * w); - if (line_ptr == RT_NULL) return; - - /* draw each line */ - for (y = h - 1; y >= 0; y --) - { - /* read line pixels */ - rtgui_filerw_read(bmp->filerw, bmp->line_pixels, 1, bmp->pitch); - - /* Skip padding bytes */ - if (bmp->pad) - { - int i; - rt_uint8_t padbyte; - for ( i=0; i < bmp->pad; ++i ) - rtgui_filerw_read(bmp->filerw, &padbyte, 1, 1); - } - - if (image->palette == RT_NULL) - { - int pitch; - rtgui_blit_line_func blit_line; - blit_line = rtgui_blit_line_get(hw_driver->bits_per_pixel/8 , bmp->byte_per_pixel); - pitch = w * bmp->byte_per_pixel; - if (line_ptr != RT_NULL) - { - blit_line(line_ptr, bmp->line_pixels, pitch); - dc->engine->blit_line(dc, - dst_rect->x1, dst_rect->x1 + w, - dst_rect->y1 + y, - line_ptr); - } - } - else - { - int x; - rtgui_color_t color; - - /* use palette */ - bits = bmp->line_pixels; - for (x = 0; x < w; x ++) - { - color = image->palette->colors[*bits]; bits ++; - rtgui_dc_draw_color_point(dc, dst_rect->x1 + x, dst_rect->y1 + y, color); - } - } - } - if (line_ptr != RT_NULL) rtgui_free(line_ptr); - } - } + rt_uint8_t bytePerPixel; + rt_uint32_t imageWidth; + rt_bool_t error; + + bmp = (struct rtgui_image_bmp*)image->data; + RT_ASSERT(image != RT_NULL || dc != RT_NULL || dst_rect != RT_NULL || bmp != RT_NULL); + + bytePerPixel = bmp->bit_per_pixel / 8; + if (!bytePerPixel) + { + bytePerPixel = 1; + } + imageWidth = image->w * bytePerPixel; /* Scaled width in byte */ + error = RT_FALSE; + + do + { + /* this dc is not visible */ + if (rtgui_dc_get_visible(dc) != RT_TRUE) + { + break; + } + + /* the minimum rect */ + if (image->w < rtgui_rect_width(*dst_rect)) + { + w = image->w; + } + else + { + w = rtgui_rect_width(*dst_rect); + } + if (image->h < rtgui_rect_height(*dst_rect)) + { + h = image->h; + } + else + { + h = rtgui_rect_height(*dst_rect); + } + + if (!bmp->is_loaded) + { + rt_uint8_t *wrkBuffer; + rt_uint16_t readLength, readIndex, loadIndex; + rt_uint8_t skipLength; + rt_uint16_t x, y; + rt_int8_t scale1, scale2; + + wrkBuffer = (rt_uint8_t *)rt_malloc(BMP_WORKING_BUFFER_SIZE); + if (wrkBuffer == RT_NULL) + { + rt_kprintf("BMP err: no mem (%d)\n", BMP_WORKING_BUFFER_SIZE); + break; + } + + /* Read the pixels. Note that the bmp image is upside down */ + if (rtgui_filerw_seek(bmp->filerw, bmp->pixel_offset, RTGUI_FILE_SEEK_SET) < 0) + { + break; + } + + if (bmp->bit_per_pixel == 1) + { + if (bmp->scale > 3) + { + scale1 = bmp->scale - 3; + scale2 = 3; + } + else + { + scale1 = 0; + scale2 = bmp->scale; + } + } + else if (bmp->bit_per_pixel == 4) + { + if (bmp->scale > 1) + { + scale1 = bmp->scale - 1; + scale2 = 1; + } + else + { + scale1 = 0; + scale2 = bmp->scale; + } + } + + /* Process whole image */ + y = 0; + while (y < image->h) + { + x = 0; + readIndex = 0; + skipLength= 0; + + /* Process a line */ + while (readIndex < bmp->pitch) + { + /* Put progress indicator */ + rt_kprintf("\r%lu%%", y * 100UL / image->h); + + /* Read data to buffer */ + readLength = (BMP_WORKING_BUFFER_SIZE > (bmp->pitch - readIndex)) ? \ + (bmp->pitch - readIndex) : BMP_WORKING_BUFFER_SIZE; + if (rtgui_filerw_read(bmp->filerw, (void *)wrkBuffer, 1, readLength) != readLength) + { + rt_kprintf("BMP err: read failed\n"); + error = RT_TRUE; + break; + } + readIndex += readLength; + + /* Process read buffer */ + if (bmp->bit_per_pixel == 1) + { + rt_uint8_t j; + rtgui_color_t color; + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1) + { + for (j = 0; j < 8; j += 1 << scale2) + { + color = image->palette->colors[(wrkBuffer[loadIndex] & (1 << (7 - j))) >> (7 - j)]; + rtgui_dc_draw_color_point(dc, + dst_rect->x1 + x++, + dst_rect->y1 + image->h - y, + color); + } + if (scale1 && (readLength % (1 << scale1))) + { + skipLength = (1 << scale1) - readLength % (1 << scale1); + } + } + } + else if (bmp->bit_per_pixel == 4) + { + rt_uint8_t j; + rtgui_color_t color; + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << scale1) + { + for (j = 0; j < 8; j += 1 << (2 + scale2)) + { + color = image->palette->colors[(wrkBuffer[loadIndex] & (0x0F << (4 - j))) >> (4 - j)]; + rtgui_dc_draw_color_point(dc, + dst_rect->x1 + x++, + dst_rect->y1 + image->h - y, + color); + } + } + if (scale1 && (readLength % (1 << scale1))) + { + skipLength = (1 << scale1) - readLength % (1 << scale1); + } + } + else if (bmp->bit_per_pixel == 8) + { + rtgui_color_t color; + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += 1 << bmp->scale) + { + color = image->palette->colors[wrkBuffer[loadIndex]]; + rtgui_dc_draw_color_point(dc, + dst_rect->x1 + x++, + dst_rect->y1 + image->h - y, + color); + } + if (readLength % (1 << bmp->scale)) + { + skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale); + } + } + else + { + rtgui_blit_line_func blit_line; + rt_uint8_t hw_bytePerPixel = hw_driver->bits_per_pixel / 8; + rt_uint8_t temp[4] = {0}; + + if (!hw_bytePerPixel) + { + hw_bytePerPixel = 1; + } + + if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) + { + blit_line = rtgui_blit_line_get_inv(hw_bytePerPixel, bytePerPixel); + } + else + { + blit_line = rtgui_blit_line_get(hw_bytePerPixel, bytePerPixel); + } + + for (loadIndex = skipLength; loadIndex < readLength; loadIndex += bytePerPixel << bmp->scale) + { + blit_line(temp, &wrkBuffer[loadIndex], bytePerPixel); + dc->engine->blit_line(dc, + dst_rect->x1 + x, dst_rect->x1 + x, + dst_rect->y1 + image->h - y, + temp); + x++; + } + if (readLength % (1 << bmp->scale)) + { + skipLength = (1 << bmp->scale) - readLength % (1 << bmp->scale); + } + } + } + if (error) + { + break; + } + y++; + + /* Skip padding bytes */ + if (bmp->pad) + { + if ( rtgui_filerw_seek(bmp->filerw, bmp->pad, RTGUI_FILE_SEEK_CUR) < 0) + { + error = RT_TRUE; + break; + } + } + + /* Height scale down */ + if (bmp->scale) + { + if (rtgui_filerw_seek(bmp->filerw, (bmp->pitch + bmp->pad) * ((1 << bmp->scale) - 1), + RTGUI_FILE_SEEK_CUR) < 0) + { + error = RT_TRUE; + break; + } + } + } + if (error) + { + break; + } + /* Release memory */ + rt_free(wrkBuffer); +// rt_kprintf("BMP: load to display\n"); + } + else + { + rt_uint16_t x, y; + rt_uint8_t* ptr; + + for (y = 0; y < h; y ++) + { + ptr = bmp->pixels + (y * imageWidth); + if (bmp->bit_per_pixel <= 8) + { + rtgui_color_t color; + + /* Using palette */ + for (x = 0; x < w; x ++) + { + color = image->palette->colors[*(ptr++)]; + rtgui_dc_draw_color_point(dc, + dst_rect->x1 + x, + dst_rect->y1 + y, + color); + } + } + else + { + rtgui_blit_line_func blit_line; + rt_uint8_t hw_bytePerPixel = hw_driver->bits_per_pixel / 8; + rt_uint8_t temp[4] = {0}; + + if (!hw_bytePerPixel) + { + hw_bytePerPixel = 1; + } + + if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) + { + blit_line = rtgui_blit_line_get_inv(hw_bytePerPixel, bytePerPixel); + } + else + { + blit_line = rtgui_blit_line_get(hw_bytePerPixel, bytePerPixel); + } + + for (x = 0; x < w; x ++) + { + blit_line(temp, ptr, bytePerPixel); + ptr += bytePerPixel; + dc->engine->blit_line(dc, + dst_rect->x1 + x, dst_rect->x1 + x, + dst_rect->y1 + y, + temp); + } + } + } + } +// rt_kprintf("BMP: blit ok\n"); + } while(0); } void rtgui_image_bmp_init() diff --git a/components/rtgui/common/image_jpg.c b/components/rtgui/common/image_jpg.c index decf6de8c7..0980fc68d1 100644 --- a/components/rtgui/common/image_jpg.c +++ b/components/rtgui/common/image_jpg.c @@ -1,3 +1,8 @@ +/* + * Change Logs: + * Date Author Notes + * 2012-01-24 onelife add TJpgDec (Tiny JPEG Decompressor) support + */ #include #include @@ -494,3 +499,477 @@ static rt_bool_t rtgui_image_jpeg_check(struct rtgui_filerw* file) } #endif + +#if defined(RTGUI_IMAGE_TJPGD) +/***************************************************************************//** + * @file image_jpg.c + * @brief JPEG decoder using TJpgDec module (elm-chan.org) + * COPYRIGHT (C) 2012, RT-Thread Development Team + * @author onelife + * @version 1.0 + ******************************************************************************* + * @section License + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE + ******************************************************************************* + * @section Change Logs + * Date Author Notes + * 2012-01-24 onelife Initial creation for limited memory devices + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup TJpgDec + * @{ + ******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "tjpgd.h" + +#include +#include +#include +#include + +#ifdef RTGUI_USING_DFS_FILERW +#include +#endif + +/* Private typedef -----------------------------------------------------------*/ +struct rtgui_image_jpeg +{ + struct rtgui_filerw* filerw; + struct rtgui_dc *dc; + rt_uint16_t dst_x, dst_y; + rt_uint16_t dst_w, dst_h; + rt_bool_t is_loaded; + rt_bool_t to_buffer; + rt_uint8_t scale; + rt_uint8_t byte_per_pixel; + JDEC tjpgd; /* jpeg structure */ + void *pool; + rt_uint8_t *pixels; +}; + +/* Private define ------------------------------------------------------------*/ +#define TJPGD_WORKING_BUFFER_SIZE (3100) +#define TJPGD_MAX_MCU_WIDTH_ON_DISP (2 * 8 * 4) /* Y component: 2x2; Display: 4-byte per pixel */ +#define TJPGD_MAX_SCALING_FACTOR (3) +#define hw_driver (rtgui_graphic_driver_get_default()) + +/* Private macro -------------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* static rt_bool_t rtgui_image_jpeg_check(struct rtgui_filerw* file, + rt_uint16_t *width, rt_uint16_t *height); +static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image* image, + struct rtgui_filerw* file, rt_uint8_t scale, rt_bool_t load); */ +static rt_bool_t rtgui_image_jpeg_check(struct rtgui_filerw* file); +static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load); +static void rtgui_image_jpeg_unload(struct rtgui_image* image); +static void rtgui_image_jpeg_blit(struct rtgui_image* image, + struct rtgui_dc* dc, struct rtgui_rect* dst_rect); + +/* Private variables ---------------------------------------------------------*/ +struct rtgui_image_engine rtgui_image_jpeg_engine = +{ + "jpeg", + {RT_NULL}, + rtgui_image_jpeg_check, + rtgui_image_jpeg_load, + rtgui_image_jpeg_unload, + rtgui_image_jpeg_blit +}; + +struct rtgui_image_engine rtgui_image_jpg_engine = +{ + "jpg", + {RT_NULL}, + rtgui_image_jpeg_check, + rtgui_image_jpeg_load, + rtgui_image_jpeg_unload, + rtgui_image_jpeg_blit +}; + +/* Private functions ---------------------------------------------------------*/ +void rtgui_image_jpeg_init() +{ + /* register jpeg on image system */ + rtgui_image_register_engine(&rtgui_image_jpeg_engine); + /* register jpg on image system */ + rtgui_image_register_engine(&rtgui_image_jpg_engine); +} + +static UINT tjpgd_in_func(JDEC *jdec, BYTE *buff, UINT ndata) +{ + struct rtgui_filerw *file = *(struct rtgui_filerw **)jdec->device; + + if (buff == RT_NULL) + { + return rtgui_filerw_seek(file, ndata, RTGUI_FILE_SEEK_CUR); + } + + return rtgui_filerw_read(file, (void *)buff, 1, ndata); +} + +static UINT tjpgd_out_func(JDEC *jdec, void *bitmap, JRECT *rect) +{ + struct rtgui_image_jpeg *jpeg = (struct rtgui_image_jpeg *)jdec->device; + rt_uint16_t w, h, y; + rt_uint16_t rectWidth; /* Width of source rectangular (bytes) */ + rt_uint8_t *src, *dst; + + /* Put progress indicator */ + if (rect->left == 0) + { + rt_kprintf("\r%lu%%", (rect->top << jpeg->scale) * 100UL / jdec->height); + } + + /* Copy the decompressed RGB rectanglar to the frame buffer */ + rectWidth = (rect->right - rect->left + 1) * jpeg->byte_per_pixel; + src = (rt_uint8_t *)bitmap; + + if (jpeg->to_buffer) + { + rt_uint16_t imageWidth; /* Width of image (bytes) */ + + imageWidth = (jdec->width >> jdec->scale) * jpeg->byte_per_pixel; + dst = jpeg->pixels + rect->top * imageWidth + rect->left * jpeg->byte_per_pixel; + /* Left-top of destination rectangular */ + for (h = rect->top; h <= rect->bottom; h++) + { + rt_memcpy(dst, src, rectWidth); + src += rectWidth; + dst += imageWidth; /* Next line */ + } + } + else + { + rtgui_blit_line_func blit_line = RT_NULL; + + w = rect->right < jpeg->dst_w ? rect->right : jpeg->dst_w; + w = w - rect->left + 1; + h = rect->bottom < jpeg->dst_h ? rect->bottom : jpeg->dst_h; + h = h - rect->top + 1; + if (jpeg->byte_per_pixel == hw_driver->bits_per_pixel / 8) + { + if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) + { + blit_line = rtgui_blit_line_get_inv(hw_driver->bits_per_pixel / 8, jpeg->byte_per_pixel); + } + } + else + { + blit_line = rtgui_blit_line_get(hw_driver->bits_per_pixel / 8, jpeg->byte_per_pixel); + } + + if (blit_line) + { + rt_uint8_t line_buf[TJPGD_MAX_MCU_WIDTH_ON_DISP]; + + for (y = 0; y < h; y++) + { + blit_line(line_buf, src, w * jpeg->byte_per_pixel); + jpeg->dc->engine->blit_line(jpeg->dc, + jpeg->dst_x + rect->left, jpeg->dst_x + rect->left + w - 1, + jpeg->dst_y + rect->top + y, + line_buf); + src += rectWidth; + } + } + else + { + for (y = 0; y < h; y++) + { + jpeg->dc->engine->blit_line(jpeg->dc, + jpeg->dst_x + rect->left, jpeg->dst_x + rect->left + w - 1, + jpeg->dst_y + rect->top + y, + src); + src += rectWidth; + } + } + } + return 1; /* Continue to decompress */ +} + +static rt_bool_t rtgui_image_jpeg_check(struct rtgui_filerw* file) +//static rt_bool_t rtgui_image_jpeg_check(struct rtgui_filerw* file, +// rt_uint32_t *width, rt_uint32_t *height) +{ + rt_bool_t is_JPG; + JDEC tjpgd; + void *pool; + + is_JPG = RT_FALSE; + do + { + if (!file ) + { + break; + } + + pool = rt_malloc(TJPGD_WORKING_BUFFER_SIZE); + if (pool == RT_NULL) + { + rt_kprintf("TJPGD err: no mem\n"); + break; + } + + if (rtgui_filerw_seek(file, 0, SEEK_SET) == -1) + { + break; + } + + if (jd_prepare(&tjpgd, tjpgd_in_func, pool, + TJPGD_WORKING_BUFFER_SIZE, (void *)&file) == JDR_OK) + { +// *width = (rt_uint32_t)tjpgd.width; +// *height = (rt_uint32_t)tjpgd.height; + is_JPG = RT_TRUE; + } + + rt_kprintf("TJPGD: check OK\n"); + } while(0); + + rt_free(pool); + + return is_JPG; +} + +static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image* image, struct rtgui_filerw* file, rt_bool_t load) +//static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image* image, +// struct rtgui_filerw* file, rt_uint8_t scale, rt_bool_t load) +{ + rt_uint8_t scale = 2; + rt_bool_t res = RT_FALSE; + struct rtgui_image_jpeg *jpeg; + JRESULT ret; + + if (scale > TJPGD_MAX_SCALING_FACTOR) + { + return RT_FALSE; + } + + do + { + jpeg = (struct rtgui_image_jpeg *)rt_malloc(sizeof(struct rtgui_image_jpeg)); + if (jpeg == RT_NULL) + { + break; + } + jpeg->filerw = file; + jpeg->is_loaded = RT_FALSE; + jpeg->to_buffer = load; + jpeg->scale = scale; +#if (JD_FORMAT == 0) + jpeg->byte_per_pixel = 3; +#elif (JD_FORMAT == 1) + jpeg->byte_per_pixel = 2; +#endif + jpeg->pool = RT_NULL; + jpeg->pixels = RT_NULL; + + jpeg->pool = rt_malloc(TJPGD_WORKING_BUFFER_SIZE); + if (jpeg->pool == RT_NULL) + { + rt_kprintf("TJPGD err: no mem (%d)\n", TJPGD_WORKING_BUFFER_SIZE); + break; + } + + if (rtgui_filerw_seek(jpeg->filerw, 0, SEEK_SET) == -1) + { + break; + } + + ret = jd_prepare(&jpeg->tjpgd, tjpgd_in_func, jpeg->pool, + TJPGD_WORKING_BUFFER_SIZE, (void *)jpeg); + if (ret != JDR_OK) + { + if (ret == JDR_FMT3) + { + rt_kprintf("TJPGD: not supported format\n"); + } + break; + } + rt_kprintf("TJPGD: prepare OK\n"); + + image->w = (rt_uint16_t)jpeg->tjpgd.width >> jpeg->scale; + image->h = (rt_uint16_t)jpeg->tjpgd.height >> jpeg->scale; + + /* set image private data and engine */ + image->data = jpeg; + image->engine = &rtgui_image_jpeg_engine; + + if (jpeg->to_buffer == RT_TRUE) + { + jpeg->pixels = (rt_uint8_t *)rtgui_malloc( + jpeg->byte_per_pixel * image->w * image->h); + if (jpeg->pixels == RT_NULL) + { + rt_kprintf("TJPGD err: no mem to load (%d)\n", + jpeg->byte_per_pixel * image->w * image->h); + break; + } + + ret = jd_decomp(&jpeg->tjpgd, tjpgd_out_func, jpeg->scale); + if (ret != JDR_OK) + { + break; + } + + rtgui_filerw_close(jpeg->filerw); + jpeg->is_loaded = RT_TRUE; + + rt_kprintf("TJPGD: load to RAM\n"); + } + res = RT_TRUE; + } while(0); + + if (!res || jpeg->is_loaded) + { + rt_free(jpeg->pool); + } + if (!res) + { + rtgui_free(jpeg->pixels); + rt_free(jpeg); + } + + /* create jpeg image successful */ + return res; +} + + +static void rtgui_image_jpeg_unload(struct rtgui_image* image) +{ + if (image != RT_NULL) + { + struct rtgui_image_jpeg* jpeg; + + jpeg = (struct rtgui_image_jpeg*) image->data; + RT_ASSERT(jpeg != RT_NULL); + + if (jpeg->to_buffer == RT_TRUE) + { + if (jpeg->is_loaded == RT_TRUE) + { + rtgui_free(jpeg->pixels); + } + if (jpeg->is_loaded != RT_TRUE) + { + rtgui_filerw_close(jpeg->filerw); + } + } + else + { + rt_free(jpeg->pool); + rtgui_filerw_close(jpeg->filerw); + } + rt_free(jpeg); + } + rt_kprintf("TJPGD: unload\n"); +} + +static void rtgui_image_jpeg_blit(struct rtgui_image* image, + struct rtgui_dc* dc, struct rtgui_rect* dst_rect) +{ + rt_uint16_t w, h, y; + struct rtgui_image_jpeg *jpeg; + + jpeg = (struct rtgui_image_jpeg *) image->data; + RT_ASSERT(image != RT_NULL || dc != RT_NULL || dst_rect != RT_NULL || jpeg != RT_NULL); + + do + { + /* this dc is not visible */ + if (rtgui_dc_get_visible(dc) != RT_TRUE) + { + break; + } + jpeg->dc= dc; + + /* the minimum rect */ + if (image->w < rtgui_rect_width(*dst_rect)) + { + w = image->w; + } + else + { + w = rtgui_rect_width(*dst_rect); + } + if (image->h < rtgui_rect_height(*dst_rect)) + { + h = image->h; + } + else + { + h = rtgui_rect_height(*dst_rect); + } + + if (!jpeg->is_loaded) + { + JRESULT ret; + + jpeg->dst_x = dst_rect->x1; + jpeg->dst_y = dst_rect->y1; + jpeg->dst_w = w; + jpeg->dst_h = h; + ret = jd_decomp(&jpeg->tjpgd, tjpgd_out_func, jpeg->scale); + if (ret != JDR_OK) + { + break; + } + rt_kprintf("TJPGD: load to display\n"); + } + else + { + rt_uint8_t* src = jpeg->pixels; + rt_uint16_t imageWidth = image->w * jpeg->byte_per_pixel; + rtgui_blit_line_func blit_line = RT_NULL; + + if (jpeg->byte_per_pixel == hw_driver->bits_per_pixel / 8) + { + if (hw_driver->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) + { + blit_line = rtgui_blit_line_get_inv(hw_driver->bits_per_pixel / 8, jpeg->byte_per_pixel); + } + } + else + { + blit_line = rtgui_blit_line_get(hw_driver->bits_per_pixel / 8, jpeg->byte_per_pixel); + } + + if (blit_line) + { + rt_uint16_t x; + rt_uint8_t temp[4]; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + blit_line(temp, src, jpeg->byte_per_pixel); + src += jpeg->byte_per_pixel; + dc->engine->blit_line(dc, + dst_rect->x1 + x, dst_rect->x1 + x, + dst_rect->y1 + y, + temp); + } + } + } + else + { + for (y = 0; y < h; y++) + { + dc->engine->blit_line(dc, + dst_rect->x1, dst_rect->x1 + w - 1, + dst_rect->y1 + y, + src); + src += imageWidth; + } + } + } + } while(0); +} +#endif /* defined(RTGUI_IMAGE_TJPGD) */ +/***************************************************************************//** + * @} + ******************************************************************************/ diff --git a/components/rtgui/common/image_png.c b/components/rtgui/common/image_png.c index 9c72ef02f4..5c858bfd6e 100644 --- a/components/rtgui/common/image_png.c +++ b/components/rtgui/common/image_png.c @@ -242,9 +242,16 @@ static void rtgui_image_png_unload(struct rtgui_image* image) static void rtgui_image_png_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtgui_rect* rect) { + struct rtgui_graphic_driver* hwdev = rtgui_graphic_get_device(); rt_uint16_t x, y, w, h; rtgui_color_t* ptr; struct rtgui_image_png* png; + int fg_maxsample; + int ialpha; + float alpha; + rtgui_color_t color; + rtgui_color_t c, bgcolor; + int fc[3], bc[3]; RT_ASSERT(image != RT_NULL && dc != RT_NULL && rect != RT_NULL); RT_ASSERT(image->data != RT_NULL); @@ -255,21 +262,56 @@ static void rtgui_image_png_blit(struct rtgui_image* image, struct rtgui_dc* dc, else w = rtgui_rect_width(*rect); if (image->h < rtgui_rect_height(*rect)) h = image->h; else h = rtgui_rect_height(*rect); + + fg_maxsample = (1 << png->info_ptr->bit_depth) - 1; if (png->pixels != RT_NULL) { ptr = (rtgui_color_t*)png->pixels; - /* draw each point within dc */ + bgcolor = rtgui_color_from_565(RTGUI_DC_BC(dc)); + bc[0] = RTGUI_RGB_R(bgcolor); + bc[1] = RTGUI_RGB_G(bgcolor); + bc[2] = RTGUI_RGB_B(bgcolor); + /* draw each point within dc */ for (y = 0; y < h; y ++) { for (x = 0; x < w; x++) { - /* not alpha */ - if ((*ptr >> 24) != 255) - { - rtgui_dc_draw_color_point(dc, x + rect->x1, y + rect->y1, *ptr); - } - + c = *ptr; + ialpha = RTGUI_RGB_A(c); + if(ialpha == 0) + { + /* + * Foreground image is transparent hear. + * If the background image is already in the frame + * buffer, there is nothing to do. + */ + } + else if (ialpha == fg_maxsample) + { + /* + * Copy foreground pixel to frame buffer. + */ + rtgui_dc_draw_color_point(dc, x + rect->x1, y + rect->y1, c); + } + else + { /* output = alpha * foreground + (1-alpha) * background */ + /* + * Compositing is necessary. + * Get floating-point alpha and its complement. + * Note: alpha is always linear: gamma does not + * affect it. + */ + fc[0] = RTGUI_RGB_R(c); + fc[1] = RTGUI_RGB_G(c); + fc[2] = RTGUI_RGB_B(c); + + alpha = (float) ialpha / fg_maxsample; + color = RTGUI_RGB( (rt_uint8_t)(fc[0]*alpha + bc[0]*(1-alpha)), + (rt_uint8_t)(fc[1]*alpha + bc[1]*(1-alpha)), + (rt_uint8_t)(fc[2]*alpha + bc[2]*(1-alpha))); + rtgui_dc_draw_color_point(dc, x + rect->x1, y + rect->y1, color); + } /* move to next color buffer */ ptr ++; } diff --git a/components/rtgui/common/pixel_driver.c b/components/rtgui/common/pixel_driver.c index 31b22e164e..503efb76cd 100644 --- a/components/rtgui/common/pixel_driver.c +++ b/components/rtgui/common/pixel_driver.c @@ -1,9 +1,23 @@ +/* + * Change Logs: + * Date Author Notes + * 2012-01-24 onelife add mono color support + * 2012-01-24 onelife fix a bug in _pixel_draw_raw_hline + */ #include #include #define gfx_device (rtgui_graphic_get_device()->device) #define gfx_device_ops rt_graphix_ops(gfx_device) +static void _pixel_mono_set_pixel(rtgui_color_t *c, int x, int y) +{ + rt_uint8_t pixel; + + pixel = rtgui_color_to_mono(*c); + gfx_device_ops->set_pixel((char*)&pixel, x, y); +} + static void _pixel_rgb565p_set_pixel(rtgui_color_t *c, int x, int y) { rt_uint16_t pixel; @@ -28,6 +42,14 @@ static void _pixel_rgb888_set_pixel(rtgui_color_t *c, int x, int y) gfx_device_ops->set_pixel((char*)&pixel, x, y); } +static void _pixel_mono_get_pixel(rtgui_color_t *c, int x, int y) +{ + rt_uint8_t pixel; + + gfx_device_ops->get_pixel((char*)&pixel, x, y); + *c = rtgui_color_from_mono(pixel); +} + static void _pixel_rgb565p_get_pixel(rtgui_color_t *c, int x, int y) { rt_uint16_t pixel; @@ -52,6 +74,14 @@ static void _pixel_rgb888_get_pixel(rtgui_color_t *c, int x, int y) *c = rtgui_color_from_888(pixel); } +static void _pixel_mono_draw_hline(rtgui_color_t *c, int x1, int x2, int y) +{ + rt_uint8_t pixel; + + pixel = rtgui_color_to_mono(*c); + gfx_device_ops->draw_hline((char*)&pixel, x1, x2, y); +} + static void _pixel_rgb565p_draw_hline(rtgui_color_t *c, int x1, int x2, int y) { rt_uint16_t pixel; @@ -76,6 +106,14 @@ static void _pixel_rgb888_draw_hline(rtgui_color_t *c, int x1, int x2, int y) gfx_device_ops->draw_hline((char*)&pixel, x1, x2, y); } +static void _pixel_mono_draw_vline(rtgui_color_t *c, int x, int y1, int y2) +{ + rt_uint8_t pixel; + + pixel = rtgui_color_to_mono(*c); + gfx_device_ops->draw_vline((char*)&pixel, x, y1, y2); +} + static void _pixel_rgb565p_draw_vline(rtgui_color_t *c, int x, int y1, int y2) { rt_uint16_t pixel; @@ -102,13 +140,19 @@ static void _pixel_rgb888_draw_vline(rtgui_color_t *c, int x, int y1, int y2) static void _pixel_draw_raw_hline(rt_uint8_t *pixels, int x1, int x2, int y) { - if (x2 > x1) - gfx_device_ops->blit_line((char*)pixels, x1, y, (x2 - x1)); - else - gfx_device_ops->blit_line((char*)pixels, x2, y, (x1 - x2)); + gfx_device_ops->blit_line((char*)pixels, x1, x2, y); } /* pixel device */ +const struct rtgui_graphic_driver_ops _pixel_mono_ops = +{ + _pixel_mono_set_pixel, + _pixel_mono_get_pixel, + _pixel_mono_draw_hline, + _pixel_mono_draw_vline, + _pixel_draw_raw_hline, +}; + const struct rtgui_graphic_driver_ops _pixel_rgb565p_ops = { _pixel_rgb565p_set_pixel, @@ -140,6 +184,9 @@ const struct rtgui_graphic_driver_ops *rtgui_pixel_device_get_ops(int pixel_form { switch (pixel_format) { + case RTGRAPHIC_PIXEL_FORMAT_MONO: + return &_pixel_mono_ops; + case RTGRAPHIC_PIXEL_FORMAT_RGB565: return &_pixel_rgb565_ops; diff --git a/components/rtgui/common/rtgui_app.c b/components/rtgui/common/rtgui_app.c new file mode 100644 index 0000000000..f16a97cbf5 --- /dev/null +++ b/components/rtgui/common/rtgui_app.c @@ -0,0 +1,380 @@ +/* + * File : rtgui_application.c + * This file is part of RTGUI in RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-01-13 Grissiom first version(just a prototype of application API) + * 2012-07-07 Bernard move the send/recv message to the rtgui_system.c + */ + +#include +#include +#include + +static void _rtgui_app_constructor(struct rtgui_app *app) +{ + /* set event handler */ + rtgui_object_set_event_handler(RTGUI_OBJECT(app), + rtgui_app_event_handler); + + app->name = RT_NULL; + /* set EXITED so we can destroy an application that just created */ + app->state_flag = RTGUI_APP_FLAG_EXITED; + app->ref_count = 0; + app->exit_code = 0; + app->tid = RT_NULL; + app->server = RT_NULL; + app->mq = RT_NULL; + app->modal_object = RT_NULL; + app->main_object = RT_NULL; + app->on_idle = RT_NULL; +} + +static void _rtgui_app_destructor(struct rtgui_app *app) +{ + RT_ASSERT(app != RT_NULL); + + rt_free(app->name); + app->name = RT_NULL; +} + +DEFINE_CLASS_TYPE(application, "application", + RTGUI_OBJECT_TYPE, + _rtgui_app_constructor, + _rtgui_app_destructor, + sizeof(struct rtgui_app)); + +struct rtgui_app* rtgui_app_create( + rt_thread_t tid, + const char *title) +{ + rt_thread_t srv_tid; + struct rtgui_app *app; + struct rtgui_event_application event; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(title != RT_NULL); + + /* create application */ + app = RTGUI_APP(rtgui_object_create(RTGUI_APP_TYPE)); + if (app == RT_NULL) + return RT_NULL; + + /* one thread only can create one rtgui application */ + RT_ASSERT(tid->user_data == 0); + app->tid = tid; + /* set user thread */ + tid->user_data = (rt_uint32_t)app; + + app->mq = rt_mq_create("rtgui", sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO); + if (app->mq == RT_NULL) + { + rt_kprintf("create msgq failed.\n"); + goto __mq_err; + } + + /* set application title */ + app->name = (unsigned char*)rt_strdup((char*)title); + if (app->name == RT_NULL) + goto __err; + + /* send a message to notify rtgui server */ + srv_tid = rtgui_get_server(); + if (srv_tid == RT_NULL) + { + rt_kprintf("gui server is not running.\n"); + goto __err; + } + + /* create the rtgui server application */ + if (srv_tid == rt_thread_self()) + return app; + + RTGUI_EVENT_APP_CREATE_INIT(&event); + event.app = app; + + /* notify rtgui server to one application has been created */ + if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) == RT_EOK) + { + return app; + } + +__err: +__mq_err: + rtgui_object_destroy(RTGUI_OBJECT(app)); + tid->user_data = 0; + return RT_NULL; +} + +#define _rtgui_application_check(app) \ + do { \ + RT_ASSERT(app != RT_NULL); \ + RT_ASSERT(app->tid != RT_NULL); \ + RT_ASSERT(app->tid->user_data != 0); \ + RT_ASSERT(app->mq != RT_NULL); \ + } while (0) + +void rtgui_app_destroy(struct rtgui_app *app) +{ + rt_thread_t srv_tid; + _rtgui_application_check(app); + + if (!(app->state_flag & RTGUI_APP_FLAG_EXITED)) + { + rt_kprintf("cannot destroy a running application: %s.\n", + app->name); + return; + } + + /* send a message to notify rtgui server */ + srv_tid = rtgui_get_server(); + if (srv_tid != rt_thread_self()) /* must not the server thread */ + { + struct rtgui_event_application event; + RTGUI_EVENT_APP_DESTROY_INIT(&event); + event.app = app; + + if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) != RT_EOK) + { + rt_kprintf("destroy an application in server failed\n"); + return ; + } + } + + app->tid->user_data = 0; + rt_mq_delete(app->mq); + rtgui_object_destroy(RTGUI_OBJECT(app)); +} + +struct rtgui_app* rtgui_app_self(void) +{ + struct rtgui_app *app; + rt_thread_t self; + + /* get current thread */ + self = rt_thread_self(); + app = (struct rtgui_app*)(self->user_data); + + return app; +} + +void rtgui_app_set_onidle(rtgui_idle_func_t onidle) +{ + struct rtgui_app *app; + + app = rtgui_app_self(); + if (app != RT_NULL) + app->on_idle = onidle; +} + +rtgui_idle_func_t rtgui_app_get_onidle(void) +{ + struct rtgui_app *app; + + app = rtgui_app_self(); + if (app != RT_NULL) + return app->on_idle; + else + return RT_NULL; +} + +rt_inline rt_bool_t _rtgui_application_dest_handle( + struct rtgui_app *app, + struct rtgui_event *event) +{ + struct rtgui_event_win* wevent = (struct rtgui_event_win*)event; + + struct rtgui_object* dest_object = RTGUI_OBJECT(wevent->wid); + + if (dest_object != RT_NULL) + { + if (dest_object->event_handler != RT_NULL) + return dest_object->event_handler(RTGUI_OBJECT(dest_object), event); + else + return RT_FALSE; + } + else + { + rt_kprintf("RTGUI ERROR:server sent a event(%d) without wid\n", event->type); + return RT_FALSE; + } +} + +rt_bool_t rtgui_app_event_handler(struct rtgui_object* object, rtgui_event_t* event) +{ + struct rtgui_app* app; + + RT_ASSERT(object != RT_NULL); + RT_ASSERT(event != RT_NULL); + + app = RTGUI_APP(object); + + switch (event->type) + { + case RTGUI_EVENT_PAINT: + case RTGUI_EVENT_CLIP_INFO: + case RTGUI_EVENT_WIN_ACTIVATE: + case RTGUI_EVENT_WIN_DEACTIVATE: + case RTGUI_EVENT_WIN_CLOSE: + case RTGUI_EVENT_WIN_MOVE: + case RTGUI_EVENT_KBD: + _rtgui_application_dest_handle(app, event); + break; + + case RTGUI_EVENT_APP_ACTIVATE: + if (app->main_object != RT_NULL) + { + rtgui_win_activate(RTGUI_WIN(app->main_object)); + if (app->modal_object != RT_NULL) + rtgui_win_activate(RTGUI_WIN(app->modal_object)); + } + else if (app->modal_object != RT_NULL) + { + rtgui_win_activate(RTGUI_WIN(app->modal_object)); + } + break; + + case RTGUI_EVENT_MOUSE_BUTTON: + case RTGUI_EVENT_MOUSE_MOTION: + { + struct rtgui_event_win* wevent = (struct rtgui_event_win*)event; + struct rtgui_object* dest_object = RTGUI_OBJECT(wevent->wid); + + // FIXME: let application determine the dest_wiget but not in sever + // so we can combine this handler with above one + if (app->modal_object != RT_NULL && + dest_object != app->modal_object) + { +// rt_kprintf("discard event %s that is not sent to modal object\n", +// event_string[event->type]); + } + else + { + _rtgui_application_dest_handle(app, event); + } + } + break; + + case RTGUI_EVENT_TIMER: + { + struct rtgui_timer* timer; + struct rtgui_event_timer* etimer = (struct rtgui_event_timer*) event; + + timer = etimer->timer; + if (timer->timeout != RT_NULL) + { + /* call timeout function */ + timer->timeout(timer, timer->user_data); + } + } + break; + + case RTGUI_EVENT_COMMAND: + { + struct rtgui_event_command *ecmd = (struct rtgui_event_command*)event; + + if (ecmd->wid != RT_NULL) + return _rtgui_application_dest_handle(app, event); + } + + default: + return rtgui_object_event_handler(object, event); + } + + return RT_TRUE; +} + +rt_inline void _rtgui_application_event_loop(struct rtgui_app *app) +{ + rt_err_t result; + rt_uint16_t current_ref; + struct rtgui_event *event; + + _rtgui_application_check(app); + + /* point to event buffer */ + event = (struct rtgui_event*)app->event_buffer; + + current_ref = ++app->ref_count; + + while (current_ref <= app->ref_count) + { + RT_ASSERT(current_ref == app->ref_count); + + if (app->on_idle != RT_NULL) + { + result = rtgui_recv_nosuspend(event, sizeof(union rtgui_event_generic)); + if (result == RT_EOK) + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + else if (result == -RT_ETIMEOUT) + app->on_idle(RTGUI_OBJECT(app), RT_NULL); + } + else + { + result = rtgui_recv(event, sizeof(union rtgui_event_generic)); + if (result == RT_EOK) + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + } + } +} + +rt_base_t rtgui_app_run(struct rtgui_app *app) +{ + _rtgui_application_check(app); + + app->state_flag &= ~RTGUI_APP_FLAG_EXITED; + + _rtgui_application_event_loop(app); + + if (app->ref_count == 0) + app->state_flag |= RTGUI_APP_FLAG_EXITED; + + return app->exit_code; +} + +void rtgui_app_exit(struct rtgui_app* app, rt_uint16_t code) +{ + --app->ref_count; + app->exit_code = code; +} + +/** + * set this application as window manager + */ +rt_err_t rtgui_app_set_as_wm(void) +{ + rt_thread_t srv_tid; + struct rtgui_event_set_wm event; + struct rtgui_app* app; + + srv_tid = rtgui_get_server(); + app = rtgui_app_self(); + if (app != RT_NULL && srv_tid != RT_NULL) + { + /* notify rtgui server, this is a window manager */ + RTGUI_EVENT_SET_WM_INIT(&event); + event.app = app; + + rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)); + return RT_EOK; + } + + return RT_ERROR; +} + +void rtgui_app_set_main_win(struct rtgui_win* win) +{ + struct rtgui_app *app; + + app = rtgui_app_self(); + if (app != RT_NULL) + { + app->main_object = RTGUI_OBJECT(win); + } +} diff --git a/components/rtgui/common/rtgui_system.c b/components/rtgui/common/rtgui_system.c index b840893139..dce11bfaf5 100644 --- a/components/rtgui/common/rtgui_system.c +++ b/components/rtgui/common/rtgui_system.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,7 +26,7 @@ #define RTGUI_MEM_TRACE #endif -void rtgui_system_server_init(void) +void rtgui_system_server_init() { /* init image */ rtgui_system_image_init(); @@ -59,7 +59,7 @@ static void rtgui_time_out(void* parameter) event.timer = timer; - rtgui_application_send(timer->tid, &(event.parent), sizeof(rtgui_event_timer_t)); + rtgui_send(timer->tid, &(event.parent), sizeof(rtgui_event_timer_t)); } rtgui_timer_t* rtgui_timer_create(rt_int32_t time, rt_int32_t flag, rtgui_timeout_func timeout, void* parameter) @@ -285,3 +285,416 @@ void rtgui_free(void* ptr) rt_free(ptr); } +#if defined(RTGUI_MEM_TRACE) && defined(RT_USING_FINSH) +#include +void list_mem(void) +{ + rt_kprintf("Current Used: %d, Maximal Used: %d\n", mem_info.allocated_size, mem_info.max_allocated); +} +FINSH_FUNCTION_EXPORT(list_mem, display memory information); +#endif + +/************************************************************************/ +/* RTGUI Event Dump */ +/************************************************************************/ + +#ifdef _WIN32 +#define RTGUI_EVENT_DEBUG +#endif + +#ifdef RTGUI_EVENT_DEBUG +const char *event_string[] = +{ + /* application event */ + "APP_CREATE", /* create an application */ + "APP_DESTROY", /* destroy an application */ + "APP_ACTIVATE", /* activate an application */ + + /* window event */ + "WIN_CREATE", /* create a window */ + "WIN_DESTROY", /* destroy a window */ + "WIN_SHOW", /* show a window */ + "WIN_HIDE", /* hide a window */ + "WIN_ACTIVATE", /* activate a window */ + "WIN_DEACTIVATE", /* deactivate a window */ + "WIN_CLOSE", /* close a window */ + "WIN_MOVE", /* move a window */ + "WIN_RESIZE", /* resize a window */ + "WIN_MODAL_ENTER", /* a window modals */ + + "SET_WM", /* set window manager */ + + "UPDATE_BEGIN", /* begin of update rect */ + "UPDATE_END", /* end of update rect */ + "MONITOR_ADD", /* add a monitor rect */ + "MONITOR_REMOVE", /* remove a monitor rect*/ + "SHOW", /* the widget is going to be shown */ + "HIDE", /* the widget is going to be hidden */ + "PAINT", /* paint on screen */ + "TIMER", /* timer */ + + /* clip rect information */ + "CLIP_INFO", /* clip rect info */ + + /* mouse and keyboard event */ + "MOUSE_MOTION", /* mouse motion */ + "MOUSE_BUTTON", /* mouse button info */ + "KBD", /* keyboard info */ + + /* user command event */ + "COMMAND", /* user command */ + + /* request's status event */ + "STATUS", /* request result */ + "SCROLLED", /* scroll bar scrolled */ + "RESIZE", /* widget resize */ +}; + +#define DBG_MSG(x) rt_kprintf x + +static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t* event) +{ + char* sender = "(unknown)"; + + if ((event->type == RTGUI_EVENT_TIMER) || + (event->type == RTGUI_EVENT_UPDATE_BEGIN) || + (event->type == RTGUI_EVENT_MOUSE_MOTION) || + (event->type == RTGUI_EVENT_UPDATE_END)) + { + /* don't dump timer event */ + return ; + } + + if (event->sender != RT_NULL) + sender = event->sender->name; + + rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], tid->name); + switch (event->type) + { + case RTGUI_EVENT_APP_CREATE: + case RTGUI_EVENT_APP_DESTROY: + case RTGUI_EVENT_APP_ACTIVATE: + { + struct rtgui_event_application *eapp = (struct rtgui_event_application *)event; + + rt_kprintf("app: %s", eapp->app->name); + } + break; + + case RTGUI_EVENT_PAINT: + { + struct rtgui_event_paint *paint = (struct rtgui_event_paint *)event; + + if(paint->wid != RT_NULL) + rt_kprintf("win: %s", paint->wid->title); + } + break; + + case RTGUI_EVENT_KBD: + { + struct rtgui_event_kbd *ekbd = (struct rtgui_event_kbd*) event; + if (ekbd->wid != RT_NULL) + rt_kprintf("win: %s", ekbd->wid->title); + if (RTGUI_KBD_IS_UP(ekbd)) rt_kprintf(", up"); + else rt_kprintf(", down"); + } + break; + + case RTGUI_EVENT_CLIP_INFO: + { + struct rtgui_event_clip_info *info = (struct rtgui_event_clip_info *)event; + + if(info->wid != RT_NULL) + rt_kprintf("win: %s", info->wid->title); + } + break; + + case RTGUI_EVENT_WIN_CREATE: + { + struct rtgui_event_win_create *create = (struct rtgui_event_win_create*)event; + + rt_kprintf(" win: %s at (x1:%d, y1:%d, x2:%d, y2:%d), addr: %p", +#ifdef RTGUI_USING_SMALL_SIZE + create->wid->title, + RTGUI_WIDGET(create->wid)->extent.x1, + RTGUI_WIDGET(create->wid)->extent.y1, + RTGUI_WIDGET(create->wid)->extent.x2, + RTGUI_WIDGET(create->wid)->extent.y2, +#else + create->title, + create->extent.x1, + create->extent.y1, + create->extent.x2, + create->extent.y2, +#endif + create->wid + ); + } + break; + + case RTGUI_EVENT_UPDATE_END: + { + struct rtgui_event_update_end* update_end = (struct rtgui_event_update_end*)event; + rt_kprintf("(x:%d, y1:%d, x2:%d, y2:%d)", update_end->rect.x1, + update_end->rect.y1, + update_end->rect.x2, + update_end->rect.y2); + } + break; + + case RTGUI_EVENT_WIN_ACTIVATE: + case RTGUI_EVENT_WIN_DEACTIVATE: + case RTGUI_EVENT_WIN_SHOW: + case RTGUI_EVENT_WIN_MODAL_ENTER: + { + struct rtgui_event_win *win = (struct rtgui_event_win *)event; + + if(win->wid != RT_NULL) + rt_kprintf("win: %s", win->wid->title); + } + break; + + case RTGUI_EVENT_WIN_MOVE: + { + struct rtgui_event_win_move *win = (struct rtgui_event_win_move *)event; + + if(win->wid != RT_NULL) + { + rt_kprintf("win: %s", win->wid->title); + rt_kprintf(" to (x:%d, y:%d)", win->x, win->y); + } + } + break; + + case RTGUI_EVENT_WIN_RESIZE: + { + struct rtgui_event_win_resize* win = (struct rtgui_event_win_resize *)event; + + if (win->wid != RT_NULL) + { + rt_kprintf("win: %s, rect(x1:%d, y1:%d, x2:%d, y2:%d)", win->wid->title, + RTGUI_WIDGET(win->wid)->extent.x1, + RTGUI_WIDGET(win->wid)->extent.y1, + RTGUI_WIDGET(win->wid)->extent.x2, + RTGUI_WIDGET(win->wid)->extent.y2); + } + } + break; + + case RTGUI_EVENT_MOUSE_BUTTON: + case RTGUI_EVENT_MOUSE_MOTION: + { + struct rtgui_event_mouse *mouse = (struct rtgui_event_mouse*)event; + + if (mouse->button & RTGUI_MOUSE_BUTTON_LEFT) rt_kprintf("left "); + else rt_kprintf("right "); + + if (mouse->button & RTGUI_MOUSE_BUTTON_DOWN) rt_kprintf("down "); + else rt_kprintf("up "); + + if (mouse->wid != RT_NULL) + rt_kprintf("win: %s at (%d, %d)", mouse->wid->title, + mouse->x, mouse->y); + else + rt_kprintf("(%d, %d)", mouse->x, mouse->y); + } + break; + + case RTGUI_EVENT_MONITOR_ADD: + { + struct rtgui_event_monitor *monitor = (struct rtgui_event_monitor*)event; + if (monitor->wid != RT_NULL) + { + rt_kprintf("win: %s, the rect is:(%d, %d) - (%d, %d)", monitor->wid->title, + monitor->rect.x1, monitor->rect.y1, + monitor->rect.x2, monitor->rect.y2); + } + } + break; + } + + rt_kprintf("\n"); +} +#else +#define DBG_MSG(x) +#define rtgui_event_dump(tid, event) +#endif + +/************************************************************************/ +/* RTGUI IPC APIs */ +/************************************************************************/ +rt_err_t rtgui_send(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t result; + struct rtgui_app *app; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* find struct rtgui_application */ + app = (struct rtgui_app*) (tid->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + result = rt_mq_send(app->mq, event, event_size); + if (result != RT_EOK) + { + if (event->type != RTGUI_EVENT_TIMER) + rt_kprintf("send event to %s failed\n", app->tid->name); + } + + return result; +} + +rt_err_t rtgui_send_urgent(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t result; + struct rtgui_app *app; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* find rtgui_application */ + app = (struct rtgui_app*) (tid->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + result = rt_mq_urgent(app->mq, event, event_size); + if (result != RT_EOK) + rt_kprintf("send ergent event failed\n"); + + return result; +} + +rt_err_t rtgui_send_sync(rt_thread_t tid, rtgui_event_t* event, rt_size_t event_size) +{ + rt_err_t r; + struct rtgui_app *app; + rt_int32_t ack_buffer, ack_status; + struct rt_mailbox ack_mb; + + RT_ASSERT(tid != RT_NULL); + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + rtgui_event_dump(tid, event); + + /* init ack mailbox */ + r = rt_mb_init(&ack_mb, "ack", &ack_buffer, 1, 0); + if (r!= RT_EOK) + goto __return; + + app = (struct rtgui_app*) (tid->user_data); + if (app == RT_NULL) + { + r = -RT_ERROR; + goto __return; + } + + event->ack = &ack_mb; + r = rt_mq_send(app->mq, event, event_size); + if (r != RT_EOK) + { + rt_kprintf("send sync event failed\n"); + goto __return; + } + + r = rt_mb_recv(&ack_mb, (rt_uint32_t*)&ack_status, RT_WAITING_FOREVER); + if (r!= RT_EOK) + goto __return; + + if (ack_status != RTGUI_STATUS_OK) + r = -RT_ERROR; + else + r = RT_EOK; + +__return: + /* fini ack mailbox */ + rt_mb_detach(&ack_mb); + return r; +} + +rt_err_t rtgui_ack(rtgui_event_t* event, rt_int32_t status) +{ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event->ack != RT_NULL); + + rt_mb_send(event->ack, status); + + return RT_EOK; +} + +rt_err_t rtgui_recv(rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_app* app; + rt_err_t r; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + app = (struct rtgui_app*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + r = rt_mq_recv(app->mq, event, event_size, RT_WAITING_FOREVER); + + return r; +} + +rt_err_t rtgui_recv_nosuspend(rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_app *app; + rt_err_t r; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event != 0); + + app = (struct rtgui_app*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + r = rt_mq_recv(app->mq, event, event_size, 0); + + return r; +} + +rt_err_t rtgui_recv_filter(rt_uint32_t type, rtgui_event_t* event, rt_size_t event_size) +{ + struct rtgui_app *app; + + RT_ASSERT(event != RT_NULL); + RT_ASSERT(event_size != 0); + + app = (struct rtgui_app*) (rt_thread_self()->user_data); + if (app == RT_NULL) + return -RT_ERROR; + + while (rt_mq_recv(app->mq, event, event_size, RT_WAITING_FOREVER) == RT_EOK) + { + if (event->type == type) + { + return RT_EOK; + } + else + { + if (RTGUI_OBJECT(app)->event_handler != RT_NULL) + { + RTGUI_OBJECT(app)->event_handler(RTGUI_OBJECT(app), event); + } + } + } + + return -RT_ERROR; +} + +rt_thread_t rtgui_get_server(void) +{ + return rt_thread_find("rtgui"); +} + -- cgit v1.3.1