Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 21463) +++ apps/lang/english.lang (working copy) @@ -12559,3 +12559,17 @@ touchscreen: "Reset Calibration" + + id: LANG_WPS_RAM_USAGE + desc: in the info screen, display amount of bytes used by WPS + user: + + *: "WPS RAM Usage:" + + + *: "WPS RAM Usage:" + + + *: "WPS RAM Usage" + + Index: apps/settings.c =================================================================== --- apps/settings.c (revision 21463) +++ apps/settings.c (working copy) @@ -841,6 +841,11 @@ #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 unload_remote_wps_backdrop(); #endif + + wps_buffer_init(); /* reinitialise the wps buffer here instead of in + * wps_data_load() to protect it when there is + * more than one screen... This does mean that there + * will be waste if you just load a .wps file */ if ( global_settings.wps_file[0] && global_settings.wps_file[0] != 0xff ) { snprintf(buf, sizeof buf, WPS_DIR "/%s.wps", Index: apps/gui/wps/wps_buffer.c =================================================================== --- apps/gui/wps/wps_buffer.c (revision 0) +++ apps/gui/wps/wps_buffer.c (revision 0) @@ -0,0 +1,90 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: wps_parser.c 19880 2009-01-29 20:49:43Z mcuelenaere $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * Copyright (C) 2009 Jonathan Gordon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include "config.h" +#include "buffer.h" +#include "settings.h" + +/* WPS buffer management. + * This module is used to allocate space in a single global WPS buffer for + * tokens for both/all screens. + * + * This is mostly just copy/paste from firmware/buffer.c + */ + +static unsigned char *buffer_start = NULL, *buffer_pos = NULL; +static size_t buf_size; +#define IMG_BUFSIZE ((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ + + (2*LCD_HEIGHT*LCD_WIDTH/8)) +void wps_buffer_init(void) +{ + if (buffer_start == NULL) + { + /* WAY more than needed but sensible untill configurable */ + buf_size = IMG_BUFSIZE;/* global_settings.wps_buf_size */ + + buffer_start = buffer_alloc(buf_size); + buffer_pos = buffer_start; + } + else + { + /* reset the buffer.... */ + buffer_pos = buffer_start; + } +} + +/* get the number of bytes currently being used */ +size_t wps_buffer_usage(void) +{ + return buffer_pos-buffer_start; +} + +/* Allocate size bytes from the buffer */ +void* wps_buffer_alloc(size_t size) +{ + void* retval = buffer_pos; + if (wps_buffer_usage()+size >= buf_size) + { + return NULL; + } + buffer_pos += size; + /* 32-bit aligned */ + buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); + return retval; +} + +void* wps_buffer_grab(size_t *freespace) +{ + *freespace = buf_size - wps_buffer_usage(); + return buffer_pos; +} + +void wps_buffer_increment(size_t used) +{ + buffer_pos += used; + /* 32-bit aligned */ + buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); +} + Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 21463) +++ apps/gui/gwps-common.c (working copy) @@ -290,8 +290,12 @@ #if LCD_DEPTH > 1 if (display->depth > 1) { - data->viewports[0].vp.fg_pattern = display->get_foreground(); - data->viewports[0].vp.bg_pattern = display->get_background(); + struct wps_viewport *vp = find_viewport(data, VP_LABEL_DEFAULT); + if (vp) + { + vp->vp.fg_pattern = display->get_foreground(); + vp->vp.bg_pattern = display->get_background(); + } } #endif display->clear_display(); @@ -426,15 +430,40 @@ pb->x, pb->x + pb->width, y+1, pb->height-2); } +struct gui_img* find_img(struct wps_data *wps_data, char id) +{ + struct wpsll *llitem = wps_data->images; + struct gui_img *img; + for(llitem = wps_data->images; llitem; llitem = llitem->next) + { + img = (struct gui_img *)llitem->token->value.data; + if (img->id == id) + return img; + } + return NULL; +} +struct wps_viewport* find_viewport(struct wps_data *wps_data, char id) +{ + struct wpsll *llitem = wps_data->viewports; + struct wps_viewport *vp; + for(llitem = wps_data->viewports; llitem; llitem = llitem->next) + { + vp = (struct wps_viewport *)llitem->token->value.data; + if (vp->label == id) + return vp; + } + return NULL; +} /* clears the area where the image was shown */ static void clear_image_pos(struct gui_wps *gwps, int n) { if(!gwps) return; struct wps_data *data = gwps->data; + struct gui_img *img = find_img(data, n); gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - gwps->display->fillrect(data->img[n].x, data->img[n].y, - data->img[n].bm.width, data->img[n].subimage_height); + gwps->display->fillrect(img->x, img->y, + img->bm.width, img->subimage_height); gwps->display->set_drawmode(DRMODE_SOLID); } @@ -442,26 +471,27 @@ { struct screen *display = gwps->display; struct wps_data *data = gwps->data; - if(data->img[n].always_display) + struct gui_img *img = find_img(data, n); + if(img->always_display) display->set_drawmode(DRMODE_FG); else display->set_drawmode(DRMODE_SOLID); #if LCD_DEPTH > 1 - if(data->img[n].bm.format == FORMAT_MONO) { + if(img->bm.format == FORMAT_MONO) { #endif - display->mono_bitmap_part(data->img[n].bm.data, - 0, data->img[n].subimage_height * subimage, - data->img[n].bm.width, data->img[n].x, - data->img[n].y, data->img[n].bm.width, - data->img[n].subimage_height); + display->mono_bitmap_part(img->bm.data, + 0, img->subimage_height * subimage, + img->bm.width, img->x, + img->y, img->bm.width, + img->subimage_height); #if LCD_DEPTH > 1 } else { - display->transparent_bitmap_part((fb_data *)data->img[n].bm.data, - 0, data->img[n].subimage_height * subimage, - data->img[n].bm.width, data->img[n].x, - data->img[n].y, data->img[n].bm.width, - data->img[n].subimage_height); + display->transparent_bitmap_part((fb_data *)img->bm.data, + 0, img->subimage_height * subimage, + img->bm.width, img->x, + img->y, img->bm.width, + img->subimage_height); } #endif } @@ -471,20 +501,21 @@ if(!gwps || !gwps->data || !gwps->display) return; - int n; struct wps_data *data = gwps->data; struct screen *display = gwps->display; - - for (n = 0; n < MAX_IMAGES; n++) + struct wpsll *llitem; + for ( llitem = data->images; llitem; llitem = llitem->next) { - if (data->img[n].loaded) + struct gui_img *img = (struct gui_img*)llitem->token->value.data; + if (img->loaded) { - if (data->img[n].display >= 0) + if (img->display >= 0) { - wps_draw_image(gwps, n, data->img[n].display); - } else if (data->img[n].always_display && data->img[n].vp == vp) + wps_draw_image(gwps, img->id, img->display); + } + else if (img->always_display && img->vp == vp) { - wps_draw_image(gwps, n, 0); + wps_draw_image(gwps, img->id, 0); } } } @@ -726,7 +757,7 @@ return &(token->value.c); case WPS_TOKEN_STRING: - return data->strings[token->value.i]; + return token->value.data; case WPS_TOKEN_TRACK_TIME_ELAPSED: format_time(buf, buf_size, @@ -1495,12 +1526,11 @@ #ifdef HAVE_LCD_BITMAP case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY: { - struct gui_img *img = data->img; - int n = data->tokens[i].value.i & 0xFF; - int subimage = data->tokens[i].value.i >> 8; - - if (n >= 0 && n < MAX_IMAGES && img[n].loaded) - img[n].display = subimage; + char n = data->tokens[i].value.i & 0xFF; + struct gui_img *img = find_img(data, n); + int subimage = (data->tokens[i].value.i >> 8)&0xff; + if (img->loaded) + img->display = subimage; break; } #endif @@ -1543,20 +1573,11 @@ break; case WPS_VIEWPORT_ENABLE: { - char label = data->tokens[i].value.i; - int j; + struct wps_viewport *thisvp = data->tokens[i].value.data; char temp = VP_DRAW_HIDEABLE; - for(j=0;jnum_viewports;j++) - { - temp = VP_DRAW_HIDEABLE; - if ((data->viewports[j].hidden_flags&VP_DRAW_HIDEABLE) && - (data->viewports[j].label == label)) - { - if (data->viewports[j].hidden_flags&VP_DRAW_WASHIDDEN) - temp |= VP_DRAW_WASHIDDEN; - data->viewports[j].hidden_flags = temp; - } - } + if (thisvp->hidden_flags&VP_DRAW_WASHIDDEN) + temp |= VP_DRAW_WASHIDDEN; + thisvp->hidden_flags = temp; } break; default: @@ -1882,7 +1903,7 @@ if (!id3) return false; - int v, line, i, subline_idx; + int line, i, subline_idx; unsigned flags; char linebuf[MAX_PATH]; @@ -1909,7 +1930,8 @@ /* reset to first subline if refresh all flag is set */ if (refresh_mode == WPS_REFRESH_ALL) { - display->set_viewport(&data->viewports[0].vp); + struct wps_viewport *wvp = find_viewport(data, VP_LABEL_DEFAULT); + display->set_viewport(&wvp->vp); display->clear_viewport(); for (i = 0; i <= data->num_lines; i++) @@ -1929,51 +1951,56 @@ state->ff_rewind_count = ffwd_offset; /* disable any viewports which are conditionally displayed */ - for (v = 0; v < data->num_viewports; v++) + struct wpsll *viewportll; + int vp_refresh_mode = refresh_mode; + for(viewportll=data->viewports; viewportll; viewportll = viewportll->next) { - if (data->viewports[v].hidden_flags&VP_DRAW_HIDEABLE) + struct wps_viewport *wvp = viewportll->token->value.data; + if (wvp->hidden_flags&VP_DRAW_HIDEABLE) { - if (data->viewports[v].hidden_flags&VP_DRAW_HIDDEN) - data->viewports[v].hidden_flags |= VP_DRAW_WASHIDDEN; + if (wvp->hidden_flags&VP_DRAW_HIDDEN) + wvp->hidden_flags |= VP_DRAW_WASHIDDEN; else - data->viewports[v].hidden_flags |= VP_DRAW_HIDDEN; + wvp->hidden_flags |= VP_DRAW_HIDDEN; } } - for (v = 0; v < data->num_viewports; v++) + for(viewportll=data->viewports; viewportll; viewportll = viewportll->next) { - struct wps_viewport *wps_vp = &(data->viewports[v]); - unsigned vp_refresh_mode = refresh_mode; - display->set_viewport(&wps_vp->vp); - + struct wps_viewport *wvp = viewportll->token->value.data; + display->set_viewport(&wvp->vp); + vp_refresh_mode = refresh_mode; + #ifdef HAVE_LCD_BITMAP /* Set images to not to be displayed */ - for (i = 0; i < MAX_IMAGES; i++) + struct wpsll *llitem; + for ( llitem = data->images; llitem; llitem = llitem->next) { - data->img[i].display = -1; + struct gui_img *img = (struct gui_img*)llitem->token->value.data; + img->display = -1; } #endif /* dont redraw the viewport if its disabled */ - if ((wps_vp->hidden_flags&VP_DRAW_HIDDEN)) + if ((wvp->hidden_flags&VP_DRAW_HIDDEN)) { - if (!(wps_vp->hidden_flags&VP_DRAW_WASHIDDEN)) - display->scroll_stop(&wps_vp->vp); - wps_vp->hidden_flags |= VP_DRAW_WASHIDDEN; + if (!(wvp->hidden_flags&VP_DRAW_WASHIDDEN)) + display->scroll_stop(&wvp->vp); + wvp->hidden_flags |= VP_DRAW_WASHIDDEN; continue; } - else if (((wps_vp->hidden_flags& + else if (((wvp->hidden_flags& (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) { vp_refresh_mode = WPS_REFRESH_ALL; - wps_vp->hidden_flags = VP_DRAW_HIDEABLE; + wvp->hidden_flags = VP_DRAW_HIDEABLE; } if (vp_refresh_mode == WPS_REFRESH_ALL) { display->clear_viewport(); } - for (line = wps_vp->first_line; - line <= wps_vp->last_line; line++) + for (line = wvp->first_line; + line <= wvp->last_line; line++) { memset(linebuf, 0, sizeof(linebuf)); update_line = false; @@ -1999,8 +2026,8 @@ /* the peakmeter should be alone on its line */ update_line = false; - int h = font_get(wps_vp->vp.font)->height; - int peak_meter_y = (line - wps_vp->first_line)* h; + int h = font_get(wvp->vp.font)->height; + int peak_meter_y = (line - wvp->first_line)* h; /* The user might decide to have the peak meter in the last line so that it is only displayed if no status bar is @@ -2037,17 +2064,17 @@ viewport there will be a blank line. To get around this we dont allow any actual drawing to happen in the deault vp if other vp's are defined */ - ((data->num_viewports>1 && v!=0) || data->num_viewports == 1)) + ((viewportll->next && wvp->label!=VP_LABEL_DEFAULT) || !viewportll->next)) { if (flags & WPS_REFRESH_SCROLL) { /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) - write_line(display, &align, line - wps_vp->first_line, true); + write_line(display, &align, line - wvp->first_line, true); } else - write_line(display, &align, line - wps_vp->first_line, false); + write_line(display, &align, line - wvp->first_line, false); } } @@ -2055,13 +2082,11 @@ /* progressbar */ if (vp_refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) { - if (wps_vp->pb) - { - draw_progressbar(gwps, wps_vp); - } + if (wvp->pb) + draw_progressbar(gwps, wvp); } /* Now display any images in this viewport */ - wps_display_images(gwps, &wps_vp->vp); + wps_display_images(gwps, &wvp->vp); #endif } Index: apps/gui/wps_debug.c =================================================================== --- apps/gui/wps_debug.c (revision 21463) +++ apps/gui/wps_debug.c (working copy) @@ -43,7 +43,7 @@ return next ? "next " : ""; } -static char *get_token_desc(struct wps_token *token, struct wps_data *data, +static char *get_token_desc(struct wps_token *token, char *buf, int bufsize) { bool next = token->next; @@ -65,7 +65,7 @@ case WPS_TOKEN_STRING: snprintf(buf, bufsize, "String '%s'", - data->strings[token->value.i]); + token->value.data); break; #ifdef HAVE_LCD_BITMAP @@ -456,7 +456,7 @@ /* Dump parsed WPS */ for (i = 0, token = data->tokens; i < data->num_tokens; i++, token++) { - get_token_desc(token, data, buf, sizeof(buf)); + get_token_desc(token, buf, sizeof(buf)); switch(token->type) { @@ -502,26 +502,30 @@ if (wps_verbose_level > 0) { - DEBUGF("Number of viewports : %d\n", data->num_viewports); - for (v = 0; v < data->num_viewports; v++) + struct wpsll *ll; + for (v=0, ll=data->viewports; ll; ll = ll->next, v++) { - DEBUGF("vp %d: First line: %d\n", v, data->viewports[v].first_line); - DEBUGF("vp %d: Last line: %d\n", v, data->viewports[v].last_line); + struct wps_viewport *vp = ll->token->value.data; + DEBUGF("vp %d: First line: %d\n", v, vp->first_line); + DEBUGF("vp %d: Last line: %d\n", v, vp->last_line); } DEBUGF("Number of sublines : %d\n", data->num_sublines); DEBUGF("Number of tokens : %d\n", data->num_tokens); + DEBUGF("Buffer Usage: %ld\n", wps_buffer_usage()); DEBUGF("\n"); } if (wps_verbose_level > 1) { - for (v = 0; v < data->num_viewports; v++) + struct wpsll *ll; + for (v=0, ll=data->viewports; ll; ll = ll->next, v++) { - DEBUGF("Viewport %d - +%d+%d (%dx%d)\n",v,data->viewports[v].vp.x, - data->viewports[v].vp.y, - data->viewports[v].vp.width, - data->viewports[v].vp.height); - for (i = data->viewports[v].first_line, line = &data->lines[data->viewports[v].first_line]; i <= data->viewports[v].last_line; i++,line++) + struct wps_viewport *vp = ll->token->value.data; + DEBUGF("Viewport %d - +%d+%d (%dx%d)\n",v,vp->vp.x, + vp->vp.y, + vp->vp.width, + vp->vp.height); + for (i = vp->first_line, line = &data->lines[vp->first_line]; i <= vp->last_line; i++,line++) { DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", i, line->num_sublines, line->first_subline_idx); @@ -544,36 +548,12 @@ } } } + DEBUGF("Buffer Usage (pre image loading): %ld\n", wps_buffer_usage()); DEBUGF("\n"); } } -static void print_wps_strings(struct wps_data *data) -{ - int i, len, total_len = 0, buf_used = 0; - - if (wps_verbose_level > 1) DEBUGF("Strings:\n"); - for (i = 0; i < data->num_strings; i++) - { - len = strlen(data->strings[i]); - total_len += len; - buf_used += len + 1; - if (wps_verbose_level > 1) - DEBUGF("%2d: (%2d) '%s'\n", i, len, data->strings[i]); - } - if (wps_verbose_level > 1) DEBUGF("\n"); - - if (wps_verbose_level > 0) - { - DEBUGF("Number of unique strings: %d (max: %d)\n", - data->num_strings, WPS_MAX_STRINGS); - DEBUGF("Total string length: %d\n", total_len); - DEBUGF("String buffer used: %d out of %d bytes\n", - buf_used, STRING_BUFFER_SIZE); - DEBUGF("\n"); - } -} #endif void print_debug_info(struct wps_data *data, enum wps_parse_error fail, int line) @@ -582,7 +562,6 @@ if (debug_wps && wps_verbose_level) { dump_wps_tokens(data); - print_wps_strings(data); print_line_info(data); } #endif /* SIMULATOR */ @@ -609,7 +588,7 @@ case PARSE_FAIL_INVALID_CHAR: DEBUGF("ERR: Unexpected conditional char after token %d: \"%s\"", data->num_tokens-1, - get_token_desc(&data->tokens[data->num_tokens-1], data, + get_token_desc(&data->tokens[data->num_tokens-1], buf, sizeof(buf)) ); break; @@ -617,7 +596,7 @@ case PARSE_FAIL_COND_SYNTAX_ERROR: DEBUGF("ERR: Conditional syntax error after token %d: \"%s\"", data->num_tokens-1, - get_token_desc(&data->tokens[data->num_tokens-1], data, + get_token_desc(&data->tokens[data->num_tokens-1], buf, sizeof(buf)) ); break; @@ -625,7 +604,7 @@ case PARSE_FAIL_COND_INVALID_PARAM: DEBUGF("ERR: Invalid parameter list for token %d: \"%s\"", data->num_tokens, - get_token_desc(&data->tokens[data->num_tokens], data, + get_token_desc(&data->tokens[data->num_tokens], buf, sizeof(buf)) ); break; Index: apps/gui/gwps.c =================================================================== --- apps/gui/gwps.c (revision 21463) +++ apps/gui/gwps.c (working copy) @@ -926,7 +926,8 @@ FOR_NB_SCREENS(i) { - struct viewport *vp = &gui_wps[i].data->viewports[0].vp; + struct wps_viewport *wvp = find_viewport(gui_wps[i].data, VP_LABEL_DEFAULT); + struct viewport *vp = &wvp->vp; bool draw = wpsbars & (VP_SB_ONSCREEN(i) | VP_SB_IGNORE_SETTING(i)); if (!draw) { Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 21463) +++ apps/gui/gwps.h (working copy) @@ -62,6 +62,7 @@ #ifdef HAVE_LCD_BITMAP struct gui_img { + short id; struct bitmap bm; struct viewport* vp; /* The viewport to display this image in */ short int x; /* x-pos */ @@ -98,31 +99,16 @@ #ifdef HAVE_LCD_BITMAP -#define MAX_IMAGES (26*2) /* a-z and A-Z */ -#define MAX_PROGRESSBARS 3 - -/* The image buffer is big enough to store one full-screen native bitmap, - plus two full-screen mono bitmaps. */ - -#define IMG_BUFSIZE ((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ - + (2*LCD_HEIGHT*LCD_WIDTH/8)) - -#define WPS_MAX_VIEWPORTS 24 #define WPS_MAX_LINES ((LCD_HEIGHT/5+1) * 2) #define WPS_MAX_SUBLINES (WPS_MAX_LINES*3) #define WPS_MAX_TOKENS 1024 -#define WPS_MAX_STRINGS 128 -#define STRING_BUFFER_SIZE 1024 #define WPS_MAX_COND_LEVEL 10 #else -#define WPS_MAX_VIEWPORTS 2 #define WPS_MAX_LINES 2 #define WPS_MAX_SUBLINES 12 #define WPS_MAX_TOKENS 64 -#define WPS_MAX_STRINGS 32 -#define STRING_BUFFER_SIZE 64 #define WPS_MAX_COND_LEVEL 5 #endif @@ -307,19 +293,8 @@ WPS_TOKEN_SETTING, }; -struct wps_token { - unsigned char type; /* enough to store the token type */ - /* Whether the tag (e.g. track name or the album) refers the - current or the next song (false=current, true=next) */ - bool next; - union { - char c; - unsigned short i; - } value; -}; - /* Description of a subline on the WPS */ struct wps_subline { @@ -358,6 +333,8 @@ #define VP_DRAW_HIDEABLE 0x1 #define VP_DRAW_HIDDEN 0x2 #define VP_DRAW_WASHIDDEN 0x4 +#define VP_LABEL_DEFAULT '\0' +#define VP_LABEL_STATIC '|' struct wps_viewport { struct viewport vp; /* The LCD viewport struct */ struct progressbar *pb; @@ -380,22 +357,40 @@ }; #define MAX_TOUCHREGIONS 12 #endif + +struct wps_token { + unsigned char type; /* enough to store the token type */ + + /* Whether the tag (e.g. track name or the album) refers the + current or the next song (false=current, true=next) */ + bool next; + + union { + char c; + unsigned int i; + void *data; /* pointer into global wps buffer */ + } value; +}; + +struct wpsll { + struct wps_token *token; + struct wpsll *next; +}; + /* wps_data this struct holds all necessary data which describes the viewable content of a wps */ struct wps_data { #ifdef HAVE_LCD_BITMAP - struct gui_img img[MAX_IMAGES]; - unsigned char img_buf[IMG_BUFSIZE]; - unsigned char* img_buf_ptr; - int img_buf_free; bool wps_sb_tag; bool show_sb_on_wps; - struct progressbar progressbar[MAX_PROGRESSBARS]; - short progressbar_count; + struct wpsll *images; + struct wpsll *progressbars; + struct wps_token *backdrop; + bool peak_meter_enabled; #ifdef HAVE_ALBUMART @@ -429,9 +424,7 @@ the index of the line being parsed. */ int num_lines; - /* Number of viewports in the WPS */ - int num_viewports; - struct wps_viewport viewports[WPS_MAX_VIEWPORTS]; + struct wpsll *viewports; struct wps_line lines[WPS_MAX_LINES]; @@ -445,10 +438,8 @@ int num_tokens; struct wps_token tokens[WPS_MAX_TOKENS]; - char string_buffer[STRING_BUFFER_SIZE]; - char *strings[WPS_MAX_STRINGS]; - int num_strings; - + struct wpsll *strings; + bool wps_loaded; /* tick the volume button was last pressed */ @@ -543,4 +534,16 @@ bool gui_sync_wps_uses_albumart(void); #endif + +struct gui_img* find_img(struct wps_data *wps_data, char id); /* in gwps-common.c */ +struct wps_viewport* find_viewport(struct wps_data *wps_data, char id); + +/* wps_buffer functions */ + +void wps_buffer_init(void); +void* wps_buffer_alloc(size_t size); +void* wps_buffer_grab(size_t *freespace); +void wps_buffer_increment(size_t used); +size_t wps_buffer_usage(void); + #endif Index: apps/gui/wps_parser.c =================================================================== --- apps/gui/wps_parser.c (revision 21463) +++ apps/gui/wps_parser.c (working copy) @@ -75,22 +75,9 @@ /* the current line in the file */ static int line; -#ifdef HAVE_LCD_BITMAP +/* the current viewport */ +static struct wps_viewport *curr_vp; -#if LCD_DEPTH > 1 -#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */ -#else -#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */ -#endif - -#define PROGRESSBAR_BMP MAX_IMAGES -#define BACKDROP_BMP (MAX_BITMAPS-1) - -/* pointers to the bitmap filenames in the WPS source */ -static const char *bmp_names[MAX_BITMAPS]; - -#endif /* HAVE_LCD_BITMAP */ - #if defined(DEBUG) || defined(SIMULATOR) /* debugging function */ extern void print_debug_info(struct wps_data *data, int fail, int line); @@ -353,6 +340,36 @@ /* the array MUST end with an empty string (first char is \0) */ }; +/* add a wpsll item to the list chain. ALWAYS appended because some of the + * chains require the order to be kept. + */ +static void add_to_ll_chain(struct wpsll **list, struct wpsll *item) +{ + if (*list == NULL) + *list = item; + else + { + struct wpsll *t = *list; + while (t->next) + t = t->next; + t->next = item; + } +} +/* create and init a new wpsll item. + * passing NULL to token will alloc a new one. + */ +static struct wpsll *new_wpsll_item(struct wps_token *token) +{ + struct wpsll *llitem = wps_buffer_alloc(sizeof(struct wpsll)); + if (!token) + token = wps_buffer_alloc(sizeof(struct wps_token)); + if (!llitem || !token) + return NULL; + llitem->next = NULL; + llitem->token = token; + return llitem; +} + /* Returns the number of chars that should be skipped to jump immediately after the first eol, i.e. to the start of the next line */ static int skip_end_of_line(const char *wps_bufptr) @@ -379,12 +396,13 @@ struct wps_data *wps_data) { (void)token; /* Kill warnings */ + struct wps_viewport *vp = find_viewport(wps_data, VP_LABEL_DEFAULT); wps_data->wps_sb_tag = true; wps_data->show_sb_on_wps = true; - if (wps_data->viewports[0].vp.y == 0) + if (vp->vp.y == 0) { - wps_data->viewports[0].vp.y = STATUSBAR_HEIGHT; - wps_data->viewports[0].vp.height -= STATUSBAR_HEIGHT; + vp->vp.y = STATUSBAR_HEIGHT; + vp->vp.height -= STATUSBAR_HEIGHT; } return skip_end_of_line(wps_bufptr); } @@ -394,12 +412,13 @@ struct wps_data *wps_data) { (void)token; /* Kill warnings */ + struct wps_viewport *vp = find_viewport(wps_data, VP_LABEL_DEFAULT); wps_data->wps_sb_tag = true; wps_data->show_sb_on_wps = false; - if (wps_data->viewports[0].vp.y == STATUSBAR_HEIGHT) + if (vp->vp.y == STATUSBAR_HEIGHT) { - wps_data->viewports[0].vp.y = 0; - wps_data->viewports[0].vp.height += STATUSBAR_HEIGHT; + vp->vp.y = 0; + vp->vp.height += STATUSBAR_HEIGHT; } return skip_end_of_line(wps_bufptr); } @@ -408,16 +427,19 @@ char* filename, struct bitmap *bm) { + (void)wps_data; int format; + size_t bm_space_available; #ifdef HAVE_REMOTE_LCD if (wps_data->remote_wps) format = FORMAT_ANY|FORMAT_REMOTE; else #endif format = FORMAT_ANY|FORMAT_TRANSPARENT; - + bm->data = wps_buffer_grab(&bm_space_available); + int ret = read_bmp_file(filename, bm, - wps_data->img_buf_free, + bm_space_available, format,NULL); if (ret > 0) @@ -426,8 +448,8 @@ if (ret % 2) ret++; /* Always consume an even number of bytes */ #endif - wps_data->img_buf_ptr += ret; - wps_data->img_buf_free -= ret; + /* let the buffer manager know how much we used */ + wps_buffer_increment(ret); return true; } @@ -470,11 +492,11 @@ struct wps_token *token, struct wps_data *wps_data) { - (void)wps_data; - int n = get_image_id(wps_bufptr[0]); + char n = (wps_bufptr[0]); + struct gui_img *img = find_img(wps_data, n); int subimage; - if (n == -1) + if (!img) { /* invalid picture display tag */ return WPS_ERROR_INVALID_PARAM; @@ -483,7 +505,7 @@ if ((subimage = get_image_id(wps_bufptr[1])) != -1) { /* Sanity check */ - if (subimage >= wps_data->img[n].num_subimages) + if (subimage >= img->num_subimages) return WPS_ERROR_INVALID_PARAM; /* Store sub-image number to display in high bits */ @@ -499,19 +521,23 @@ struct wps_token *token, struct wps_data *wps_data) { - int n; const char *ptr = wps_bufptr; const char *pos; const char* filename; const char* id; const char *newline; int x,y; - + /* tokens for image lod are not saved, so we need a new copy to be able to link them */ + struct wpsll *llitem = new_wpsll_item((token->type == WPS_TOKEN_IMAGE_DISPLAY)?token:NULL); + struct gui_img *img = wps_buffer_alloc(sizeof(struct gui_img)); + if (!llitem || !img) + return WPS_ERROR_INVALID_PARAM; + + llitem->token->value.data = img; /* format: %x|n|filename.bmp|x|y| or %xl|n|filename.bmp|x|y| or %xl|n|filename.bmp|x|y|num_subimages| */ - if (*ptr != '|') return WPS_ERROR_INVALID_PARAM; @@ -524,28 +550,22 @@ if (*ptr != '|') return WPS_ERROR_INVALID_PARAM; - /* get the image ID */ - n = get_image_id(*id); - - /* check the image number and load state */ - if(n < 0 || n >= MAX_IMAGES || wps_data->img[n].loaded) - { - /* Invalid image ID */ - return WPS_ERROR_INVALID_PARAM; - } - + /* store the image ID */ + img->id = (id[0]); + /* save a pointer to the filename */ - bmp_names[n] = filename; + img->bm.data = (unsigned char*)filename; - wps_data->img[n].x = x; - wps_data->img[n].y = y; + img->x = x; + img->y = y; + img->num_subimages = 1; /* save current viewport */ - wps_data->img[n].vp = &wps_data->viewports[wps_data->num_viewports].vp; + img->vp = &curr_vp->vp; if (token->type == WPS_TOKEN_IMAGE_DISPLAY) { - wps_data->img[n].always_display = true; + img->always_display = true; } else { @@ -554,12 +574,13 @@ newline = strchr(ptr, '\n'); pos = strchr(ptr, '|'); if (pos && pos < newline) - wps_data->img[n].num_subimages = atoi(ptr); + img->num_subimages = atoi(ptr); - if (wps_data->img[n].num_subimages <= 0) + if (img->num_subimages <= 0) return WPS_ERROR_INVALID_PARAM; } - + add_to_ll_chain(&wps_data->images, llitem); + /* Skip the rest of the line */ return skip_end_of_line(wps_bufptr); } @@ -570,13 +591,24 @@ { (void)wps_data; char letter = wps_bufptr[0]; - - if (letter < 'a' || letter > 'z') + struct wps_viewport *vp = find_viewport(wps_data, letter); + /* viewports are regularly mentioned before being setup. + * so if find_viewport() doesnt find one we need to create it first. + * this means in parse_viewport() we need to make sure it hasnt been created yet + * before allocating room on the buffer for one + */ + if (vp == NULL) { - /* invalid viewport tag */ - return WPS_ERROR_INVALID_PARAM; + struct wpsll *llitem = new_wpsll_item(token); + struct wps_viewport *wvp = wps_buffer_alloc(sizeof(struct wps_viewport)); + if (!llitem || !wvp) + return WPS_ERROR_INVALID_PARAM; + token->value.data = wvp; + wvp->label = letter; + add_to_ll_chain(&wps_data->viewports, llitem); + return 1; } - token->value.i = letter; + token->value.data = vp; return 1; } @@ -589,6 +621,10 @@ struct viewport* vp; int depth; uint32_t set = 0; + struct wpsll *llitem = NULL; + struct wps_viewport *wvp = NULL, *prev_vp = curr_vp; + bool add_to_ll = true; + /* tokens for viewport load are not saved, so we need a new copy to be able to link them */ enum { PL_X = 0, PL_Y, @@ -606,15 +642,9 @@ lcd_height = LCD_REMOTE_HEIGHT; } #endif - - if (wps_data->num_viewports >= WPS_MAX_VIEWPORTS) - return WPS_ERROR_INVALID_PARAM; - wps_data->num_viewports++; /* check for the optional letter to signify its a hideable viewport */ /* %Vl|