diff --git a/Resources/UK/Phoenix/Choices b/Resources/UK/Phoenix/Choices index 8e841033efcabfcd10c0eb18eb7cb0ace435cd63..09b804ec9dfc69263a41bd316266772ef2f8b289 100644 --- a/Resources/UK/Phoenix/Choices +++ b/Resources/UK/Phoenix/Choices @@ -224,6 +224,35 @@ PlugInControl:asap ClientPull:yes SeeFetches:no +# Image garbage collection +# ======================== +# +# CollectAfter - If 'yes', garbage collection occurs after a new page +# fetch is completed (free memory etc. permitting). This may +# mean higher transient memory requirements of course. If +# 'no', garbage collection occurs the moment a page is +# cleared ready for a new one to fetch. This will affect how +# high you might want to set UnusedImageLimit. +# FreeRAMLimit - If free memory falls below this amount when a new image is +# to be created, the garbage collection system is run to try +# and get more RAM. The amount is specified in kilobytes. +# Only as many images as need to be deleted to maintain the +# required free memory, are deleted. So, use 0 for unlimited +# (UnusedImageLimit becomes the only constraint). +# UnusedImageLimit - If the number of images a browser is holding ready for +# garbage collection exceeds the value given here, get rid +# of an unused image - so this number of unused images will +# be reached and thereafter maintained, since for each image +# created, one pending garbage collection is removed. Use +# zero to effectively disable image garbage collection; +# images from a current page are discard the moment that +# browser window goes to a new location. Use -1 for +# unlimited (FreeRAMLimit becomes the only constraint). + +CollectAfter:yes +FreeRAMLimit:2097512 +UnusedImageLimit:8 + # Hotlist controls # ================ # diff --git a/c/Fetch b/c/Fetch index 8e42e9360fa3fc4b27afac40b06f410969fe8546..01bf826062f9d5ac3114d5652eee7b8075cf55f8 100644 --- a/c/Fetch +++ b/c/Fetch @@ -1266,12 +1266,15 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr) /* Try adding this title to the history, ignoring any errors */ - history_add_title(browser_fetch_url(b), p); + history_add_title(browser_current_url(b), p); } } if (tptr->tag == BODY) { + int bg_set = 0; + int fg_set = 0; + /* The BODY tag. All sorts of exciting stuff in here... */ if (HtmlBODYbgcolour(tptr) != NULL_COLOUR) @@ -1292,6 +1295,8 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr) if (b->background_image < 0) b->antialias_colour = b->background_colour; browser_update_bottom(b, 0); + + bg_set = 1; } /* Background images */ @@ -1302,19 +1307,31 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr) /* and remember the image number in the browser_data structure */ image_new_image(b, HtmlBODYbackground(tptr), tptr, 2, NULL); + + b->antialias_colour = redraw_backcol(b); /* For the time being, at least */ + + bg_set = 1; + } + else + { + b->background_image = -1; + b->antialias_colour = redraw_backcol(b); } /* Get the rest of the colour info out */ - if (HtmlBODYtext (tptr) != NULL_COLOUR) b->text_colour = HtmlBODYtext (tptr); - if (HtmlBODYlink (tptr) != NULL_COLOUR) b->link_colour = HtmlBODYlink (tptr); - if (HtmlBODYvlink(tptr) != NULL_COLOUR) b->used_colour = HtmlBODYvlink(tptr); - if (HtmlBODYalink(tptr) != NULL_COLOUR) b->followed_colour = HtmlBODYalink(tptr); + if (HtmlBODYtext (tptr) != NULL_COLOUR) fg_set = 1, b->text_colour = HtmlBODYtext (tptr); + if (HtmlBODYlink (tptr) != NULL_COLOUR) fg_set = 1, b->link_colour = HtmlBODYlink (tptr); + if (HtmlBODYvlink(tptr) != NULL_COLOUR) fg_set = 1, b->used_colour = HtmlBODYvlink(tptr); + if (HtmlBODYalink(tptr) != NULL_COLOUR) fg_set = 1, b->followed_colour = HtmlBODYalink(tptr); /* Pull out the onload and onunload scripts */ - if (HtmlBODYonload (tptr)) b->onload = HtmlBODYonload (tptr); + if (HtmlBODYonload(tptr)) b->onload = HtmlBODYonload(tptr); + else b->onload = bg_set ? "" : NULL; + if (HtmlBODYonunload(tptr)) b->onunload = HtmlBODYonunload(tptr); + else b->onunload = bg_set ? "" : NULL; } /* Deal with META... tags */ @@ -1700,8 +1717,9 @@ void fetch_fetcher(browser_data * b) /* Write to the global history */ if ( - b->displayed == Display_Fetched_Page || - b->displayed == Display_External_Image + b->displayed == Display_Fetched_Page || + b->displayed == Display_External_Image || + b->displayed == Display_About_Page ) history_record(b, b->urlddata); @@ -1747,35 +1765,58 @@ void fetch_fetcher(browser_data * b) b->final_token = NULL; /* Last HStream structure dealt with */ b->last_char = ' '; /* Last character dealt with */ - b->background_colour = -1; /* Background colour, or -1 for default */ - - b->background_image = -1; /* Image no. of background image, 0=none */ b->text_colour = choices.text_colour; /* Body text default colour */ b->link_colour = choices.link_colour; /* Link text default colour */ b->used_colour = choices.used_colour; /* Followed link default colour */ - b->antialias_colour = redraw_backcol(b); /* Colour to anti-alias to, or -1=none */ b->followed_colour = choices.followed_colour; /* Following link default colour */ b->selected_colour = choices.selected_colour; /* Selected (highlighted) link colour */ - b->onload = NULL; /* <BODY onload> attribute */ - b->onunload = NULL; /* <BODY onunload> attribute */ + if (b->reloading || (b->onload == NULL && b->onunload == NULL)) + { + b->background_colour = -1; /* Background colour, or -1 for default */ + b->background_image = -1; /* Image no. of background image, 0=none */ + b->antialias_colour = redraw_backcol(b); /* Colour to anti-alias to, or -1=none */ + } + else + { + b->onload = NULL; /* <BODY onload> attribute */ + b->onunload = NULL; /* <BODY onunload> attribute */ + } + +// Eeek! Needs doing, but not here. The SCRIPT callbacks would have gone off +// by now, so all of the functions just defined for this page are trashed; +// and trashed *after* the scripts have already run with the previous page's +// stuff visible. Fix me, fix me, fix me... +// +// /* For JavaScript, close down the old context for the window and */ +// /* get a new one - we shouldn't be able to access things defined */ +// /* in the previous page in this new page. */ +// +// #ifdef JAVASCRIPT +// +// javascript_lose_context(b); +// +// if (fetch_chkerror(b, javascript_gain_context(b, b->ancestor))) return; +// +// #endif /* If this was a History-based fetch, clear the flag */ - b->from_history = 0; + b->from_history = 0; /* Ensure the nesting level and filling frame counters are reset */ - b->nesting_level = 0; - b->filling_frame = 0; + b->nesting_level = 0; + b->filling_frame = 0; /* Allow scroll bars to be reset */ - b->tools_lock = 1; + b->tools_lock = 1; /* Cancel any pending automatic fetches */ if (b->meta_refresh_at) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, b); + b->meta_refresh_at = 0; b->meta_refresh_url = NULL; @@ -1829,6 +1870,10 @@ void fetch_fetcher(browser_data * b) image_discard(b); + /* If forcing a reload, garbage collect immediately */ + + if (b->reloading) image_gc(b, 0, 1); + /* Flag that images need to be garbage collected later (as */ /* free memory drops down after the fetch), and call the */ /* garbage collector now since we may have exceeded the */ @@ -1890,18 +1935,6 @@ void fetch_fetcher(browser_data * b) toolbars_cancel_status(b, Toolbars_Status_Connecting); toolbars_update_status(b, Toolbars_Status_Fetching); -// /* For JavaScript, close down the old context for the window and */ -// /* get a new one - we shouldn't be able to access things defined */ -// /* in the previous page in this new page. */ -// -// #ifdef JAVASCRIPT -// -// javascript_lose_context(b); -// -// if (fetch_chkerror(b, javascript_gain_context(b, b->ancestor))) return; -// -// #endif - /* Since the new fetch is now official, update the current and previous */ /* page variables */ @@ -2082,6 +2115,10 @@ _kernel_oserror * fetch_cancel(browser_data * b) if (b->meta_refresh_at) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, b); b->meta_refresh_at = 0; + /* If an onLoad JavaScript specifier was present, cancel it too */ + + if (b->onload) b->onload = ""; + /* If not fetching, exit here */ if (!fetch_fetching(b)) return NULL; diff --git a/c/Frames b/c/Frames index 67b27d69e35ae72de40081f168f063f1da6f4bf5..dd1601cb8169bd438b4e15d55adfa72e878c9d88 100644 --- a/c/Frames +++ b/c/Frames @@ -2568,7 +2568,6 @@ browser_data * frames_find_target(browser_data * b, const char * target) /* the relevant browser_data structure with */ /* frames_find_browser_from_index. */ /* */ -/* */ /* Parameters: Pointer to a browser_data struct */ /* representing the parent (it and */ /* all its children are searched for */ diff --git a/c/Images b/c/Images index 2eb21b178f3074b2a62f1ef93fa0c784b55309f5..0f3ed07c1390488f4e3a61bf73f363d2976919e7 100644 --- a/c/Images +++ b/c/Images @@ -84,10 +84,15 @@ static void image_remove_all_data (int image); static void image_delay (browser_data * b, int image); static void image_abandon (browser_data * b, int image); static void image_prepare (browser_data * b, HStream * token, int image, int background); -static void image_delete_image_entry (int image); + +static void image_mark_as_deleted (int i); +static void image_mark_as_gcable (int i); static void image_destroy (int image); +static int image_renumber (int old, int new); +static int image_purge_deleted_entries (void); static void image_post_deletion_clearup (void); static int image_gc_oldest (browser_data * b); + static void image_refetch (browser_data * b, int image, int priority, int redraw); static _kernel_oserror * image_update_area (browser_data * b, int x, int y, BBox * ubox, int image, int redraw); @@ -95,7 +100,7 @@ static _kernel_oserror * image_update_image (browser_data * b, int ima static _kernel_oserror * image_register_filler (int xref); -static int image_data_offset (int image); +//static int image_data_offset (int image); static int image_count_fetches (browser_data * b); static int image_get_token_image_xref (browser_data * b, HStream * token); @@ -111,7 +116,6 @@ static int image_can_be_saved_as_sprite (browser_data * b, int i); /* Locals */ static image_info * idata = NULL; /* Flex block for image_info structures (referenced as an array) */ -static char * ddata = NULL; /* Flex block for in-transit fetch data, URLs, etc. */ static int nimages = 0; /* Current number of image_info structures in idata array */ static int lastimage = 0; /* Used to work out what image_process_null should handle next */ static int animhandler = 0; /* Flag so code knows when to (de)register GIF animation handler */ @@ -426,47 +430,21 @@ static _kernel_oserror * image_load_chunk(browser_data * b, int image, char * bu static void image_remove_data(browser_data * b, int image) { - int p, oldsize, remove; - #ifdef TRACE if (tl & (1u<<15)) Printf("image_remove_data: Called for image %d\n",image); #endif - /* Get the current data size */ - - oldsize = flex_size((flex_ptr) &ddata); - - /* The alloc field holds the total amount of data associated */ - /* with the image, and the ualloc field holds the amount */ - /* that the URL uses. So subtract ualloc from alloc to get */ - /* the amount that must be removed. */ - - remove = idata[image].alloc - idata[image].ualloc; - - if (remove) + if (idata[image].flex->fetchdata) { - /* Need to shuffle the rest of the flex block */ - /* down and shrink the block, if this isn't */ - /* the last image (i.e. p != oldsize). */ - - p = image_data_offset(image) + idata[image].alloc; - - if (p != oldsize) memmove(ddata + p - remove, ddata + p, oldsize - p); - - flex_extend((flex_ptr) &ddata, oldsize - remove); - #ifdef TRACE - flexcount -= remove; + flexcount -= flex_size(&idata[image].flex->fetchdata); if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif - } - /* Subtract the amount removed from the alloc field */ - /* and set isize to zero, i.e. we're not storing */ - /* any image data anymore. */ + flex_free(&idata[image].flex->fetchdata); - idata[image].alloc -= remove; - idata[image].isize = 0; + idata[image].flex->fetchdata = NULL; + } #ifdef TRACE if (tl & (1u<<15)) Printf("image_remove_data: Successful\n"); @@ -485,45 +463,38 @@ static void image_remove_data(browser_data * b, int image) static void image_remove_all_data(int image) { - int p, oldsize, remove; - #ifdef TRACE if (tl & (1u<<15)) Printf("image_remove_all_data: Called for image %d\n",image); #endif - /* Get the current data size */ - - oldsize = flex_size((flex_ptr) &ddata); + if (!idata[image].flex) return; - /* The alloc field holds the total amount of data associated */ - /* with the image. */ - - remove = idata[image].alloc; - - if (remove) + if (idata[image].flex->urldata) { - /* Need to shuffle the rest of the flex block */ - /* down and shrink the block, if this isn't */ - /* the last image */ - - p = image_data_offset(image); + #ifdef TRACE + flexcount -= flex_size((flex_ptr) &idata[image].flex->urldata); + if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); + #endif - if (oldsize - p - remove) memmove(ddata + p, ddata + p + remove, oldsize - p - remove); + flex_free((flex_ptr) &idata[image].flex->urldata); - flex_extend((flex_ptr) &ddata, oldsize - remove); + idata[image].flex->urldata = NULL; + } + if (idata[image].flex->fetchdata) + { #ifdef TRACE - flexcount -= remove; + flexcount -= flex_size(&idata[image].flex->fetchdata); if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif - } - /* Subtract the amount removed from the alloc field */ - /* and set isize to zero, i.e. we're not storing */ - /* any image data anymore. */ + flex_free(&idata[image].flex->fetchdata); + + idata[image].flex->fetchdata = NULL; + } - idata[image].alloc = 0; - idata[image].isize = 0; + free(idata[image].flex); + idata[image].flex = NULL; #ifdef TRACE if (tl & (1u<<15)) Printf("image_remove_all_data: Successful\n"); @@ -864,7 +835,7 @@ static void image_prepare(browser_data * b, HStream * token, int image, int back _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * token, int background, int * handle) { - int size, ok, ulen; + int ok, ulen; int xref; int use_xref = 0; int tried_once = 0; @@ -931,15 +902,15 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * /* Can we simply create a cross reference to another image? */ if ( - idata[i].alloc && /* The image has data allocated for it */ - idata[i].xref < 0 && /* The image doesn't cross reference things itself */ - idata[i].background == !!background && /* We're not trying to make a b/g an f/g or vice versa */ - !strcmp(url, ddata + image_data_offset(i)) && /* This holds a URL which matches that passed in */ + idata[i].flex->urldata && /* The image has an associated URL */ + idata[i].xref < 0 && /* The image doesn't cross reference things itself */ + idata[i].background == !!background && /* We're not trying to make a b/g an f/g or vice versa */ + !strcmp(url, idata[i].flex->urldata) && /* This holds a URL which matches that passed in */ ( - !background || /* This isn't a background image, or... */ + !background || /* This isn't a background image, or... */ ( - background && /* If this is a background image, the background */ - idata[i].owner->background_colour == b->background_colour /* colours match in the two owner browsers */ + background && /* If this is a background image, the background */ + redraw_backcol(idata[i].owner) == redraw_backcol(b) /* colours match in the two owner browsers */ ) ) ) @@ -951,14 +922,10 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * } } - if (xref >= 0) ulen = 0; /* Don't need any extra data for a cross referenced image. */ - else - { - ulen = (strlen(url) + 1); - ulen = (int) WordAlign(ulen); - } + /* Don't need to hold the URL for a cross referenced image */ - size = ulen; + if (xref >= 0) ulen = 0; + else ulen = strlen(url) + 1; /* Are we cross-referencing an image which is ready for garbage */ /* collection? If so, we can just claim this one. */ @@ -1021,7 +988,39 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * } while (!ok); - if (ok) + /* Throw back an error if out of memory */ + + if (!ok) + { + erb.errnum = Utils_Error_Custom_Message; + + StrNCpy0(erb.errmess, + lookup_token("NoMemImg:There is not enough free memory for any new images (%0).", + 0, + "1")); + + return &erb; + } + + /* Increment the image counter, zero the contents of the image_info structure */ + /* and fill in some of the fields where contents are known now. */ + + memset(&idata[nimages], 0, sizeof(image_info)); /* Precautionary catch-all */ + + idata[nimages].owner = b; + idata[nimages].x = -1; + idata[nimages].y = -1; + + idata[nimages].token = token; + idata[nimages].last_used = time(NULL); + idata[nimages].xref = xref; + + idata[nimages].background = !!background; + idata[nimages].hadfiller = 0; + + /* Allocate space for the URL */ + + if (ulen) { tried_once = 0; @@ -1029,19 +1028,14 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * { /* Allocate space for the image data */ - if (ddata) - { - int oldsize; + idata[nimages].flex = malloc(sizeof(image_flex)); - #ifdef TRACE - flexcount += sizeof(image_info); - if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); - #endif + if (!idata[nimages].flex) ok = 0; + else ok = 1; - oldsize = flex_size ((flex_ptr) &ddata); - ok = flex_extend((flex_ptr) &ddata, oldsize + size); - } - else ok = flex_alloc ((flex_ptr) &ddata, size); + memset(idata[nimages].flex, 0, sizeof(image_flex)); + + if (ok) ok = flex_alloc((flex_ptr) &idata[nimages].flex->urldata, ulen); if (!ok && !tried_once) { @@ -1053,7 +1047,7 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * while (!ok); } - /* Throw back an error if out of memory */ + /* Again, throw back an error if out of memory */ if (!ok) { @@ -1068,30 +1062,10 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * } #ifdef TRACE - flexcount += size; + flexcount += ulen; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif - /* Increment the image counter, zero the contents of the image_info structure */ - /* and fill in some of the fields where contents are known now. */ - - memset(&idata[nimages], 0, sizeof(image_info)); /* Precautionary catch-all */ - - idata[nimages].owner = b; - idata[nimages].x = -1; - idata[nimages].y = -1; - - idata[nimages].alloc = size; - idata[nimages].ualloc = ulen; - idata[nimages].isize = 0; - - idata[nimages].token = token; - idata[nimages].last_used = time(NULL); - idata[nimages].xref = xref; - - idata[nimages].background = !!background; - idata[nimages].hadfiller = 0; - /* Set the 'delayed' flag if it's not a background image and */ /* images are flagged as not being shown right now, or if it */ /* is a backgrond image and backgrounds are flagged to be */ @@ -1112,11 +1086,11 @@ _kernel_oserror * image_new_image(browser_data * b, const char * url, HStream * } /* If there's data for a URL, copy it into the above allocated block */ - /* and ImageLib about the new image. */ + /* and inform ImageLib of the new image. */ if (ulen) { - strcpy(ddata + image_data_offset(nimages), url); + strcpy(idata[nimages].flex->urldata, url); #ifdef ALL_FAST idata[nimages].istore = NewImage(NULL, IMAGE_FAST); @@ -1216,32 +1190,43 @@ _kernel_oserror * image_process_null(browser_data * b) fetches < choices.max_images ) { - const char * referer = browser_current_url(b); - - e = html_get(ddata + image_data_offset(image), /* Document to fetch */ - NULL, /* Pointer to any extra data */ - (int *) &idata[image].handle, /* Place to return the fetch handle */ - URL_Method_http_GET, /* Fetch method */ + const char * referer = browser_base_url(b); + char * url = malloc(strlen(idata[image].flex->urldata) + 1); - #ifndef SINGLE_USER - user.name, /* User name for MailServ, if using */ - #else /* a multiuser version */ - NULL, - #endif - - 0, /* 0 = Don't parse fetched data */ - !b->reloading, /* 1 = Proxy can be used, 0 = can't */ - referer); /* URL of referring page */ + if (url) + { + strcpy(url, idata[image].flex->urldata); + + e = html_get(url, /* Document to fetch */ + NULL, /* Pointer to any extra data */ + (int *) &idata[image].handle, /* Place to return the fetch handle */ + URL_Method_http_GET, /* Fetch method */ + + #ifndef SINGLE_USER + user.name, /* User name for MailServ, if using */ + #else /* a multiuser version */ + NULL, + #endif + + 0, /* 0 = Don't parse fetched data */ + !b->reloading, /* 1 = Proxy can be used, 0 = can't */ + referer); /* URL of referring page */ + free(url); + } + else e = NULL; /* Suppress compiler warning */ - if (e) + if (!url || e) { /* Don't report it; countless 'I've failed' reports for */ /* the very beginning of a fetch are not very helpful. */ - /* Particularly, 'file not found' for file fetches, can */ - /* be major pain. */ + /* Particularly, 'file not found' for file fetches can */ + /* be major pain! */ image_abandon(b, image); + return NULL; } + + url = NULL; } } while (image != lastimage && !idata[image].handle); @@ -1344,7 +1329,7 @@ _kernel_oserror * image_process_null(browser_data * b) /* called, the sprite will plot slowly resulting in */ /* (typically) painfully slow redraws. */ - if (image == idata[image].owner->background_image) + if (image == b->background_image) // idata[image].owner->background_image) { b->antialias_colour = redraw_backcol(b); @@ -1387,8 +1372,12 @@ _kernel_oserror * image_process_null(browser_data * b) int remn, sofar, waiting; int realsize; + int oldsize; HStream * tptr; void * store; + char * url = malloc(strlen(idata[image].flex->urldata) + 1); + + if (url) strcpy(url, idata[image].flex->urldata); /* Go in with no store; only interested in new data, as */ /* anything fetched so far goes into the ddata block. */ @@ -1401,28 +1390,32 @@ _kernel_oserror * image_process_null(browser_data * b) /* block each time, it won't be able to see the whole header */ /* block and the fetch fails (well, the image library keeps */ /* waiting for something to happen). At the time of writing this */ - /* is demonstrated by the images at http://www.debenhams.co.uk/'. */ + /* is demonstrated by the images at http://www.debenhams.co.uk/. */ - if (idata[image].isize) + if (idata[image].flex->fetchdata) { - int p = image_data_offset(image) + idata[image].ualloc; + int isize = flex_size(&idata[image].flex->fetchdata); /* Complain if the flex allocation fails, else copy the data across */ - if (!flex_alloc(&store, idata[image].isize)) + if (!flex_alloc(&store, isize)) { image_abandon(b, image); - + free(url); return NULL; } else { + int budge = flex_set_budge(0); + #ifdef TRACE - flexcount += idata[image].isize; + flexcount += isize; if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); #endif - memcpy(store, ddata + p, idata[image].isize); + memcpy(store, idata[image].flex->fetchdata, isize); + + flex_set_budge(budge); } } @@ -1460,17 +1453,23 @@ _kernel_oserror * image_process_null(browser_data * b) /* Call the fetch routine */ - e = html_get_next_token(b, - idata[image].handle, - &remn, - &sofar, - &tptr, - &waiting, - &store, - ddata + image_data_offset(image), - 1); + if (url) + { + e = html_get_next_token(b, + idata[image].handle, + &remn, + &sofar, + &tptr, + &waiting, + &store, + url, + 1); + + free(url); + } + else e = NULL; /* Suppress compiler warning */ - if (e) + if (!url || e) { /* If there's an error, free the store and ditch the image */ @@ -1490,9 +1489,18 @@ _kernel_oserror * image_process_null(browser_data * b) if (tl & (1u<<15)) Printf("image_process_null: Exitting with error\n"); #endif - return e; + /* Only return errors in STRICT_PARSER builds for similar reason to */ + /* suppression of any errors from html_get above. */ + + #ifdef STRICT_PARSER + return e; + #else + return NULL; + #endif } + url = NULL; + #ifdef TRACE_FETCH_STORE if (store) @@ -1527,23 +1535,23 @@ _kernel_oserror * image_process_null(browser_data * b) /* How much data was added? */ - if (store) realsize = flex_size(&store) - idata[image].isize; /* We already had 'isize' bytes before the fetcher was entered */ - else realsize = 0; + oldsize = idata[image].flex->fetchdata ? flex_size(&idata[image].flex->fetchdata) : 0; + realsize = store ? flex_size(&store) - oldsize : 0; /* If we've got data in the local store, copy it to the image store. */ - if (realsize >= 0) + if (realsize > 0) { - int p, oldsize; + int ok; + int amount = flex_size(&store); + int budge; - /* oldsize holds the whole image data block size (for all images) */ + /* Make enough room for the extra data */ - oldsize = flex_size((flex_ptr) &ddata); + if (idata[image].flex->fetchdata) ok = flex_extend(&idata[image].flex->fetchdata, amount); + else ok = flex_alloc (&idata[image].flex->fetchdata, amount); - /* Allocate 'size' extra bytes, doing the relevant error handling */ - /* code if the allocation fails */ - - if (!flex_extend((flex_ptr) &ddata, oldsize + realsize)) + if (!ok) { #ifdef TRACE flexcount -= flex_size(&store); @@ -1573,26 +1581,27 @@ _kernel_oserror * image_process_null(browser_data * b) #endif - /* p points to the first byte after the data used by this image */ - - p = image_data_offset(image) + idata[image].alloc; + /* Copy the added data from the temporary store into the image's store */ - /* Move all data from p up to the end of the block (as was, hence */ - /* oldsize) along the block by size bytes, effectively creating */ - /* a gap of that many bytes just after this image's data. If p */ - /* = oldsize, this was the last image in the block and there's */ - /* no data above it to move (so don't do the memmove). */ + budge = flex_set_budge(0); - if (p != oldsize) memmove(ddata + p + realsize, ddata + p, oldsize - p); + memcpy(((char *) idata[image].flex->fetchdata) + oldsize, + ((char *) store) + oldsize, + realsize); - /* Copy the new data into that gap */ + flex_set_budge(budge); + } - memcpy(ddata + p, ((char *) store) + idata[image].isize, realsize); + /* Free the temporary store, if it was used */ - /* Update the image's image data and total data pointers */ + if (store) + { + #ifdef TRACE + flexcount -= flex_size(&store); + if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); + #endif - idata[image].alloc += realsize; - idata[image].isize += realsize; + flex_free(&store); } /* Act according to the fetch status */ @@ -1601,54 +1610,45 @@ _kernel_oserror * image_process_null(browser_data * b) { case 1: break; /* Nothing happened yet, or the HTTP response header is still coming in */ case 2: break; /* Redirected, we can ignore and wait for the fetcher to cope */ - case 0: /* Not awaiting delivery (shouldn't happen in this context, but here 'just in case') */ - case 3: /* We have some data */ + + case 0: /* Not awaiting delivery (shouldn't happen in this context, but here 'just in case') */ + case 3: /* We have some data */ { - int i, n, n1; + int offset, remaining, this_block; - /* Flag that a fetch has started to happen */ + /* Flag that a fetch is in progress (rather than headers still */ + /* arriving, waiting, or redirecting) */ idata[image].started = 1; - /* Set 'n' to the size of data that was fetched */ - - if (store) n = flex_size(&store); - else n = 0; - /* Increment the 'bytes so far' counter for the image */ - idata[image].bytesgot += n; + idata[image].bytesgot += realsize; /* Push the data into the library, in chunks defined by */ /* the size of 'buffer' (allocated as a char[] above). */ + /* We do this as we can't be sure the ImageLib Load */ + /* function is flex-safe, so the recently fetched data */ + /* is copiedied into a temporary, non-movable block. */ - i = 0; + offset = oldsize; + remaining = realsize; - while (n) + while (remaining > 0) { - n1 = n; + this_block = remaining; - if (n1 > sizeof(buffer)) n1 = sizeof(buffer); - memcpy(buffer, (char *) store + i, n1); + if (this_block > sizeof(buffer)) this_block = sizeof(buffer); + memcpy(buffer, ((char *) idata[image].flex->fetchdata) + offset, this_block); - i += n1; - n -= n1; + offset += this_block; + remaining -= this_block; - e = image_load_chunk(b, image, buffer, n1); + e = image_load_chunk(b, image, buffer, this_block); if (e) { - /* If there's an error, free the store and ditch the image */ - - if (store) - { - #ifdef TRACE - flexcount -= flex_size(&store); - if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); - #endif - - flex_free(&store); - } + /* If there's an error, ditch the image */ image_abandon(b, image); @@ -1668,18 +1668,6 @@ _kernel_oserror * image_process_null(browser_data * b) break; } - /* Free the temporary store, if it was used */ - - if (store) - { - #ifdef TRACE - flexcount -= flex_size(&store); - if (tl & (1u<<14)) Printf("** flexcount: %d\n",flexcount); - #endif - - flex_free(&store); - } - /* Closure of long 'if' that deals with either continuing */ /* to fetch data for an image, or getting the first chunk */ /* of data for a fetch. (The code immediately above is for */ @@ -1704,105 +1692,98 @@ _kernel_oserror * image_process_null(browser_data * b) } /*************************************************/ -/* image_delete_image_entry() */ -/* */ -/* Deletes an image_info structure from the */ -/* array of structures. The cross reference */ -/* image numbers of subsequent images are */ -/* adjusted appropriately. */ +/* image_mark_as_deleted() */ /* */ -/* The idata flex block is not shrunk; this is */ -/* expected to be ,one externally, to avoid */ -/* possibly freeing many small blocks */ -/* consecutively (which can be slow with flex). */ -/* E.g. see image_post_deletion_clearup. */ +/* Mark an image as deleted, but don't remove it */ +/* from the image array yet. When all images */ +/* that are to be deleted have been thus marked, */ +/* call image_purge_deleted_entries before */ +/* continuing. */ /* */ -/* NOTE. Since this removes items from the idata */ -/* array, if you're calling during a for() loop */ -/* scanning that array, count *backwards* from */ -/* nimages - 1 to 0. Otherwise, clearly, things */ -/* will go horribly wrong. */ +/* Does not free any memory at all, in the image */ +/* array or any other blocks. Does not cancel */ +/* fetches or sort out other image references */ +/* such as background_image fields in */ +/* browser_data structures either, because this */ +/* may be called when images are renumbered */ +/* rather than wholly removed. If completely */ +/* wiping an image, make sure you do all of that */ +/* *before* calling here. */ /* */ -/* Parameters: Image number to remove. */ +/* Parameters: Number of the image to mark as */ +/* deleted. */ /*************************************************/ -static void image_delete_image_entry(int image) +static void image_mark_as_deleted(int i) { - browser_data * b; - int i; + /* Try to set the flags up so that if for some horrific */ + /* reason this image should end up being processed as a */ + /* "live" item, it'll do minimum damage! */ - nimages--; - - if (lastimage == image) lastimage--; - if (lastimage >= nimages) lastimage = nimages - 1; + idata[i].handle = 0; + idata[i].istore = NULL; - /* Only need to alter xref numbers or move flex data */ - /* around if this wasn't the last image in the block */ + idata[i].deleted = 1; - if (image < nimages) /* (Not 'nimages - 1' as nimages has been decremented by this point) */ - { - memmove(&idata[image], &idata[image + 1], sizeof(image_info) * (nimages - image)); + idata[i].fetched = 1; + idata[i].delayed = 0; + idata[i].success = 1; - for (i = image; i < nimages; i++) - { - #ifdef TRACE - if (idata[i].xref == image) Printf("JUST DELETED IMAGE %d WHICH WAS XREF'D AND SHOULDN'T HAVE BEEN\n", i); - #endif + idata[i].hadfirst = 1; + idata[i].reformat = 0; + idata[i].hadfiller = 0; + idata[i].canredraw = 0; + idata[i].priority = 0; - /* Did this cross reference an image which will have changed number? */ - - if (idata[i].xref > image) idata[i].xref--; - - /* Update the associated token */ - - #ifdef FAST_TOKEN_REFERENCE - - if (idata[i].token) - { - idata[i].token->flags &= (1 << FAST_TOKEN_REFERENCE_SHIFT) - 1; - idata[i].token->flags |= ((i + 1) << FAST_TOKEN_REFERENCE_SHIFT); - } + idata[i].token = NULL; - #endif - - /* Did this have a filler function registered for it? */ - - if (idata[i].hadfiller) - { - /* If so, then provided the filler function is still available, */ - /* reregister with the new image number. */ - - if (!idata[i].istore->RegisterFiller) - { - idata[i].hadfiller = 0; - } - else - { - show_error_ret(image_register_filler(i)); - } - } - } - } + return; +} - /* Need to also alter browser_data structures' background image */ - /* number fields. */ +/*************************************************/ +/* image_mark_as_gcable() */ +/* */ +/* Mark an image as suitable for garbage */ +/* collection. Such images may exist in the */ +/* image array for as long as required and may */ +/* be reclaimed as working items by calls to */ +/* image_new_image. */ +/* */ +/* Parameters: Number of the image to mark as */ +/* suitable for garbage collection. */ +/*************************************************/ - b = last_browser; +static void image_mark_as_gcable(int i) +{ + idata[i].token = NULL; - while (b) - { - if (b->background_image > image) b->background_image--; + /* Yup, that was all that needs doing for now */ - b = b->previous; - } + return; } /*************************************************/ /* image_discard() */ /* */ -/* Discards all images for a given browser */ -/* window, freeing the memory and shutting down */ -/* any active fetches. */ +/* For a given browser, discard images: */ +/* */ +/* * Any images which are xrefed by another */ +/* browser have their ownership transferred */ +/* to that other browser and the xrefing item */ +/* is removed instead */ +/* */ +/* * Any images owned by the given browser which */ +/* just xref other images are removed */ +/* */ +/* * Any remaining images holding actual image */ +/* data are marked for garbage collection but */ +/* not removed immediately. */ +/* */ +/* When an image is removed, all data, including */ +/* fetches, ImageLib info and external refs to */ +/* the image number is sorted out. Remaining */ +/* items in the image_info array may end up */ +/* renumbered. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the images. */ @@ -1813,7 +1794,7 @@ _kernel_oserror * image_discard(browser_data * b) int i, xref; #ifdef TRACE - if (tl & (1u<<15)) Printf("\nimage_discard: Called for %p\n\n", b); + if (tl & (1u<<15)) Printf("\nimage_discard: Called for %p. There are %d images.\n\n", b, nimages); #endif if (!nimages) return NULL; @@ -1825,15 +1806,7 @@ _kernel_oserror * image_discard(browser_data * b) _swix(Hourglass_Start, _IN(0), 1); - #ifdef TRACE - if (tl & (1u<<15)) - { - Printf("image_discard: First pass, checking for cross referencees owned by %p\n", b); - Printf(" There are %d images before this pass.\n\n", nimages); - } - #endif - - /* Must go backwards because we can delete items from the array */ + /* Must go backwards because we may delete items from the array */ /* during the loop itself */ for (i = nimages - 1; i >= 0; i--) @@ -1930,51 +1903,48 @@ _kernel_oserror * image_discard(browser_data * b) /* Delete the cross referencer */ #ifdef TRACE - if (tl & (1u<<15)) Printf("image_discard: Deleting entry owned by %p that cross references image %d\n", idata[i].owner, idata[i].xref); + if (tl & (1u<<15)) Printf("image_discard: Deleting entry owned by %p that cross references image %d\n\n", idata[i].owner, idata[i].xref); #endif - image_remove_all_data(i); - - /* Safe because we're counting through the array backwards */ - - image_delete_image_entry(i); + image_destroy(i); } - } - #ifdef TRACE - if (tl & (1u<<15)) - { - Printf("\nimage_discard: First pass complete, there are now %d images\n", nimages); - Printf(" Second pass, removing remaining images owned by %p\n\n", b); - } - #endif + /* OK, so this image isn't owned by another browser but cross referencing */ + /* one owned by ourselves. A simpler case is where we own an image that */ + /* just cross references another - we can delete those straight away */ - /* Now delete any remaining images owned by the given browser */ - /* - count backwards as we might remove items from the idata */ - /* array during the loop. */ - - for (i = nimages - 1; i >= 0; i--) - { - if (idata[i].owner == b) + else if (idata[i].owner == b) { - if (idata[i].istore) + if (idata[i].xref >= 0) { - /* Mark the image as suitable for garbage collection */ + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_discard: Image %d is a simple cross-referencer, deleting it\n\n", i); + #endif + + image_destroy(i); + } - idata[i].token = NULL; + /* Next case; this is owned by us but holds real data. In this case, mark */ + /* it as suitable for garbage collection but not as deleted. */ + else if (idata[i].bytesgot) + { #ifdef TRACE - if (tl & (1u<<15)) Printf("\nimage_discard: Image %d marked for GC but not deleted\n", i); + if (tl & (1u<<15)) Printf("image_discard: Image %d being marked for GC\n", i); #endif + + image_mark_as_gcable(i); } + + /* Last case: Not a cross referencer, but has no data yet - get rid of it */ + else { - image_remove_all_data(i); - image_delete_image_entry(i); - #ifdef TRACE - if (tl & (1u<<15)) Printf("\nimage_discard: Image %d deleted\n", i); + if (tl & (1u<<15)) Printf("image_discard: Image does not cross reference but has no bytes fetched for it yet; so deleting it\n\n", i); #endif + + image_destroy(i); } } } @@ -1982,13 +1952,13 @@ _kernel_oserror * image_discard(browser_data * b) _swix(Hourglass_Off, 0); #ifdef TRACE - if (tl & (1u<<15)) Printf("\nimage_discard: Second pass complete, there are now %d images\n\n", nimages); + if (tl & (1u<<15)) Printf("image_discard: Delete pass complete; there are %d images. Calling clearup function.\n\n", nimages); #endif image_post_deletion_clearup(); #ifdef TRACE - if (tl & (1u<<15)) Printf("image_discard: Successful\n\n"); + if (tl & (1u<<15)) Printf("\nimage_discard: Successful. Post-clearup, there are %d images.\n\n", nimages); #endif return NULL; @@ -1997,39 +1967,26 @@ _kernel_oserror * image_discard(browser_data * b) /*************************************************/ /* image_destroy() */ /* */ -/* image_discard gets rid of cross referencing */ -/* images and transfers ownership of items that */ -/* are owned by the given browser but cross */ -/* referenced by another to that other. It does */ -/* not delete actual, non-cross-referencing */ -/* images owned by the given browser though, but */ -/* instead marks them as suitable for later */ -/* garbage collection. */ -/* */ -/* image_delete_image_entry is used to remove an */ -/* item from the idata array but does not deal */ -/* with ImageLib data or ongoing fetches. */ -/* */ -/* To actually kill an image off completely, use */ -/* this function. It's called by the garbage */ -/* collector image_gc and used to be part of */ -/* image_discard before the image garbage */ -/* collection system existed. */ -/* */ -/* Be careful what you delete (!) and remember */ -/* to call image_post_deletion_clearup when all */ -/* the images you want to get rid of have been */ -/* removed by this function. */ -/* */ -/* NB - this calls image_delete_image_entry, so */ -/* the same restrictions on scanning through */ -/* the idata array as for that function apply. */ +/* Close down any fetch associated with an */ +/* image, deal with any references to it (e.g. */ +/* the background_image field of a browser_data */ +/* structure), and remove all data except for */ +/* the actual image_info array entry. The item */ +/* is marked as deleted. */ +/* */ +/* Callers should be aware of the need to call */ +/* image_post_deletion_clearup as soon as */ +/* possible after a round of image deletions. */ /* */ /* Parameters: Number of the image to remove. */ /*************************************************/ static void image_destroy(int image) { + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_destroy: Called for image %d\n", image); + #endif + /* If the image was being fetched, close that session */ if (idata[image].handle) @@ -2061,71 +2018,289 @@ static void image_destroy(int image) idata[image].istore -> Delete(idata[image].istore); #endif + + idata[image].istore = NULL; } + /* Get rid of associated data except the image_info struct */ + image_remove_all_data(image); - image_delete_image_entry(image); + + /* Clear the background image field of the owner if necessary */ + + if (idata[image].owner->background_image == image) + { + idata[image].owner->background_image = -1; + } + + /* Mark the image as deleted */ + + image_mark_as_deleted(image); #ifdef TRACE - if (tl & (1u<<15)) Printf("\nimage_destroy: Image %d deleted\n", image); + if (tl & (1u<<15)) Printf("image_destroy: Image %d deleted\n\n", image); #endif } /*************************************************/ -/* image_post_deletion_clearup() */ +/* image_renumber() */ /* */ -/* After deleting a set of images or image_info */ -/* structures which had no associated data in */ -/* ImageLib, call this to tidy up - deregister */ -/* the animation handler, resize the idata flex */ -/* block, etc. */ +/* Move an image in the image array. Copies */ +/* over the structure from new position to old */ +/* and marks the old as deleted. */ +/* */ +/* Destination image number must be a deleted */ +/* image! */ +/* */ +/* Parameters: Image's current number; */ +/* */ +/* Image's desired number. */ +/* */ +/* Returns: 1 if the item was renumbered, 0 */ +/* if there was a problem (e.g. */ +/* parameters out of range, */ +/* destination image not deleted, */ +/* etc.). */ /*************************************************/ -static void image_post_deletion_clearup(void) +static int image_renumber(int old, int new) { - int newsize, i; + if ( + old < 0 || + new < 0 || + old >= nimages || + new >= nimages || + old == new + ) + return 0; - _swix(Hourglass_Start, _IN(0), 1); + if (!idata[new].deleted) + { + #ifdef TRACE - /* If there is an animation handler present, but no animated */ - /* images remain, remove that handler. */ + erb.errnum = Utils_Error_Custom_Normal; - if (animhandler) - { - int found = 0; + sprintf(erb.errmess, + "In image_renumber, %d can't be renumbered to %d as the latter has not been deleted!", + old, + new); + + show_error_ret(&erb); - #ifdef TRACE - if (tl & (1u<<15)) Printf("image_post_deletion_clearup: There is an animation handler present; checking to see if it can be removed\n"); #endif + return 0; + } + + /* First off, repoint any images which xref this one, if this */ + /* image has image data (else it can't be xref'd) */ + + if (idata[old].istore) + { + int i; + for (i = 0; i < nimages; i++) { - if (idata[i].istore && idata[i].istore->animated) + if (idata[i].xref == old) idata[i].xref = new; + } + } + + /* Sort out background images */ + + if (idata[old].owner->background_image == old) idata[old].owner->background_image = new; + + /* Copy the old structure into the new position */ + + idata[new] = idata[old]; + + /* Reregister filler functions, if necessary */ + + if (idata[new].hadfiller) + { + /* If so, then provided the filler function is still available, */ + /* reregister with the new image number. */ + + if (!idata[new].istore->RegisterFiller) + { + idata[new].hadfiller = 0; + } + else + { + show_error_ret(image_register_filler(new)); + } + } + + /* Update the associated token */ + + #ifdef FAST_TOKEN_REFERENCE + + if (idata[new].token) + { + idata[new].token->flags &= (1 << FAST_TOKEN_REFERENCE_SHIFT) - 1; + idata[new].token->flags |= ((new + 1) << FAST_TOKEN_REFERENCE_SHIFT); + } + + #endif + + /* Mark the old item as deleted. */ + + image_mark_as_deleted(old); + + /* Finished */ + + return 1; +} + +/*************************************************/ +/* image_purge_deleted_entries() */ +/* */ +/* Gets rid of items in the image array which */ +/* are marked as deleted by renumbering things */ +/* to fill holes and then shrinking the image */ +/* array block. */ +/* */ +/* Assumes nimages is set up to include all of */ +/* the image array entries (i.e. it hasn't been */ +/* decremented yet) and decrements it before */ +/* exitting. */ +/* */ +/* Images marked as deleted but still in the */ +/* image array MUST ALWAYS BE REMOVED by this */ +/* function before anything else goes on after a */ +/* round of deleting things. Deleted images will */ +/* cause significant problems if run through the */ +/* rest of the image system...! */ +/* */ +/* This function does not touch any allocation */ +/* blocks other than idata, holding the array of */ +/* image_info structures. The caller should */ +/* clean up any other image related data when */ +/* going through images marking them as deleted. */ +/* */ +/* Returns: 1 if any items were deleted (so */ +/* nimages will have been */ +/* decremented appropriately), else */ +/* 0. */ +/*************************************************/ + +static int image_purge_deleted_entries(void) +{ + int first_space = -1; + int last_live = -1; + int finished = 0; + + int i; + int newsize; + + #ifdef TRACE + if (tl && (1u<<15)) Printf("image_purge_deleted_entries: Called\n"); + #endif + + /* Shuffle non-deleted items from higher in the image */ + /* array down into free places currently held by */ + /* deleted items lower down. On the whole, we're */ + /* likely to shuffle less data and renumber fewer */ + /* images this way than by a dumb "shuffle data down */ + /* over the deleted hole" approach. */ + + do + { + /* Find the first deleted item in the array */ + + for ( + i = first_space == -1 ? 0 : first_space; + i < nimages; + i++ + ) + { + if (idata[i].deleted) { - found = 1; + first_space = i; break; } } - if (!found) + if (first_space == -1) { #ifdef TRACE - if (tl & (1u<<15)) Printf("image_post_deletion_clearup: Removing animation handler\n\n"); + if (tl && (1u<<15)) Printf("image_purge_deleted_entries: No images are marked as deleted, exitting\n"); #endif - deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) image_animate_images, NULL); - animhandler = 0; + return 0; } - #ifdef TRACE + /* Find the last non-deleted (live) item in the array */ + + for ( + i = last_live == -1 ? (nimages - 1) : last_live; + i >= 0; + i-- + ) + { + if (!idata[i].deleted) + { + last_live = i; + break; + } + } + + /* If we can find a live image, proceed */ + + if (last_live != -1) + { + if (first_space > last_live) + { + /* If the first space is above the last live item, we */ + /* can just shrink the array. */ + + nimages = first_space; /* I.e. last_live + 1 */ + + #ifdef TRACE + + if (first_space - last_live != 1) + { + erb.errnum = Utils_Error_Custom_Normal; + + StrNCpy0(erb.errmess, + "You're imagining this error from image_purge_deleted_entries, because it is impossible for it to occur."); + + show_error_ret(&erb); + } + #endif + + finished = 1; + } else { - if (tl & (1u<<15)) Printf("image_post_deletion_clearup: The handler is still required\n\n"); + /* If the first space is below the last live item, must start */ + /* moving things around. Ho hum. */ + + #ifdef TRACE + if (tl && (1u<<15)) Printf("image_purge_deleted_entries: Renumbering %d to %d\n", last_live, first_space); + #endif + + image_renumber(last_live, first_space); } + } - #endif + /* If there are no live images, can exit the loop */ + + else + { + #ifdef TRACE + if (tl && (1u<<15)) Printf("image_purge_deleted_entries: There are no images left\n"); + #endif + + nimages = 0; + finished = 1; + } } + while (!finished); + + /* Check lastimage is OK */ + + if (lastimage >= nimages) lastimage = nimages - 1; /* Ensure the image_info data block matches the size of the images now present */ @@ -2144,10 +2319,85 @@ static void image_post_deletion_clearup(void) if (idata) { - if (newsize) flex_extend((flex_ptr) &idata, newsize); - else flex_free((flex_ptr) &idata); + if (newsize) flex_extend ((flex_ptr) &idata, newsize); + else flex_free ((flex_ptr) &idata); } + #ifdef TRACE + if (tl && (1u<<15)) Printf("image_purge_deleted_entries: Successful, nimages now %d\n", nimages); + #endif + + return 1; +} + +/*************************************************/ +/* image_post_deletion_clearup() */ +/* */ +/* After deleting a set of images or image_info */ +/* structures which had no associated data in */ +/* ImageLib, call this to tidy up - deregister */ +/* the animation handler, resize the idata flex */ +/* block, etc. */ +/*************************************************/ + +static void image_post_deletion_clearup(void) +{ + int i; + + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_post_deletion_clearup: Called\n"); + #endif + + _swix(Hourglass_Start, _IN(0), 1); + + /* Compact the image_info array and shrink the idata flex block; */ + /* if the function returns 0 we've no work to do here */ + + if (image_purge_deleted_entries()) + { + /* If there is an animation handler present, but no animated */ + /* images remain, remove that handler. */ + + if (animhandler) + { + int found = 0; + + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_post_deletion_clearup: There is an animation handler present; checking to see if it can be removed\n"); + #endif + + for (i = 0; i < nimages; i++) + { + if (idata[i].istore && idata[i].istore->animated) + { + found = 1; + break; + } + } + + if (!found) + { + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_post_deletion_clearup: Removing animation handler\n\n"); + #endif + + deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) image_animate_images, NULL); + animhandler = 0; + } + + #ifdef TRACE + + else + { + if (tl & (1u<<15)) Printf("image_post_deletion_clearup: The handler is still required\n\n"); + } + + #endif + } + } + + /* Trace build sanity check */ + #ifdef FAST_TOKEN_REFERENCE #ifdef TRACE @@ -2169,6 +2419,10 @@ static void image_post_deletion_clearup(void) _swix(Hourglass_Off, 0); + #ifdef TRACE + if (tl & (1u<<15)) Printf("image_post_deletion_clearup: Successful\n"); + #endif + return; } @@ -2187,6 +2441,12 @@ static void image_post_deletion_clearup(void) /* caller must remember to invoke */ /* image_post_deletion_clearup. */ /* */ +/* It is assumed that for any images marked as */ +/* suitable for GC, the owner browser still */ +/* exists. Consequently, this function MUST be */ +/* called for a given browser if that browser is */ +/* about to be shut down. */ +/* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the images to collect */ /* or NULL to remove any images */ @@ -2227,8 +2487,6 @@ _kernel_oserror * image_gc(browser_data * b, unsigned int uid, int remove_js_too clearup = 1; } } - - if (clearup) image_post_deletion_clearup(); } /* Find the given unique ID */ @@ -2288,6 +2546,8 @@ _kernel_oserror * image_gc(browser_data * b, unsigned int uid, int remove_js_too #endif } + if (clearup) image_post_deletion_clearup(); + return NULL; } @@ -3028,8 +3288,8 @@ static _kernel_oserror * image_update_image(browser_data * b, int image, BBox * { /* Ignore errors, this isn't vital */ - imghistory_record((const char **) &ddata, - image_data_offset(i), + imghistory_record((const char **) &idata[i].flex->urldata, + 0, idata[i].istore->width_os, idata[i].istore->height_os); } @@ -3088,8 +3348,8 @@ static _kernel_oserror * image_update_image(browser_data * b, int image, BBox * { /* Ignore errors, this isn't vital */ - imghistory_record((const char **) &ddata, - image_data_offset(i), + imghistory_record((const char **) &idata[i].flex->urldata, + 0, idata[i].istore->width_os, idata[i].istore->height_os); } @@ -3407,23 +3667,10 @@ _kernel_oserror * image_fill_background(void * handle, int * i) /* The image may exist in a table, and we should check what */ /* background colour to draw if this is the case. */ - if (idata[image].token && idata[image].token->parent) + if (idata[image].token && b->use_source_cols) { - table_headdata * head = idata[image].token->parent; - table_row * row = NULL; - table_stream * table = NULL; - - if (head) row = head->parent; - if (row) table = row->parent; - - if (table) - { - if (TABLE_HAS_BGCOL(table)) bgcolour = TABLE_BGCOL(table), noplot = 1; - - /* Individual cells can override the table */ - - if (TD_HAS_BGCOL(head)) bgcolour = TD_BGCOL(head), noplot = 1; - } + int effective_bgcolour = tokenutils_background_colour(b, idata[image].token); + if (effective_bgcolour > -1) bgcolour = effective_bgcolour, noplot = 1; } /* We may still have no defined background colour, in which */ @@ -3551,6 +3798,7 @@ _kernel_oserror * image_fill_background(void * handle, int * i) float tempx, tempy; float tempw, temph; int htop; + int oimage; #ifdef TRACE if (tl & (1u<<15)) Printf("image_fill_background: Plotting scaled background\n"); @@ -3602,12 +3850,18 @@ _kernel_oserror * image_fill_background(void * handle, int * i) { for (x = redraw.xmin; x <= redraw.xmax; x += w) { + oimage = image_redrawing; + image_redrawing = bimage; + e = (idata[bimage].istore -> Render(idata[bimage].istore, x, y, 100, w, h)); + + image_redrawing = oimage; + if (e) break; } @@ -3620,6 +3874,7 @@ _kernel_oserror * image_fill_background(void * handle, int * i) { BBox redraw; int htop; + int oimage; #ifdef TRACE if (tl & (1u<<15)) Printf("image_fill_background: Plotting unscaled background\n"); @@ -3654,12 +3909,17 @@ _kernel_oserror * image_fill_background(void * handle, int * i) { for (x = redraw.xmin; x <= redraw.xmax; x += w) { + oimage = image_redrawing; + image_redrawing = bimage; + e = (idata[bimage].istore -> Render(idata[bimage].istore, x, y, 100, -1, -1)); + image_redrawing = oimage; + if (e) break; } @@ -3716,11 +3976,10 @@ _kernel_oserror * image_redraw(browser_data * b, WimpRedrawWindowBlock * r, HStr /* image for the given token, which may cross reference 'image', which */ /* holds the actual render data. */ - image = image_get_token_image_actual(b, token); + image = actual = image_get_token_image_actual(b, token); if (image < 0) return NULL; - actual = image; if (idata[actual].xref >= 0) image = idata[actual].xref; /* If the image has a fetched width and height, */ @@ -3890,7 +4149,7 @@ int image_tile_window(browser_data * b, WimpRedrawWindowBlock * r, int xorigin, for (x = xmin; x <= r->redraw_area.xmax; x += w) { browser_redrawing = b; - image_redrawing = image; + image_redrawing = b->background_image; e = idata[image].istore -> Render(idata[image].istore, x, @@ -4055,38 +4314,6 @@ _kernel_oserror * image_mode_change(void) return NULL; } -/*************************************************/ -/* image_data_offset() */ -/* */ -/* Returns the offset into the ddata block of */ -/* the data associated with a given image. */ -/* */ -/* Parameters: An image number, from 0 to */ -/* nimages - 1. */ -/* */ -/* Returns: Pointer to the data associated */ -/* with that image (as a char *). */ -/*************************************************/ - -static int image_data_offset(int image) -{ - int i, count = 0; - - #ifdef TRACE - if (tl & (1u<<15)) Printf("image_data_offset: Called for image %d\n",image); - #endif - - if (image <= 0) return 0; /* Image 0's data offset will be zero... */ - - for (i = 0; i < image; count += idata[i].alloc, i++); - - #ifdef TRACE - if (tl & (1u<<15)) Printf("image_data_offset: Successful\n"); - #endif - - return count; -} - /*************************************************/ /* image_count_fetches() */ /* */ @@ -4263,7 +4490,7 @@ int image_total_bytes_fetched(browser_data * b) for (image = 0; image < nimages; image++) { - if (idata[image].owner == b) count += idata[image].bytesgot; + if (idata[image].owner == b && idata[image].token) count += idata[image].bytesgot; } } @@ -4501,7 +4728,7 @@ static int image_get_token_image_xref(browser_data * b, HStream * token) /* is the one with render data attached, not */ /* just a cross reference image. */ - if (found >= 0) + if (found >= 0 && found < nimages) { if (idata[found].xref >= 0) found = idata[found].xref; } @@ -4870,8 +5097,8 @@ static _kernel_oserror * image_get_image_size(browser_data * b, int image, BBox if (real_width <= 0 && real_height <= 0) { - imghistory_return_size((const char **) &ddata, - image_data_offset(actual), + imghistory_return_size((const char **) &idata[actual].flex->urldata, + 0, &real_width, &real_height); } @@ -5300,7 +5527,6 @@ int image_set_token_image_position(browser_data * b, HStream * t, int x, int y) void image_get_background_image_url(browser_data * b, char * buffer, int size) { - int offset; int old_budge; int image = b ? b->background_image : -1; @@ -5310,17 +5536,13 @@ void image_get_background_image_url(browser_data * b, char * buffer, int size) if (size < 2 || image < 0 || image >= nimages) return; - /* Find the offset of the URL in the 'ddata' block */ - - offset = image_data_offset(image); - /* Lock flex */ old_budge = flex_set_budge(0); /* Copy the URL in, ensuring termination */ - strncpy(buffer, ddata + offset, size); + strncpy(buffer, idata[image].flex->urldata, size); buffer[size - 1] = 0; /* Restore flex's previous budge state */ @@ -5367,7 +5589,7 @@ void image_convert_to_pixels(browser_data * b, HStream * token, int * x, int * y /* If the library has got enough information to fill in the */ /* width of the image, proceed with the conversion */ - if (image >= 0 && idata[image].istore->width > 0) + if (image >= 0 && idata[image].istore && idata[image].istore->width > 0) { *x = *x * idata[image].istore->width / idata[image].istore->width_os; *y = *y * idata[image].istore->height / idata[image].istore->height_os; @@ -5557,7 +5779,8 @@ int image_token_can_be_saved_as_sprite(browser_data * b, HStream * image) _kernel_oserror * image_export_sprite(char * path, browser_data * b, HStream * image) { - int i; + int im, i; + _kernel_oserror * e; if (!path || !*path) return NULL; @@ -5565,8 +5788,11 @@ _kernel_oserror * image_export_sprite(char * path, browser_data * b, HStream * i /* Find the image number */ - if (!image) i = b->background_image; - else i = image_get_token_image_xref(b, image); + if (!image) im = b->background_image; + else im = image_get_token_image_actual(b, image); + + if (idata[im].xref >= 0) i = idata[im].xref; + else i = im; /* Must have image data... */ @@ -5588,9 +5814,17 @@ _kernel_oserror * image_export_sprite(char * path, browser_data * b, HStream * i /* Export the image */ - return idata[i].istore -> DumpSprite(idata[i].istore, - path, - -1); + browser_redrawing = b; + image_redrawing = im; + + e = idata[i].istore -> DumpSprite(idata[i].istore, + path, + -1); + + browser_redrawing = NULL; + image_redrawing = -1; + + return e; } /*************************************************/ @@ -5637,7 +5871,7 @@ int image_sprite_size(browser_data * b, HStream * image) _kernel_oserror * image_export_original(char * path, browser_data * b, HStream * image) { char url[Limits_URL]; - int i, offset; + int i; if (!path || !*path) return NULL; @@ -5650,9 +5884,7 @@ _kernel_oserror * image_export_original(char * path, browser_data * b, HStream * /* Must have image data... */ - offset = image_data_offset(i); - - if (!ddata[offset]) + if (!idata[i].flex->urldata) { #ifdef TRACE @@ -5670,7 +5902,7 @@ _kernel_oserror * image_export_original(char * path, browser_data * b, HStream * /* Start a fetch for this URL */ - strncpy(url, ddata + offset, sizeof(url)); + strncpy(url, idata[i].flex->urldata, sizeof(url)); url[sizeof(url) - 1] = 0; RetError(windows_create_browser(url, @@ -5886,9 +6118,6 @@ int image_to_draw_file(browser_data * b, WimpRedrawWindowBlock * r, HStream * to // int image_size = 0; - browser_redrawing = b; - image_redrawing = actual; - if (!dont_create || !unique_name) { unique_name = malloc(Limits_OS_Pathname); @@ -5899,9 +6128,15 @@ int image_to_draw_file(browser_data * b, WimpRedrawWindowBlock * r, HStream * to /* Output the sprite, skipping the first 12 bytes of sprite area header */ + browser_redrawing = b; + image_redrawing = actual; + e = idata[image].istore -> DumpSprite(idata[image].istore, unique_name, -1); + + browser_redrawing = NULL; + image_redrawing = -1; } } @@ -5957,6 +6192,9 @@ int image_to_draw_file(browser_data * b, WimpRedrawWindowBlock * r, HStream * to unique_name = NULL; } +// browser_redrawing = b; +// image_redrawing = actual; +// // e = idata[image].istore -> StartExport(idata[image].istore, &image_size); // ok = 1; // @@ -5974,12 +6212,12 @@ int image_to_draw_file(browser_data * b, WimpRedrawWindowBlock * r, HStream * to // } // // e = idata[image].istore -> EndExport(idata[image].istore); +// +// browser_redrawing = NULL; +// image_redrawing = -1; /* Flag if we succeeded */ - browser_redrawing = NULL; - image_redrawing = -1; - if (!e && ok) plotted = 1; } @@ -6070,9 +6308,15 @@ int image_draw_file_size(browser_data * b, HStream * token, int dont_delete) { protocols_util_make_unique_name(unique_name, Limits_OS_Pathname); + browser_redrawing = b; + image_redrawing = actual; + e = idata[image].istore -> DumpSprite(idata[image].istore, unique_name, -1); + + browser_redrawing = NULL; + image_redrawing = -1; } if (!e && unique_name) @@ -6164,8 +6408,8 @@ int image_tile_to_draw(browser_data * b, WimpRedrawWindowBlock * r, int xorigin, /* Work out the coordinates over which to tile the image */ - xmin = coords_x_toworkarea(r->redraw_area.xmin,r); - ymax = coords_y_toworkarea(r->redraw_area.ymax,r); + xmin = coords_x_toworkarea(r->redraw_area.xmin, r); + ymax = coords_y_toworkarea(r->redraw_area.ymax, r); xmin -= ((xmin - xorigin) % w); ymax -= ((ymax - yorigin) % h) + 1; @@ -6195,10 +6439,16 @@ int image_tile_to_draw(browser_data * b, WimpRedrawWindowBlock * r, int xorigin, protocols_util_make_unique_name(name, sizeof(name)); + browser_redrawing = b; + image_redrawing = b->background_image; + e = idata[image].istore -> DumpSprite(idata[image].istore, name, -1); + browser_redrawing = NULL; + image_redrawing = -1; + if (!e) { e = _swix(OS_File, @@ -6270,14 +6520,7 @@ int image_tile_to_draw(browser_data * b, WimpRedrawWindowBlock * r, int xorigin, /* Write out the image */ - browser_redrawing = b; - image_redrawing = image; - ok = savedraw_write_bytes(block, image_size); - - browser_redrawing = NULL; - image_redrawing = -1; - if (!ok) goto image_tile_to_draw_exit; #ifdef STRICT_PARSER diff --git a/c/JSwindow b/c/JSwindow index 064e477dd4b8d55ee8c6b4f37b2dc3e136ed6a79..087107433490a8851595b398f369fffc4a75e46f 100644 --- a/c/JSwindow +++ b/c/JSwindow @@ -391,7 +391,6 @@ jsdocument_initialise_class(b); jsdocument_define_document(b); - jsurl_define_location(b); // JSObject *obj; @@ -1215,7 +1214,11 @@ case WIN_OPENER: { - if (decoder->opener && !JSVAL_TO_OBJECT(*vp)) decoder->opener = NULL; + if ( + decoder->opener && + !JSVAL_TO_OBJECT(*vp) + ) + decoder->opener = NULL; } break; diff --git a/c/JavaScript b/c/JavaScript index 8ac2f27e358190a4c59bba656d518d5b817655a5..ee87385ace95719c4eaea2c3df27980efc39f7eb 100644 --- a/c/JavaScript +++ b/c/JavaScript @@ -114,6 +114,8 @@ _kernel_oserror * javascript_body_onload(browser_data * b) if (tl & (1u<<24)) Printf("javascript_body_onload: Called\n"); #endif + if (!b->onload || !*b->onload) return NULL; + #ifdef CUSTOMER_SPECIAL /* Only call customer_ functions if on the customer's site */ @@ -125,7 +127,19 @@ _kernel_oserror * javascript_body_onload(browser_data * b) #endif - b->onload = NULL; + /* This is a bit unusual as the Customer hack existed before any real */ + /* JS support, hence the function itself being 'live' even in non JS */ + /* builds. */ + + #ifdef JAVASCRIPT + + e = javascript_process_script(b, b->onload); + + #endif + + /* Prevent multiple script executions... */ + + b->onload = ""; return e; } diff --git a/c/Reformat b/c/Reformat index 25ea8640185e7e4946eae623b34031e9e26e72c4..5dd94f7f7b11a201228cea35e5b4cd5c52a26108 100644 --- a/c/Reformat +++ b/c/Reformat @@ -2866,6 +2866,24 @@ static int reformat_reformatter_r(unsigned int flags, browser_data * b, reformat if (!newchunks) bottom = y; + /* If this is the first line for a whole page, see if we should */ + /* now clear the background colour and image */ + + if (!d->table && !d->nlines) + { + if (!b->onload && !b->onunload) + { + b->background_colour = -1; /* Background colour, or -1 for default */ + b->background_image = -1; /* Image no. of background image, 0=none */ + b->antialias_colour = redraw_backcol(b); /* Colour to anti-alias to, or -1=none */ + + browser_update_bottom(b, 0); + + b->onload = ""; + b->onunload = ""; + } + } + /* Add the new line structure */ e = reformat_add_line(b, d); diff --git a/c/TokenUtils b/c/TokenUtils index b86b3f7c5808fba89409e1308d219ab6c541aeb3..13c6f34eb587e153892abf35082abc15ac309507 100644 --- a/c/TokenUtils +++ b/c/TokenUtils @@ -1025,3 +1025,51 @@ int tokenutils_within_distance(browser_data * b, HStream * t1, HStream * t2, int return (check <= distance); } + +/*************************************************/ +/* tokenutils_background_colour() */ +/* */ +/* See what background colour should be used for */ +/* a body text token; deals with tables, going */ +/* down through the structure until something */ +/* with a background colour is found (just */ +/* checking the immediate local table or cell is */ +/* not good enough as a background colour from */ +/* an outer level table as part of a nested set */ +/* of cells may be what is showing through). */ +/* */ +/* Parameters: Pointer to a browser_data struct */ +/* relevant to the token; */ +/* */ +/* Pointer to the HStream struct */ +/* who's background colour should be */ +/* returned. */ +/* */ +/* Returns: Background colour as BBGGRR00, */ +/* or -1 if none was found (so you */ +/* should use redraw_backcol() or */ +/* any page background image). */ +/*************************************************/ + +int tokenutils_background_colour(browser_data * b, HStream * t) +{ + while (t && t->parent) + { + table_headdata * head = t->parent; + table_row * row = NULL; + table_stream * table = NULL; + + if (head) row = head->parent; + if (row) table = row->parent; + + if (table) + { + if (TD_HAS_BGCOL(head)) return TD_BGCOL(head); + if (TABLE_HAS_BGCOL(table)) return TABLE_BGCOL(table); + } + + t = (HStream *) table; + } + + return -1; +} diff --git a/c/URLutils b/c/URLutils index 2b534a9b0629a9f91491a8ee969d32c335e8bb86..c75af6a6bbc0479c7ab325ea4ce54a33d38bcfaa 100644 --- a/c/URLutils +++ b/c/URLutils @@ -1804,7 +1804,7 @@ void urlutils_set_displayed(browser_data * b, char * iurl) } /*************************************************/ -/* Urlutils_check_protocols() */ +/* urlutils_check_protocols() */ /* */ /* Checks a given URL to see if the fetch */ /* protocol it specifies can be handled. */ diff --git a/c/Windows b/c/Windows index 9e7f9526150bae4a0a0c36238cbf90e7e6154f5f..27da60e26212db62fa6b5d7c37a3e320c45534b4 100644 --- a/c/Windows +++ b/c/Windows @@ -531,9 +531,18 @@ _kernel_oserror * windows_create_browser(const char * url, browser_data * real_p #ifdef JAVASCRIPT - /* Get an execution context for this window */ + if (save_type == Windows_CreateBrowser_AsJSChild && real_parent) + { + /* Get an execution context using the parent */ + + RetError(javascript_gain_context(b, real_parent)); + } + else + { + /* Get an execution context using any ancestor */ - RetError(javascript_gain_context(b, b->ancestor)); + RetError(javascript_gain_context(b, b->ancestor)); + } #endif @@ -1129,11 +1138,16 @@ int windows_open_browser(int eventcode, WimpPollBlock * b, IdBlock * idb, browse } else { - b->open_window_request.visible_area.xmin = s.visible_area.xmin; - b->open_window_request.visible_area.xmax = s.visible_area.xmax; + int add, rmarg; + + convert_to_os(choices.right_margin, &rmarg); + + if (s.visible_area.xmax - s.visible_area.xmin > handle->display_extent) add = s.visible_area.xmax - s.visible_area.xmin; + else if (s.visible_area.xmax - s.visible_area.xmin < handle->display_extent) add = handle->display_extent + rmarg * 2; /* To give a reasonable right border gap */ + else add = handle->display_extent; - w.xmin = s.visible_area.xmin; - w.xmax = s.visible_area.xmax; + w.xmin = b->open_window_request.visible_area.xmin = s.visible_area.xmin; + w.xmax = b->open_window_request.visible_area.xmax = s.visible_area.xmin + add; } b->open_window_request.visible_area.ymin = s.visible_area.ymin - o.outline.ymin + (shift ? 128 : 0); diff --git a/h/Images b/h/Images index e5fcfba3e75f75a86679d98fe18601b3b465905a..4a9ea737d1708aef87819066defceac9892bbd25 100644 --- a/h/Images +++ b/h/Images @@ -42,6 +42,18 @@ #define ImageDefaultOSSize_X 48 #define ImageDefaultOSSize_Y 48 +/* The image_flex structure is used to hold flex anchors. It is */ +/* attached to image_info (below) in a small malloc block; since */ +/* image_info structs are held in a flex area they cannot hold */ +/* the flex anchors directly. */ + +typedef struct image_flex +{ + char * urldata; + void * fetchdata; +} +image_flex; + /* The image_info structure is used for the image handling code, */ /* where each image has associated data about its size, fetch */ /* status and so-on. */ @@ -59,10 +71,7 @@ typedef struct image_info int x; /* X position on the page for the owner */ int y; /* Y position on the page for the owner */ - int dataoffset; /* Offset of image data within image data block */ - int alloc; /* Total space allocated in flex block */ - int ualloc; /* Space allocated to url in flex block */ - int isize; /* Size of image storage used */ + image_flex * flex; /* For URL data, fetch data etc. */ HStream * token; /* Token this image appears in - may be NULL (pending GC) */ time_t last_used; /* Time when the image was last used (for GC purposes) */ @@ -73,6 +82,8 @@ typedef struct image_info int bytesgot; /* Total bytes fetched for this image so far */ + unsigned int deleted :1; /* Image is marked as deleted (so remove it from array ASAP!) */ + unsigned int started :1; /* The fetch has started to happen */ unsigned int fetched :1; /* Flag indicating the image is fetched */ unsigned int delayed :1; /* Flag indicating the image is delayed (by delayimages option) */ diff --git a/h/TokenUtils b/h/TokenUtils index 84b48ad38bb9166e16f908889b4005a98243c1f5..fff04cc90628eb37433b274503ab2f29c3a347f0 100644 --- a/h/TokenUtils +++ b/h/TokenUtils @@ -44,3 +44,5 @@ reformat_cell * tokenutils_find_cell (reformat_cell * cell, int depth, void tokenutils_token_offset (browser_data * b, token_path * path, int * offset_x, int * offset_y); reformat_cell * tokenutils_token_cell (browser_data * b, HStream * token); int tokenutils_within_distance (browser_data * b, HStream * t1, HStream * t2, int distance); + +int tokenutils_background_colour (browser_data * b, HStream * t);