diff --git a/c/Browser b/c/Browser
index 5d399654dee4522aa2275100e85c313108a6a685..e75fab97dbdb46e11813300cb1e7c196a9325178 100644
--- a/c/Browser
+++ b/c/Browser
@@ -660,7 +660,7 @@ HStream * browser_find_selectable_top_r(browser_data * b, reformat_cell * cell,
 
         /* Deal with tables */
 
-        if (t->tag == TABLE && ISBODY(t))
+        if (t->tagno == TAG_TABLE)
         {
           table_stream   * table     = (table_stream *) t;
           table_row      * row       = table->List;
@@ -968,7 +968,7 @@ HStream * browser_find_selectable_bot_r(browser_data * b, reformat_cell * cell,
 
         /* Deal with tables */
 
-        if (t->tag == TABLE && ISBODY(t))
+        if (t->tagno == TAG_TABLE)
         {
           table_stream   * table     = (table_stream *) t;
           table_row      * row       = NULL;
@@ -1977,7 +1977,7 @@ static HStream * browser_get_pointer_token_r(browser_data * b, reformat_cell * c
 
       /* If the token represents a table... */
 
-      if (tp->tag == TABLE && ISBODY(tp))
+      if (tp->tagno == TAG_TABLE)
       {
         /* In this case there are table streams hung from d->cdata */
 
@@ -2115,7 +2115,7 @@ static HStream * browser_get_pointer_token_r(browser_data * b, reformat_cell * c
 
         return over;
 
-      /* Closure of 'if (tp->tag == TABLE && ISBODY(tp))' */
+      /* Closure of 'if (tp->tagno == TAG_TABLE)' */
       }
 
       /* If the token represents an image... */
@@ -2341,7 +2341,7 @@ static int browser_top_line_r(browser_data * b, reformat_cell * cell, reformat_c
 
     /* Otherwise, is there a table in the line? */
 
-    if (first_token->tag == TABLE && ISBODY(first_token))
+    if (first_token->tagno == TAG_TABLE)
     {
       table_stream   * table     = (table_stream *) first_token;
       table_row      * row       = NULL;
@@ -2411,7 +2411,7 @@ static int browser_top_line_r(browser_data * b, reformat_cell * cell, reformat_c
       /* Closure of 'if (cellarray)' */
       }
 
-    /* Closure of 'if (first_token->tag == TABLE && ISBODY(first_token))' */
+    /* Closure of 'if (first_token->tagno == TAG_TABLE)' */
     }
 
   /* Closure of 'else' case for 'if (l >= cell->nlines)' */
@@ -2528,7 +2528,7 @@ static int browser_bottom_line_r(browser_data * b, reformat_cell * cell, reforma
 
     /* Otherwise, is there a table in the line? */
 
-    if (first_token->tag == TABLE && ISBODY(first_token))
+    if (first_token->tagno == TAG_TABLE)
     {
       table_stream   * table     = (table_stream *) first_token;
       table_row      * row       = NULL;
@@ -2606,7 +2606,7 @@ static int browser_bottom_line_r(browser_data * b, reformat_cell * cell, reforma
       /* Closure of 'if (cellarray)' */
       }
 
-    /* Closure of 'if (first_token->tag == TABLE && ISBODY(first_token))' */
+    /* Closure of 'if (first_token->tagno == TAG_TABLE)' */
     }
 
   /* Closure of 'else' case for 'if (l >= cell->nlines)' */
diff --git a/c/Fetch b/c/Fetch
index f9cc880f554d2fc274d97845ea991595fcc91acc..38b673556a2ed6a419bd56b4906e25acb5396640 100644
--- a/c/Fetch
+++ b/c/Fetch
@@ -58,6 +58,7 @@
 #include "Images.h"
 #include "Memory.h"
 #include "Meta.h"
+#include "Object.h"
 #include "Redraw.h"
 #include "Reformat.h"
 #include "SaveFile.h"
@@ -296,10 +297,7 @@ static HStream * fetch_find_anchor_token_r(browser_data * b, HStream * streambas
   {
     /* A table token? */
 
-    if (
-         tp->tag == TABLE &&
-         ISBODY(tp)
-       )
+    if (tp->tagno == TAG_TABLE)
     {
       table_stream   * table      = (table_stream *) tp;
       table_row      * row        = NULL;
@@ -390,7 +388,7 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr)
   /* Are we reprocessing the contents of a table tag which has been */
   /* dealt with before?                                             */
 
-  if (tptr->tag == TABLE && ISBODY(tptr)) reprocess_table = 1;
+  if (tptr->tagno == TAG_TABLE) reprocess_table = 1;
 
   /* Deal with smart quotes etc. */
 
@@ -423,6 +421,15 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr)
                                            0))) return;
       }
 
+      /* Ask the Object library to handle a new OBJECT, EMBED or APPLET tag */
+
+      if (tptr->tagno == TAG_OBJECT)
+      {
+        if (fetch_chkerror(b,
+                           object_new_object(b,
+                                             tptr))) return;
+      }
+
       /* Handle some form tags */
 
       if (tptr->style & FORM)
@@ -478,7 +485,7 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr)
     /* later date (e.g. as part of the reformatting process) to ensure they */
     /* are all preprocessed correctly.                                      */
 
-    if (tptr->tag == TABLE)
+    if (tptr->tagno == TAG_TABLE)
     {
       table_stream   * table = (table_stream *) tptr;
       table_row      * R;
@@ -512,14 +519,8 @@ void fetch_preprocess_token(browser_data * b, HStream * tptr)
                 while (attached)
                 {
                   if (
-                       (
-                         ISBODY(attached) &&
-                         attached->tag == TABLE
-                       )
-                       ||
-                       (
-                         !(attached->flags & HFlags_DealtWithToken)
-                       )
+                       attached->tagno == TAG_TABLE ||
+                       !(attached->flags & HFlags_DealtWithToken)
                      )
                      fetch_preprocess_token(b, attached);
 
@@ -1294,7 +1295,7 @@ void fetch_fetcher(browser_data * b)
 
       if (!tptr)
       {
-        if (b->last_token->tag == TABLE && ISBODY(b->last_token))
+        if (b->last_token->tagno == TAG_TABLE)
         {
           /* If the last thing the reformatter dealt with was a table, */
           /* then extra table structures could have been added by      */
@@ -1497,11 +1498,29 @@ void fetch_stop(browser_data * b, int keep_source)
 
   if (b->save_dbox) saveobject_close(b);
 
-  /* If there is a fetch, and the associated HTML document isn't being */
-  /* used by the display routines, close that fetch handle and free    */
-  /* any memory associated with it.                                    */
+  if (b->fetch_handle)
+  {
+    /* If there is a fetch, and the associated HTML document isn't being */
+    /* used by the display routines, close that fetch handle and free    */
+    /* any memory associated with it.                                    */
+
+    if (b->fetch_handle != b->display_handle) html_close(b->fetch_handle);
+
+    /* Otherwise, still have to call EndParse (which html_close would */
+    /* do, if it were called).                                        */
+
+    else
+    {
+      urlstat * up = urlstat_find_entry(b->fetch_handle);
+
+      if (up && up->context)
+      {
+        HtmlEndParse(up->context);
+        up->context = NULL;
+      }
+    }
+  }
 
-  if ((b->fetch_handle) && (b->fetch_handle != b->display_handle)) html_close(b->fetch_handle);
   b->fetch_handle = 0;
 
   /* Discard the URL being fetched */
diff --git a/c/FetchHTML b/c/FetchHTML
index be151e0b1aa8df8ed295f80a1966b5c18b5bc63f..2fadf97e1591e129af1bbf49f0ffd3bf06bd3317 100644
--- a/c/FetchHTML
+++ b/c/FetchHTML
@@ -1683,16 +1683,7 @@ _kernel_oserror * html_get_next_token(browser_data * b, unsigned int handle, int
       e = url_status(0, handle, &s, NULL, NULL);
       if (e) return e;
 
-      if (s & URL_Status_Done)
-      {
-        up->fetching = 0;
-
-        if (up->context)
-        {
-          HtmlEndParse(up->context);
-          up->context = NULL;
-        }
-      }
+      if (s & URL_Status_Done) up->fetching = 0;
     }
   }
 
diff --git a/c/Object b/c/Object
index 066401ac9fdb6068aa7b03bb958363ac3c688504..0c809fc7b71f8e06e4398666efac5515597639ce 100644
--- a/c/Object
+++ b/c/Object
@@ -46,6 +46,8 @@
 #include "Fetch.h" /* (Which itself includes URLstat.h) */
 #include "FetchHTML.h"
 #include "Images.h"
+#include "Memory.h"
+#include "MiscDefs.h"
 #include "PlugIn.h"
 #include "Redraw.h"
 #include "Reformat.h"
@@ -53,3 +55,340 @@
 #include "URLveneer.h"
 
 #include "Object.h"
+
+/* Static function prototypes */
+
+static int               object_get_token_object (browser_data * b, HStream * t);
+static _kernel_oserror * object_get_object_size  (browser_data * b, int object, BBox * size);
+
+/*************************************************/
+/* object_new_object()                           */
+/*                                               */
+/* Adds a structure for a new Object to a        */
+/* browser's array of Objects.                   */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             to add to;                        */
+/*                                               */
+/*             Pointer to a token representing   */
+/*             the Object (OBJECT, EMBED or      */
+/*             APPLET tag).                      */
+/*************************************************/
+
+_kernel_oserror * object_new_object(browser_data * b, HStream * t)
+{
+  _kernel_oserror * e;
+
+  /* If this isn't an Object token, do nothing (well, */
+  /* complain about it in TRACE builds).              */
+
+  if (!t || t->tagno != TAG_OBJECT)
+  {
+    #ifdef TRACE
+
+      erb.errnum = Utils_Error_Custom_Normal;
+
+      sprintf(erb.errmess,
+              "Token %08x passed to object_new_object does not represent an OBJECT, APPLET or EMBED tag",
+              (int) t);
+
+      return &erb;
+
+    #endif
+
+    return NULL;
+  }
+
+  /* Allocate memory for the item */
+
+  RetError(memory_set_chunk_size(b,
+                                 NULL,
+                                 CK_OBJB,
+                                 (b->nobjects + 1) * sizeof(object_info)));
+
+  /* Fill in the new item */
+
+  b->odata[b->nobjects].browser_instance_handle = 0;
+  b->odata[b->nobjects].plugin_instance_handle  = 0;
+  b->odata[b->nobjects].plugin_task_handle      = 0;
+  b->odata[b->nobjects].token                   = t;
+
+  /* Width and height initially come from the token, but if this */
+  /* ends up leading to a Plug-In being called, that Plug-In     */
+  /* could ask for the size to change; hence the 'width' and     */
+  /* 'height' fields.                                            */
+
+  b->odata[b->nobjects].units                   = UNITS_PIXELS;
+  b->odata[b->nobjects].width                   = t->rows;
+  b->odata[b->nobjects].height                  = t->cols;
+
+  /* Finally, increment the objects counter */
+
+  b->nobjects++;
+
+  return NULL;
+}
+
+/*************************************************/
+/* object_discard()                              */
+/*                                               */
+/* Discards all Objects held by a given browser. */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the Objects.          */
+/*************************************************/
+
+_kernel_oserror * object_discard(browser_data * b)
+{
+  b->nobjects = 0;
+
+  return memory_set_chunk_size(b, NULL, CK_OBJB, 0);
+}
+
+/*************************************************/
+/* object_get_token_object()                     */
+/*                                               */
+/* Return the number of the Object represented   */
+/* in the given browser by the given token.      */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the Objects;          */
+/*                                               */
+/*             Pointer to a token representing   */
+/*             the Object (OBJECT, EMBED or      */
+/*             APPLET tag).                      */
+/*                                               */
+/* Returns:    Number of the Object from 0 to    */
+/*             number of Objects minus 1, or -1  */
+/*             if the Object cannot be found.    */
+/*************************************************/
+
+static int object_get_token_object(browser_data * b, HStream * t)
+{
+  int found = -1;
+  int i;
+
+  /* If this isn't an Object token, do nothing (well, */
+  /* complain about it in TRACE builds).              */
+
+  if (!t || t->tagno != TAG_OBJECT)
+  {
+    #ifdef TRACE
+
+      erb.errnum = Utils_Error_Custom_Normal;
+
+      sprintf(erb.errmess,
+              "Token %08x passed to object_new_object does not represent an OBJECT, APPLET or EMBED tag",
+              (int) t);
+
+      show_error_ret(&erb);
+
+    #endif
+
+    return -1;
+  }
+
+  /* Otherwise, try to find the item */
+
+  for (i = 0; i < b->nobjects; i++)
+  {
+    if (b->odata[i].token == t)
+    {
+      found = i;
+      break;
+    }
+  }
+
+  return found;
+}
+
+/*************************************************/
+/* object_get_object_size()                      */
+/*                                               */
+/* Returns the size of a given Object.           */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             to add to;                        */
+/*                                               */
+/*             Number of the Object, from 0 to   */
+/*             number of Objects minus 1;        */
+/*                                               */
+/*             Pointer to a BBox, in which the   */
+/*             size of the Object will be        */
+/*             written.                          */
+/*************************************************/
+
+static _kernel_oserror * object_get_object_size(browser_data * b, int object, BBox * size)
+{
+  /* Can't do anything without a bounding box! */
+
+  if (!size)
+  {
+    #ifdef TRACE
+
+      erb.errnum = Utils_Error_Custom_Normal;
+      strcpy(erb.errmess, "Null bounding box pointer passed to object_get_object_size");
+      return &erb;
+
+    #endif
+
+    return NULL;
+  }
+
+  /* Fill in zeros to start with */
+
+  size->xmin = size->ymin = 0;
+  size->xmax = size->ymax = 0;
+
+  /* Is this a valid object number? */
+
+  if (object < 0 || object >= b->nobjects)
+  {
+    #ifdef TRACE
+
+      erb.errnum = Utils_Error_Custom_Normal;
+
+      sprintf(erb.errmess,
+              "Invalid object number %d for passed to object_get_object_size (browser %08x, nobjects = %d)",
+              object,
+              (int) b,
+              b->nobjects);
+
+      return &erb;
+
+    #endif
+
+    return NULL;
+  }
+
+  /* Find its size */
+
+  if (b->odata[object].units == UNITS_PIXELS)
+  {
+    size->xmax = b->odata[object].width  * 2; /* A 'web pixel' -> 2 OS units under RISC OS */
+    size->ymax = b->odata[object].height * 2;
+  }
+
+  return NULL;
+}
+
+/*************************************************/
+/* object_get_token_object_size()                */
+/*                                               */
+/* Returns the size of a given Object.           */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             to add to;                        */
+/*                                               */
+/*             Pointer to a token representing   */
+/*             the Object (OBJECT, EMBED or      */
+/*             APPLET tag);                      */
+/*                                               */
+/*             Pointer to a BBox, in which the   */
+/*             size of the Object will be        */
+/*             written.                          */
+/*************************************************/
+
+_kernel_oserror * object_get_token_object_size(browser_data * b, HStream * t, BBox * size)
+{
+  return object_get_object_size(b, object_get_token_object(b, t), size);
+}
+
+/*************************************************/
+/* object_redraw()                               */
+/*                                               */
+/* Does a high level redraw of an Object, using  */
+/* an outline to show where the Object should be */
+/* if it isn't plotted by some other method.     */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the Object;           */
+/*                                               */
+/*             Pointer to a RedrawWindowBlock    */
+/*             struct which holds information    */
+/*             about the current redraw session; */
+/*                                               */
+/*             Address of the token representing */
+/*             the OBJECT, APPLET or EMBED tag;  */
+/*                                               */
+/*             The X offset in window coords (so */
+/*             OS units) of the left hand edge   */
+/*             of the Object;                    */
+/*                                               */
+/*             The Y offset in window coords (so */
+/*             OS units) of the bottom edge of   */
+/*             the Object.                       */
+/*************************************************/
+
+_kernel_oserror * object_redraw(browser_data * b, WimpRedrawWindowBlock * r, HStream * token, int x, int y)
+{
+  int object  = object_get_token_object(b, token);
+  int plotted = 0;
+
+  // Here would go some code to check if this is, say, an image,
+  // and if so call the image redraw code instead. This would set
+  // the 'plotted' flag as appropriate - may need to extend image
+  // library API to say if it was about to draw a placeholder
+  // itself, so that plotted stays unset (assuming it isn't possible
+  // to easily generalise the image placeholder plotting).
+
+  if (!plotted)
+  {
+    /* Plot a placeholder */
+
+    BBox box;
+
+    object_get_object_size(b, object, &box);
+
+    box.xmin += x;
+    box.ymin += y;
+    box.xmax += x - box.xmin;
+    box.ymax += y - box.ymin;
+
+    box.xmin &= ~(wimpt_dx() - 1);
+    box.ymin &= ~(wimpt_dy() - 1);
+Printf("%d, %d\n",box.xmax,box.ymax);
+    if (box.xmax > 8 && box.ymax > 8)
+    {
+      /* xmin, ymin hold the bottom left hand corner coordinates, whilst */
+      /* xmax, ymax hold the width and height. The adjustments are to    */
+      /* account for the way the bbc_rectanglefill function works; e.g., */
+      /* to get a width of 4 OS units, ask for 3 (as it adds this to the */
+      /* x coordinate and treats it as an inclusive x coordinate max).   */
+      /* There are corrections to plot 2 OS units inside of the real     */
+      /* bounding box (looks better when images touch each other) and to */
+      /* get the darker sides of the 'slabbed in' box overlapping the    */
+      /* lighter sides by the right amount.                              */
+
+      redraw_set_colour(Redraw_Colour_AlmostWhite);
+      bbc_rectanglefill(box.xmin + 2,
+                        box.ymin + 2,
+                        box.xmax - 5,
+                        3);
+      bbc_rectanglefill(box.xmax + box.xmin - 6,
+                        box.ymin + 2,
+                        3,
+                        box.ymax - 5);
+
+      redraw_set_colour(Redraw_Colour_MidGrey);
+      bbc_rectanglefill(box.xmin + 2,
+                        box.ymax + box.ymin - 6,
+                        box.xmax - 7,
+                        3);
+      bbc_rectanglefill(box.xmin + 2,
+                        box.ymin + 4,
+                        3,
+                        box.ymax - 7);
+    }
+    else
+    {
+      if (box.xmax < 2) box.xmax = 2;
+      if (box.ymax < 2) box.ymax = 2;
+
+      redraw_set_colour(0);
+      bbc_rectangle(box.xmin,box.ymin,box.xmax - 1,box.ymax - 1);
+    }
+  }
+
+  return NULL;
+}
diff --git a/c/Redraw b/c/Redraw
index df161111f1568c1850bdec148b4ac3a302833c75..f85f6f9ed4acedc363a4d5e5ba48b36b742a77b2 100644
--- a/c/Redraw
+++ b/c/Redraw
@@ -47,6 +47,7 @@
 #include "Forms.h"
 #include "Frames.h"
 #include "Images.h"
+#include "Object.h"
 #include "Printing.h" /* Only for the PrintSplitFraction definition at present */
 #include "PrintStyle.h"
 #include "Reformat.h"
@@ -1294,7 +1295,7 @@ _kernel_oserror * redraw_draw_r(int toplevel, int xorg, int yorg, browser_data *
 
                 /* Deal with table tags */
 
-                if (tp->tag == TABLE && ISBODY(tp))
+                if (tp->tagno == TAG_TABLE)
                 {
                   int oh;
 
@@ -1828,14 +1829,32 @@ do_image: /* (This code is also used for form INPUT TYPE=IMAGE tags; see above)
 
                     /* Redraw the image itself */
 
-                    if (nocontent != tp)
-                    {
-                      e = image_redraw(b, r, d->cdata[cn].t, o + box.xmin, o + box.ymin);
-                      if (e) return e;
-                    }
+                    if (nocontent != tp) RetError(image_redraw(b, r, d->cdata[cn].t, o + box.xmin, o + box.ymin));
                   }
                 }
 
+                /* Plot an OBJECT, EMBED or APPLET tag */
+
+                else if (tp->tagno == TAG_OBJECT)
+                {
+                  BBox box;
+                  int  ox, oy, o;
+
+                  o = 0;
+
+                  convert_pair_to_os(x, y + base, &ox, &oy);
+
+                  if (!reformat_get_object_size(b, tp, &box))
+                  {
+                    ox -= box.xmin;
+
+                    // Can you have borders on Objects? If so, draw them here in
+                    // the same way as for images above.
+                  }
+
+                  if (nocontent != tp) RetError(object_redraw(b, r, d->cdata[cn].t, o + box.xmin, o + box.ymin));
+                }
+
                 /* Plot a horizontal rule */
 
                 else if (tp->style & HR)
@@ -2038,7 +2057,7 @@ do_image: /* (This code is also used for form INPUT TYPE=IMAGE tags; see above)
                            )
                            || ISUNDERLINE(tp)
                          )
-                         && !(tp->tag == TABLE && ISBODY(tp))
+                         && !(tp->tagno == TAG_TABLE)
                        )
                     {
                       /* Underline the item - set the colour, and start at the item's x coordinate... */
@@ -2070,7 +2089,7 @@ do_image: /* (This code is also used for form INPUT TYPE=IMAGE tags; see above)
                     /* body text font baseline (so SUB and SUP *will* have an      */
                     /* effect on the positioning).                                 */
 
-                    if (ISSTRIKE(tp) && !(tp->tag == TABLE && ISBODY(tp)))
+                    if (ISSTRIKE(tp) && !(tp->tagno == TAG_TABLE))
                     {
                       /* Underline the item - set the colour, and start at the item's x coordinate... */
 
diff --git a/c/Reformat b/c/Reformat
index e6562c92828f2cb0dcb32e01e135b43b1471f874..1e8c3606a7ab5ece3af06aae9966195461c41139 100644
--- a/c/Reformat
+++ b/c/Reformat
@@ -59,6 +59,7 @@
 #include "History.h"
 #include "Images.h"
 #include "Memory.h"
+#include "Object.h"
 #include "Redraw.h"
 #include "Tables.h"
 #include "Toolbars.h"
@@ -187,7 +188,7 @@ static int reformat_istext(HStream * tp)
 {
   return (
            ((tp->style) & (IMG | HR)) == 0 &&
-           !(tp->tag == TABLE)             &&
+           tp->tagno != TAG_TABLE          &&
            !
            (
              tp->tagno         == TAG_INPUT &&
@@ -229,7 +230,7 @@ static _kernel_oserror * reformat_token_width(reformat_width_data * w, unsigned
 
   /* Deal with tables */
 
-  if (w->tp->tag == TABLE && ISBODY(w->tp))
+  if (w->tp->tagno == TAG_TABLE)
   {
     reformat_cell * cellarray;
     table_stream  * table = (table_stream *) w->tp;
@@ -535,6 +536,20 @@ static _kernel_oserror * reformat_token_width(reformat_width_data * w, unsigned
       break;
     }
   }
+
+  /* Handle OBJECT, EMBED and APPLET tags */
+
+  else if (w->tp->tagno == TAG_OBJECT)
+  {
+    RetError(reformat_get_object_size(w->b, w->tp, &box));
+
+    w->width = box.xmax - box.xmin;
+
+    convert_to_points(w->width, &w->width);
+  }
+
+  /* Handle images */
+
   else if (w->tp->style & IMG)
   {
 
@@ -553,8 +568,7 @@ do_image: /* Used by switch statement above */
 
     /* Now get the size of the image for reformatting purposes */
 
-    e = reformat_get_image_size(w->b, w->tp, &box);
-    if (e) return e;
+    RetError(reformat_get_image_size(w->b, w->tp, &box));
 
     w->width = box.xmax - box.xmin;
 
@@ -618,7 +632,7 @@ do_image: /* Used by switch statement above */
 
       /* Get a font handle for rendering the token */
 
-      h = fm_find_token_font(NULL, w->tp);
+      h = fm_find_token_font(w->b, w->tp);
 
       /* If end > offset, the loop above must have gone through at least */
       /* one non-newline character in the string, or there was no string */
@@ -650,10 +664,6 @@ do_image: /* Used by switch statement above */
       /* to the bytes counter to ensure that the chunk includes it.          */
 
       if (w->data[end] && w->data[w->offset + w->bytes] == '\n') w->bytes++;
-
-      /* We don't need to keep the font claimed for just finding out a width */
-
-      fm_lose_font(NULL, h);
     }
   }
 
@@ -1203,6 +1213,7 @@ void reformat_stop_pending(browser_data * b)
 /*             relevant to the image;            */
 /*                                               */
 /*             A token address for the image;    */
+/*                                               */
 /*             Pointer to a BBox in which the    */
 /*             relevant coords are returned.     */
 /*                                               */
@@ -1266,6 +1277,81 @@ _kernel_oserror * reformat_get_image_size(browser_data * b, HStream * tp, BBox *
   return NULL;
 }
 
+/*************************************************/
+/* reformat_get_object_size()                    */
+/*                                               */
+/* Gets a BBox for a specified Object in OS      */
+/* coordinates relative to the font base line    */
+/* and left hand edge.                           */
+/*                                               */
+/* Parameters: Pointer to a browser_data struct  */
+/*             relevant to the Object            */
+/*                                               */
+/*             A token address for the Object;   */
+/*                                               */
+/*             Pointer to a BBox in which the    */
+/*             relevant coords are returned.     */
+/*                                               */
+/* Assumes:    Pointer to the BBox may not be    */
+/*             NULL.                             */
+/*************************************************/
+
+_kernel_oserror * reformat_get_object_size(browser_data * b, HStream * tp, BBox * box)
+{
+  _kernel_oserror * e;
+
+//  imgalign          align;
+
+  /* Get the Object size from the Object library */
+
+  RetError(object_get_token_object_size(b, tp, box));
+
+//  /* Deal with alignments */
+//
+//  if (tp->style & IMG) /* It'll either be an IMG or an INPUT TYPE=IMAGE item */
+//  {
+//    if      ((tp->type & TYPE_ALIGN_MASK) == TYPE_MIDDLE) align = imgalign_MIDDLE;
+//    else if ((tp->type & TYPE_ALIGN_MASK) == TYPE_TOP)    align = imgalign_TOP;
+//    else                                                  align = imgalign_NONE;
+//  }
+//  else align = HtmlINPUTalign(tp);
+//
+//  switch (align)
+//  {
+//    case imgalign_MIDDLE:
+//    {
+//      box->ymin -= box->ymax / 2;
+//      box->ymax /= 2;
+//    }
+//    break;
+//
+//    case imgalign_TOP:
+//    {
+//      box->ymin =- box->ymax;
+//      box->ymax = 0;
+//    }
+//    break;
+//  }
+//
+//  /* Deal with links - need to account for a border */
+//  /* of maxlen * 2 pixels width. ISLINK is defined  */
+//  /* in Fetch.h.                                    */
+//
+//  if (ISLINK(tp) && (tp->style & IMG))
+//  {
+//    int b;
+//
+//    b = tp->maxlen * 2;
+//
+//    box->xmax += b;
+//    box->ymax += b;
+//    box->xmin -= b;
+//    box->ymin -= b;
+//  }
+
+  return NULL;
+}
+
 /*************************************************/
 /* reformat_bullet_width()                       */
 /*                                               */
@@ -1457,13 +1543,24 @@ static _kernel_oserror * reformat_check_height(int toplevel, browser_data * b, r
   {
     BBox box;
 
-    e = reformat_get_image_size(b, tp, &box);
-    if (e) return e;
+    RetError(reformat_get_image_size(b, tp, &box));
 
     top +=  box.ymax;
     bot  = -box.ymin;
   }
 
+  /* Deal with OBJECT, APPLET and EMBED tags */
+
+  else if (tp->tagno == TAG_OBJECT)
+  {
+    BBox box;
+
+    RetError(reformat_get_object_size(b, tp, &box));
+
+    top += box.ymax;
+    bot  = -box.ymin;
+  }
+
   /* Size of a horizontal rule; the rule is plotted */
   /* centred vertically within its bounding box so  */
   /* there is no need to set both bot and top to    */
@@ -1527,7 +1624,7 @@ static _kernel_oserror * reformat_check_height(int toplevel, browser_data * b, r
     top += reformat_bullet_height(tp->indent);
   }
 
-  else if (tp->tag == TABLE && ISBODY(tp))
+  else if (tp->tagno == TAG_TABLE)
   {
     /* Don't do anything! h is already correct */
 
@@ -2272,7 +2369,7 @@ static int reformat_reformatter_r(unsigned int flags, browser_data * b, reformat
       /* It generally looks better if there's a line break for tables, */
       /* though this is strictly not necessary.                        */
 
-      if (!newline && (tpCurr->tag == TABLE && ISBODY(tpCurr))) newline = 1;
+      if (!newline && (tpCurr->tagno == TAG_TABLE)) newline = 1;
 
       /* If the difference between the current and last tags say we should */
       /* put in a line break, flag this in newline.                        */
@@ -2400,7 +2497,7 @@ static int reformat_reformatter_r(unsigned int flags, browser_data * b, reformat
         /* Adjust the line height for tables based on */
         /* the data from the above call               */
 
-        if (tpCurr->tag == TABLE && ISBODY(tpCurr))
+        if (tpCurr->tagno == TAG_TABLE)
         {
           if (!noalloc)
           {
@@ -2486,7 +2583,7 @@ static int reformat_reformatter_r(unsigned int flags, browser_data * b, reformat
             image_token_check_redrawable(b, tpCurr);
 
             #ifdef TRACE
-              if ((tl & (1u<<20)) && tpCurr->tag == TABLE && ISBODY(tpCurr)) Printf("reformat_reformatter_r: Added a table\n");
+              if ((tl & (1u<<20)) && tpCurr->tagno == TAG_TABLE) Printf("reformat_reformatter_r: Added a table\n");
             #endif
 
 //            if (d->ldata[d->nlines - 1].n == 1)
diff --git a/c/Tables b/c/Tables
index a8e15e13d2584b9ea3e35c6080b8f0be2ab931bc..decf0e54f72ebadd06b51b32e56cbc59ec962529 100644
--- a/c/Tables
+++ b/c/Tables
@@ -2028,7 +2028,7 @@ void tables_free_memory(int toplevel, browser_data * b, reformat_cell * d, int l
     {
       /* Does the chunk represent a table? */
 
-      if (d->cdata[c].t->tag == TABLE && ISBODY(d->cdata[c].t))
+      if (d->cdata[c].t->tagno == TAG_TABLE)
       {
         table_stream   * table     = (table_stream *) d->cdata[c].t;
         table_row      * row       = NULL;
@@ -2091,7 +2091,7 @@ void tables_free_memory(int toplevel, browser_data * b, reformat_cell * d, int l
         /* Closure of 'if (cellarray)' */
         }
 
-      /* Closure of 'if (d->cdata[c].t->tag == TABLE && ISBODY(d->cdata[c].t))' */
+      /* Closure of 'if (d->cdata[c].t->tagno == TAG_TABLE)' */
       }
 
     /* Closure of loop scanning this line's chunks */
diff --git a/c/TokenUtils b/c/TokenUtils
index 44ab68da84d1b1f83de4304c111c3b5834d203d0..8126514218ff33b46cc6cc2fb3d148f63740df80 100644
--- a/c/TokenUtils
+++ b/c/TokenUtils
@@ -307,7 +307,7 @@ static int tokenutils_line_range_r(int toplevel, browser_data * b, reformat_cell
         {
           /* Must recursively scan token lists for tables */
 
-          if (d->cdata[cc].t->tag == TABLE && ISBODY(d->cdata[cc].t))
+          if (d->cdata[cc].t->tagno == TAG_TABLE)
           {
             table_stream   * table     = (table_stream *) d->cdata[cc].t;
             table_row      * row       = NULL;
@@ -464,7 +464,7 @@ static int tokenutils_line_range_r(int toplevel, browser_data * b, reformat_cell
             /* Closure of 'if (cellarray)' */
             }
 
-          /* Closure of 'if (d->cdata[cc].t->tag == TABLE && ISBODY(d->cdata[cc].t))' */
+          /* Closure of 'if (d->cdata[cc].t->tagno == TAG_TABLE)' */
           }
 
           cc++;
diff --git a/c/Trace b/c/Trace
index 3547b99ec445b205d31f8ca66991fe068259c32e..b5b218bf1ddaaf2a3b8112f81d1fff6e5a209cc2 100644
--- a/c/Trace
+++ b/c/Trace
@@ -262,7 +262,7 @@ tdtbl_fo_err: /* If there's an error whilst writing to the file */
 
           /* Deal with tables */
 
-          if (token->tag == TABLE && ISBODY(token))
+          if (token->tagno == TAG_TABLE)
           {
             TrOut(file, depth, (file, "This token represents a table. As a table_stream struct:\n\n"));
 
@@ -534,7 +534,7 @@ tdtbs_fo_err: /* If there's an error whilst writing to the file */
 
       /* Deal with tables */
 
-      if (token->tag == TABLE && ISBODY(token))
+      if (token->tagno == TAG_TABLE)
       {
         TrOut(file, depth, (file, "This token represents a table. As a table_stream struct:\n\n"));
 
@@ -769,6 +769,7 @@ tdtbs_fo_err: /* If there's an error whilst writing to the file */
     TrOut(file, depth, (file, "size\t\t0x%x\n",         (int) token->size));
     TrOut(file, depth, (file, "maxlen\t\t0x%x\n",       (int) token->maxlen));
     TrOut(file, depth, (file, "rows\t\t0x%x\n",         (int) token->rows));
+    TrOut(file, depth, (file, "cols\t\t0x%x\n",         (int) token->cols));
     TrOut(file, depth, (file, "colour\t\t0x%06xxx\n",   (int) token->colour));
     TrOut(file, depth, (file, "fontsize\t%d\n\n",       (int) token->fontsize));
 
@@ -1386,10 +1387,7 @@ tdtbs_fo_err: /* If there's an error whilst writing to the file */
       /* This area has got fairly messy due to various table */
       /* implementations and so forth                        */
 
-      if (t->style & TR)             rems &= (~TR),         list = trace_add_description(list, "Deprecated <TR)");
-      if (t->style & TD)             rems &= (~TD),         list = trace_add_description(list, "Deprecated <TD>");
-      if (t->style & PCDATA)         rems &= (~TH),         list = trace_add_description(list, "<PCDATA>");
-      if (t->style & TABLE)          rems &= (~TABLE),      list = trace_add_description(list, "<TABLE>");
+      if (t->style & PCDATA)         rems &= (~PCDATA),     list = trace_add_description(list, "(PCDATA)");
 
       /* Heading items */
 
diff --git a/h/Global b/h/Global
index 63dcedb639551c6ba40e30c028a93b5dffa43422..517f84686fb225cd686a734fc22ac844f402ebad 100644
--- a/h/Global
+++ b/h/Global
@@ -97,9 +97,13 @@ typedef enum bs_fetch
 
 } bs_fetch;
 
+/* Defined elsewhere... (easy to work out from naming convention) */
+
 struct reformat_line;
 struct reformat_line_chunk;
 
+struct object_info;
+
 /* For tables, holds information required to format a specific table cell */
 
 typedef struct reformat_cell
@@ -259,7 +263,8 @@ typedef struct browser_data
   void                   * extradata;          /* Pointer to pointer to extra data for forms.                             */
   int                      nforms;             /* Counter for forms.                                                      */
                                                /*                                                                         */
-  void                   * odata;              /* Object data (for OBJECT, EMBED and APPLET).                             */
+  struct object_info     * odata;              /* Object data (for OBJECT, EMBED and APPLET).                             */
+  int                      nobjects;           /* Saves time on working out size of odata divided by structure size.      */
                                                /*                                                                         */
   reformat_cell          * cell;               /* Pointer to malloced reformat_cell holding redraw information.           */
                                                /*                                                                         */
diff --git a/h/Object b/h/Object
index 0e2ad6d3ed5363ae731365963e53cb92ef0367f1..3915c18c231c4512e4ce5a900df88efb50bc4e8d 100644
--- a/h/Object
+++ b/h/Object
@@ -22,11 +22,13 @@
 /* History: 05-Oct-97: Created.                    */
 /***************************************************/
 
+/* Structures */
+
 /* The object_info structure is used to hold information */
 /* about each object (or applet or embed) tag that a     */
 /* browser is dealing with.                              */
 
-typedef struct   object_info
+typedef struct object_info
 {
   unsigned int   browser_instance_handle;
 
@@ -34,4 +36,18 @@ typedef struct   object_info
   unsigned int   plugin_task_handle;
 
   HStream      * token;
+
+  int            width;
+  int            height;
+  int            units;
 }
+object_info;
+
+/* Function prototypes */
+
+_kernel_oserror * object_new_object            (browser_data * b, HStream * t);
+_kernel_oserror * object_discard               (browser_data * b);
+
+_kernel_oserror * object_get_token_object_size (browser_data * b, HStream * t, BBox * size);
+
+_kernel_oserror * object_redraw                (browser_data * b, WimpRedrawWindowBlock * r, HStream * token, int x, int y);
diff --git a/h/PlugIn b/h/PlugIn
index 46b0d3b2a44f8d5c57bc8ccbe51567f30cdb1c9f..caeda30faca8c71649e727b6838305497ef92e3b 100644
--- a/h/PlugIn
+++ b/h/PlugIn
@@ -77,4 +77,8 @@ typedef struct MPlugIn_Closed
 
   int          plugin_instance_handle;
   int          browser_instance_handle;
+
+  int          errnum;
+  char         errmess[sizeof(WimpMessage) - 36];
 }
+MPlugIn_Closed;
diff --git a/h/Reformat b/h/Reformat
index 5a10610ea13263db82df5516ddf3da0ba40c3f0b..66e650e12f93366dbf2ae36bb9d318d778e11d4c 100644
--- a/h/Reformat
+++ b/h/Reformat
@@ -105,6 +105,7 @@ int                   reformat_format_timer       (int eventcode, WimpPollBlock
 void                  reformat_stop_pending       (browser_data * b);
 
 _kernel_oserror     * reformat_get_image_size     (browser_data * b, HStream * tp, BBox * box);
+_kernel_oserror     * reformat_get_object_size    (browser_data * b, HStream * tp, BBox * box);
 int                   reformat_bullet_width       (int bullet);
 int                   reformat_bullet_height      (int bullet);
 int                   reformat_y_offset           (browser_data * b);