summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rw-r--r--render/box.c61
-rw-r--r--render/box.h43
-rw-r--r--render/box_construct.c462
-rw-r--r--render/html.c99
4 files changed, 299 insertions, 366 deletions
diff --git a/render/box.c b/render/box.c
index e1959bd8d..369fe90b9 100644
--- a/render/box.c
+++ b/render/box.c
@@ -75,6 +75,7 @@ struct box * box_create(struct css_style *style,
box->children = NULL;
box->last = NULL;
box->parent = NULL;
+ box->fallback = NULL;
box->float_children = NULL;
box->next_float = NULL;
box->col = NULL;
@@ -167,46 +168,11 @@ void box_free_box(struct box *box)
form_free_control(box->gadget);
}
- box_free_object_params(box->object_params);
-
talloc_free(box);
}
/**
- * Free an object parameter structure.
- *
- * \param op object parameter structure to free
- */
-
-void box_free_object_params(struct object_params *op)
-{
- struct plugin_params *a, *b;
-
- if (!op)
- return;
-
- free(op->data);
- free(op->type);
- free(op->codetype);
- free(op->codebase);
- free(op->classid);
- free(op->basehref);
-
- for (a = op->params; a; a = b) {
- b = a->next;
- free(a->name);
- free(a->value);
- free(a->type);
- free(a->valuetype);
- free(a);
- }
-
- free(op);
-}
-
-
-/**
* Find the absolute coordinates of a box.
*
* \param box the box to calculate coordinates of
@@ -434,7 +400,7 @@ struct box *box_find_by_id(struct box *box, const char *id)
void box_dump(struct box *box, unsigned int depth)
{
unsigned int i;
- struct box * c;
+ struct box *c, *prev;
for (i = 0; i != depth; i++)
fprintf(stderr, " ");
@@ -486,6 +452,27 @@ void box_dump(struct box *box, unsigned int depth)
fprintf(stderr, " next_float %p", box->next_float);
fprintf(stderr, "\n");
- for (c = box->children; c; c = c->next)
+ for (c = box->children; c->next; c = c->next)
+ ;
+ if (box->last != c)
+ fprintf(stderr, "warning: box->last %p (should be %p) "
+ "(box %p)\n", box->last, c, box);
+ for (prev = 0, c = box->children; c; prev = c, c = c->next) {
+ if (c->parent != box)
+ fprintf(stderr, "warning: box->parent %p (should be "
+ "%p) (box on next line)\n",
+ c->parent, box);
+ if (c->prev != prev)
+ fprintf(stderr, "warning: box->prev %p (should be "
+ "%p) (box on next line)\n",
+ c->prev, prev);
box_dump(c, depth + 1);
+ }
+ if (box->fallback) {
+ for (i = 0; i != depth; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr, "fallback:\n");
+ for (c = box->fallback; c; c = c->next)
+ box_dump(c, depth + 1);
+ }
}
diff --git a/render/box.h b/render/box.h
index 8f55459ac..fe67e8fb3 100644
--- a/render/box.h
+++ b/render/box.h
@@ -81,6 +81,8 @@
struct box;
struct column;
struct css_style;
+struct object_params;
+struct object_param;
/** Type of a struct box. */
@@ -92,27 +94,6 @@ typedef enum {
BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT
} box_type;
-/* parameters for <object> and related elements */
-struct object_params {
- char* data;
- char* type;
- char* codetype;
- char* codebase;
- char* classid;
- struct plugin_params* params;
- /* not a parameter but stored here for convenience */
- char* basehref;
-
-};
-
-struct plugin_params {
- char* name;
- char* value;
- char* type;
- char* valuetype;
- struct plugin_params* next;
-};
-
/** Node in box tree. All dimensions are in pixels. */
struct box {
/** Type of box. */
@@ -181,6 +162,7 @@ struct box {
struct box *children; /**< First child box, or 0. */
struct box *last; /**< Last child box, or 0. */
struct box *parent; /**< Parent box, or 0. */
+ struct box *fallback; /**< Fallback children for object, or 0. */
/** First float child box, or 0. Float boxes are in the tree twice, in
* this list for the block box which defines the area for floats, and
@@ -221,6 +203,25 @@ struct column {
int max;
};
+/** Parameters for <object> and similar elements. */
+struct object_params {
+ char *data;
+ char *type;
+ char *codetype;
+ char *codebase;
+ char *classid;
+ struct object_param *params;
+};
+
+/** Linked list of <object> parameters. */
+struct object_param {
+ char *name;
+ char *value;
+ char *type;
+ char *valuetype;
+ struct object_param *next;
+};
+
#define UNKNOWN_WIDTH INT_MAX
#define UNKNOWN_MAX_WIDTH INT_MAX
diff --git a/render/box_construct.c b/render/box_construct.c
index 21d7f5c99..3a7c311c9 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -105,7 +105,6 @@ static bool box_object(BOX_SPECIAL_PARAMS);
static bool box_embed(BOX_SPECIAL_PARAMS);
/*static bool box_applet(BOX_SPECIAL_PARAMS);*/
static bool box_iframe(BOX_SPECIAL_PARAMS);
-static bool plugin_decode(struct content* content, struct box* box);
static bool box_get_attribute(xmlNode *n, const char *attribute,
void *context, char **value);
static bool box_extract_link(const char *rel, const char *base, char **result);
@@ -957,6 +956,7 @@ bool box_a(BOX_SPECIAL_PARAMS)
box->href = talloc_strdup(content, url);
if (!box->href)
return false;
+ free(url);
}
}
@@ -974,14 +974,14 @@ bool box_a(BOX_SPECIAL_PARAMS)
bool box_image(BOX_SPECIAL_PARAMS)
{
- char *s, *url, *s1;
- xmlChar *s2;
- url_func_result res;
+ bool ok;
+ char *s, *url;
+ xmlChar *alt, *src;
/* handle alt text */
- if ((s2 = xmlGetProp(n, (const xmlChar *) "alt"))) {
- s = squash_whitespace(s2);
- xmlFree(s2);
+ if ((alt = xmlGetProp(n, (const xmlChar *) "alt"))) {
+ s = squash_whitespace(alt);
+ xmlFree(alt);
if (!s)
return false;
box->text = talloc_strdup(content, s);
@@ -997,33 +997,20 @@ bool box_image(BOX_SPECIAL_PARAMS)
if (box->usemap && box->usemap[0] == '#')
box->usemap++;
- /* img without src is an error */
- if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "src")))
+ /* get image URL */
+ if (!(src = xmlGetProp(n, (const xmlChar *) "src")))
return true;
-
- /* remove leading and trailing whitespace */
- s1 = strip(s);
- res = url_join(s1, content->data.html.base_url, &url);
- xmlFree(s);
- if (res == URL_FUNC_NOMEM)
+ if (!box_extract_link((char *) src, content->data.html.base_url, &url))
return false;
- else if (res == URL_FUNC_FAILED)
- return true;
-
- if (strcmp(url, content->data.html.base_url) == 0)
- /* if url is equivalent to the parent's url,
- * we've got infinite inclusion: ignore */
+ xmlFree(src);
+ if (!url)
return true;
/* start fetch */
- if (!html_fetch_object(content, url, box, image_types,
- content->available_width, 1000, false)) {
- free(url);
- return false;
- }
+ ok = html_fetch_object(content, url, box, image_types,
+ content->available_width, 1000, false);
free(url);
-
- return true;
+ return ok;
}
@@ -1033,93 +1020,120 @@ bool box_image(BOX_SPECIAL_PARAMS)
bool box_object(BOX_SPECIAL_PARAMS)
{
- struct object_params *po;
- struct plugin_params *pp = NULL;
+ struct object_params *params;
+ struct object_param *param;
+ xmlChar *codebase, *classid, *data;
xmlNode *c;
-
- po = talloc(content, struct object_params);
- if (!po)
- return false;
- po->data = 0;
- po->type = 0;
- po->codetype = 0;
- po->codebase = 0;
- po->classid = 0;
- po->params = 0;
- po->basehref = 0;
-
- if (!box_get_attribute(n, "data", content, &po->data))
- return false;
+ struct box *inline_container = 0;
if (!box_get_attribute(n, "usemap", content, &box->usemap))
return false;
if (box->usemap && box->usemap[0] == '#')
box->usemap++;
- if (!box_get_attribute(n, "type", content, &po->type))
- return false;
- if (!box_get_attribute(n, "codetype", content, &po->codetype))
+ params = talloc(content, struct object_params);
+ if (!params)
return false;
- if (!box_get_attribute(n, "codebase", content, &po->codebase))
+ params->data = 0;
+ params->type = 0;
+ params->codetype = 0;
+ params->codebase = 0;
+ params->classid = 0;
+ params->params = 0;
+
+ /* codebase, classid, and data are URLs (codebase is the base for the
+ * other two) */
+ if ((codebase = xmlGetProp(n, (const xmlChar *) "codebase"))) {
+ if (!box_extract_link((char *) codebase,
+ content->data.html.base_url, &params->codebase))
+ return false;
+ xmlFree(codebase);
+ }
+ if (!params->codebase)
+ params->codebase = content->data.html.base_url;
+
+ if ((classid = xmlGetProp(n, (const xmlChar *) "codebase"))) {
+ if (!box_extract_link((char *) classid, params->codebase,
+ &params->classid))
+ return false;
+ xmlFree(classid);
+ }
+
+ if ((data = xmlGetProp(n, (const xmlChar *) "data"))) {
+ if (!box_extract_link((char *) data, params->codebase,
+ &params->data))
+ return false;
+ xmlFree(data);
+ }
+ if (!params->data)
+ /* objects without data are ignored */
+ return true;
+
+ /* codetype and type are MIME types */
+ if (!box_get_attribute(n, "codetype", params, &params->codetype))
return false;
- if (!box_get_attribute(n, "classid", content, &po->classid))
+ if (!box_get_attribute(n, "type", params, &params->type))
return false;
+ if (params->type && content_lookup(params->type) == CONTENT_OTHER)
+ /* can't handle this MIME type */
+ return true;
- /* parameters
- * parameter data is stored in a singly linked list.
- * po->params points to the head of the list.
- * new parameters are added to the head of the list.
- */
+ /* add parameters to linked list */
for (c = n->children; c; c = c->next) {
if (c->type != XML_ELEMENT_NODE)
continue;
-
if (strcmp((const char *) c->name, "param") != 0)
- /* The first non-param child is the start
- * of the alt html. Therefore, we should
- * break out of this loop.
- */
+ /* The first non-param child is the start of the alt
+ * html. Therefore, we should break out of this loop. */
break;
- pp = talloc(content, struct plugin_params);
- if (!pp)
+ param = talloc(params, struct object_param);
+ if (!param)
return false;
- pp->name = 0;
- pp->value = 0;
- pp->type = 0;
- pp->valuetype = 0;
- pp->next = 0;
+ param->name = 0;
+ param->value = 0;
+ param->type = 0;
+ param->valuetype = 0;
+ param->next = 0;
- if (!box_get_attribute(c, "name", content, &pp->name))
+ if (!box_get_attribute(c, "name", param, &param->name))
return false;
- if (!box_get_attribute(c, "value", content, &pp->value))
+ if (!box_get_attribute(c, "value", param, &param->value))
return false;
- if (!box_get_attribute(c, "type", content, &pp->type))
+ if (!box_get_attribute(c, "type", param, &param->type))
return false;
- if (!box_get_attribute(c, "valuetype", content, &pp->valuetype))
+ if (!box_get_attribute(c, "valuetype", param,
+ &param->valuetype))
return false;
- if (!pp->valuetype) {
- pp->valuetype = talloc_strdup(content, "data");
- if (!pp->valuetype)
- return false;
- }
+ if (!param->valuetype)
+ param->valuetype = "data";
- pp->next = po->params;
- po->params = pp;
+ param->next = params->params;
+ params->params = param;
}
- box->object_params = po;
+ box->object_params = params;
- /* start fetch */
- if (!plugin_decode(content, box))
- *convert_children = true;
+ /* start fetch (MIME type is ok or not specified) */
+ if (!html_fetch_object(content, params->data, box, 0,
+ content->available_width, 1000, false))
+ return false;
+
+ /* convert children and place into fallback */
+ for (c = n->children; c; c = c->next) {
+ if (!convert_xml_to_box(c, content, box->style, box,
+ &inline_container, 0, 0))
+ return false;
+ }
+ box->fallback = box->children;
+ box->children = box->last = 0;
+ *convert_children = false;
return true;
}
-#if 0
-/**
+#if 0 /**
* "Java applet" [13.4].
*
* \todo This needs reworking to be compliant to the spec
@@ -1131,7 +1145,7 @@ struct box_result box_applet(xmlNode *n, struct box_status *status,
{
struct box *box;
struct object_params *po;
- struct plugin_params *pp = NULL;
+ struct object_param *pp = NULL;
char *s;
xmlNode *c;
@@ -1183,7 +1197,7 @@ struct box_result box_applet(xmlNode *n, struct box_status *status,
continue;
if (strcmp((const char *) c->name, "param") == 0) {
- pp = calloc(1, sizeof(struct plugin_params));
+ pp = calloc(1, sizeof(struct object_param));
if (!pp)
goto no_memory;
@@ -1459,34 +1473,23 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
bool box_iframe(BOX_SPECIAL_PARAMS)
{
- struct object_params *po;
- char *s;
+ bool ok;
+ char *url;
+ xmlChar *src;
- po = talloc(content, struct object_params);
- if (!po)
+ /* get frame URL */
+ if (!(src = xmlGetProp(n, (const xmlChar *) "src")))
+ return true;
+ if (!box_extract_link((char *) src, content->data.html.base_url, &url))
return false;
- po->data = 0;
- po->type = 0;
- po->codetype = 0;
- po->codebase = 0;
- po->classid = 0;
- po->params = 0;
- po->basehref = 0;
-
- /* iframe src */
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src"))) {
- po->data = talloc_strdup(content, s);
- xmlFree(s);
- if (!po->data)
- return false;
- }
-
- box->object_params = po;
+ if (!url)
+ return true;
/* start fetch */
- plugin_decode(content, box);
-
- return true;
+ ok = html_fetch_object(content, url, box, 0,
+ content->available_width, 1000, false);
+ free(url);
+ return ok;
}
@@ -2054,66 +2057,60 @@ bool box_textarea(BOX_SPECIAL_PARAMS)
bool box_embed(BOX_SPECIAL_PARAMS)
{
- struct object_params *po;
- struct plugin_params *pp = NULL;
- char *s;
+ struct object_params *params;
+ struct object_param *param;
+ xmlChar *src;
xmlAttr *a;
- po = talloc(content, struct object_params);
- if (!po)
+ params = talloc(content, struct object_params);
+ if (!params)
return false;
- po->data = 0;
- po->type = 0;
- po->codetype = 0;
- po->codebase = 0;
- po->classid = 0;
- po->params = 0;
- po->basehref = 0;
-
- /* embed src */
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src")) != NULL) {
- LOG(("embed '%s'", s));
- po->data = talloc_strdup(content, s);
- xmlFree(s);
- if (!po->data)
- return false;
- }
+ params->data = 0;
+ params->type = 0;
+ params->codetype = 0;
+ params->codebase = 0;
+ params->classid = 0;
+ params->params = 0;
+
+ /* src is a URL */
+ if (!(src = xmlGetProp(n, (const xmlChar *) "src")))
+ return true;
+ if (!box_extract_link((char *) src, content->data.html.base_url,
+ &params->data))
+ return false;
+ xmlFree(src);
+ if (!params->data)
+ return true;
- /**
- * we munge all other attributes into a plugin_parameter structure
- */
+ /* add attributes as parameters to linked list */
for (a = n->properties; a; a = a->next) {
- pp = talloc(content, struct plugin_params);
- if (!pp)
+ if (strcasecmp((const char *) a->name, "src") == 0)
+ continue;
+ if (!a->children || !a->children->content)
+ continue;
+
+ param = talloc(content, struct object_param);
+ if (!param)
+ return false;
+ param->name = talloc_strdup(content, (const char *) a->name);
+ param->value = talloc_strdup(content,
+ (char *) a->children->content);
+ param->type = 0;
+ param->valuetype = "data";
+ param->next = 0;
+
+ if (!param->name || !param->value)
return false;
- pp->name = 0;
- pp->value = 0;
- pp->type = 0;
- pp->valuetype = 0;
- pp->next = 0;
-
- if (strcasecmp((const char *) a->name, "src") != 0 &&
- a->children && a->children->content) {
- pp->name = talloc_strdup(content,
- (const char *) a->name);
- pp->value = talloc_strdup(content,
- (char *) a->children->content);
- pp->valuetype = talloc_strdup(content, "data");
- if (!pp->name || !pp->value || !pp->valuetype)
- return false;
- pp->next = po->params;
- po->params = pp;
- }
- }
+ param->next = params->params;
+ params->params = param;
+ }
- box->object_params = po;
+ box->object_params = params;
/* start fetch */
- /* embeds have no content, so we don't care if this returns false */
- plugin_decode(content, box);
-
- return true;
+ return html_fetch_object(content, params->data, box, 0,
+ content->available_width, 1000, false);
}
/**
@@ -2122,153 +2119,6 @@ bool box_embed(BOX_SPECIAL_PARAMS)
/**
- * plugin_decode
- * This function checks that the contents of the plugin_object struct
- * are valid. If they are, it initiates the fetch process. If they are
- * not, it exits, leaving the box structure as it was on entry. This is
- * necessary as there are multiple ways of declaring an object's attributes.
- *
- * Returns false if the object could not be handled.
- */
-bool plugin_decode(struct content *content, struct box *box)
-{
- char *codebase, *url = NULL;
- struct object_params *po;
- struct plugin_params *pp;
- url_func_result res;
-
- assert(content && box);
-
- po = box->object_params;
-
- /* Check if the codebase attribute is defined.
- * If it is not, set it to the codebase of the current document.
- */
- if (po->codebase == 0)
- res = url_join("./", content->data.html.base_url,
- &codebase);
- else
- res = url_join(po->codebase, content->data.html.base_url,
- &codebase);
-
- if (res != URL_FUNC_OK)
- return false;
-
- /* free pre-existing codebase */
- if (po->codebase)
- talloc_free(po->codebase);
-
- po->codebase = talloc_strdup(content, codebase);
- if (!po->codebase) {
- free(codebase);
- return false;
- }
-
- /* no longer need this */
- free(codebase);
-
- /* Set basehref */
- po->basehref = talloc_strdup(content, content->data.html.base_url);
- if (!po->basehref)
- return false;
-
- if (po->data == 0 && po->classid == 0)
- /* no data => ignore this object */
- return false;
-
- if (po->data == 0 && po->classid != 0) {
- /* just classid specified */
- if (strncasecmp(po->classid, "clsid:", 6) == 0) {
- if (strcasecmp(po->classid, "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000") == 0) {
- /* Flash */
- for (pp = po->params;
- pp != 0 &&
- strcasecmp(pp->name, "movie") != 0;
- pp = pp->next)
- /* no body */;
- if (pp == 0)
- return false;
- res = url_join(pp->value, po->basehref, &url);
- if (res != URL_FUNC_OK)
- return false;
- /* munge the codebase */
- res = url_join("./",
- content->data.html.base_url,
- &codebase);
- if (res != URL_FUNC_OK) {
- free(url);
- return false;
- }
- if (po->codebase)
- talloc_free(po->codebase);
- po->codebase = talloc_strdup(content,
- codebase);
- free(codebase);
- if (!po->codebase) {
- free(url);
- return false;
- }
- }
- else {
- LOG(("ActiveX object"));
- return false;
- }
- } else {
- res = url_join(po->classid, po->codebase, &url);
- if (res != URL_FUNC_OK)
- return false;
-
-#if 0
- /* jmb - I'm not convinced by this */
- /* The java plugin doesn't need the .class extension
- * so we strip it.
- */
- if (strcasecmp(&po->classid[strlen(po->classid)-6],
- ".class") == 0)
- po->classid[strlen(po->classid)-6] = 0;
-#endif
- }
- } else {
- /* just data (or both) specified - data takes precedence */
- res = url_join(po->data, po->codebase, &url);
- if (res != URL_FUNC_OK)
- return false;
- }
-
- /* Check if the declared mime type is understandable.
- * Checks type and codetype attributes.
- */
- if (po->type != 0 && content_lookup(po->type) == CONTENT_OTHER)
- goto no_handler;
- if (po->codetype != 0 &&
- content_lookup(po->codetype) == CONTENT_OTHER)
- goto no_handler;
-
- /* Ensure that the object to be included isn't this document */
- if (strcasecmp(url, content->data.html.base_url) == 0)
- goto no_handler;
-
- /* If we've got to here, the object declaration has provided us with
- * enough data to enable us to have a go at downloading and
- * displaying it.
- *
- * We may still find that the object has a MIME type that we can't
- * handle when we fetch it (if the type was not specified or is
- * different to that given in the attributes).
- */
- if (!html_fetch_object(content, url, box, 0, 1000, 1000, false))
- goto no_handler;
- free(url);
-
- return true;
-
-no_handler:
- free(url);
- return false;
-}
-
-
-/**
* Get the value of an XML element's attribute.
*
* \param n xmlNode, of type XML_ELEMENT_NODE
diff --git a/render/html.c b/render/html.c
index 506904f6f..39d4541fe 100644
--- a/render/html.c
+++ b/render/html.c
@@ -45,6 +45,8 @@ static void html_object_callback(content_msg msg, struct content *object,
void *p1, void *p2, union content_msg_data data);
static void html_object_done(struct box *box, struct content *object,
bool background);
+static void html_object_failed(struct box *box, struct content *content,
+ bool background);
static bool html_object_type_permitted(const content_type type,
const content_type *permitted_types);
@@ -799,7 +801,10 @@ void html_object_callback(content_msg msg, struct content *object,
content_add_error(c, "?", 0);
content_set_status(c, messages_get("BadObject"));
content_broadcast(c, CONTENT_MSG_STATUS, data);
- content_remove_user(object, html_object_callback, c, (void*)i);
+ content_remove_user(object, html_object_callback, c,
+ (void *) i);
+ html_object_failed(box, c,
+ c->data.html.object[i].background);
break;
case CONTENT_MSG_READY:
@@ -815,7 +820,8 @@ void html_object_callback(content_msg msg, struct content *object,
break;
case CONTENT_MSG_DONE:
- html_object_done(box, object, c->data.html.object[i].background);
+ html_object_done(box, object,
+ c->data.html.object[i].background);
c->active--;
break;
@@ -826,6 +832,8 @@ void html_object_callback(content_msg msg, struct content *object,
content_set_status(c, messages_get("ObjError"),
data.error);
content_broadcast(c, CONTENT_MSG_STATUS, data);
+ html_object_failed(box, c,
+ c->data.html.object[i].background);
break;
case CONTENT_MSG_STATUS:
@@ -952,6 +960,93 @@ void html_object_done(struct box *box, struct content *object,
/**
+ * Handle object fetching or loading failure.
+ *
+ * \param box box containing object which failed to load
+ * \param content document of type CONTENT_HTML
+ * \param background the object was the background image for the box
+ *
+ * Any fallback content for the object is made visible.
+ */
+
+void html_object_failed(struct box *box, struct content *content,
+ bool background)
+{
+ struct box *b, *ic;
+
+ if (background)
+ return;
+ if (!box->fallback)
+ return;
+
+ /* make fallback boxes into children or siblings, as appropriate */
+ if (box->type != BOX_INLINE) {
+ /* easy case: fallbacks become children */
+ assert(box->type == BOX_BLOCK ||
+ box->type == BOX_TABLE_CELL ||
+ box->type == BOX_INLINE_BLOCK);
+ box->children = box->fallback;
+ box->last = box->children;
+ while (box->last->next)
+ box->last = box->last->next;
+ box->fallback = 0;
+ box_normalise_block(box, content);
+ } else {
+ assert(box->parent->type == BOX_INLINE_CONTAINER);
+ if (box->fallback->type == BOX_INLINE_CONTAINER &&
+ !box->fallback->next) {
+ /* the fallback is a single inline container: splice
+ * it into this inline container */
+ for (b = box->fallback->children; b; b = b->next)
+ b->parent = box->parent;
+ box->fallback->last->next = box->next;
+ if (!box->next)
+ box->parent->last = box->fallback->last;
+ box->next = box->fallback->children;
+ box->next->prev = box;
+ box->fallback = 0;
+ } else {
+ if (box->next) {
+ /* split this inline container into two inline
+ * containers */
+ ic = box_create(0, 0, 0, 0, content);
+ if (!ic) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+ ic->type = BOX_INLINE_CONTAINER;
+ box_insert_sibling(box->parent, ic);
+ ic->children = box->next;
+ ic->last = box->parent->last;
+ ic->children->prev = 0;
+ box->next = 0;
+ box->parent->last = box;
+ for (b = ic->children; b; b = b->next)
+ b->parent = ic;
+ }
+ /* insert the fallback after the parent */
+ for (b = box->fallback; b->next; b = b->next)
+ b->parent = box->parent->parent;
+ b->parent = box->parent->parent;
+ /* [b is the last fallback box] */
+ b->next = box->parent->next;
+ if (b->next)
+ b->next->prev = b;
+ box->parent->next = box->fallback;
+ box->fallback->prev = box->parent;
+ box->fallback = 0;
+ box_normalise_block(box->parent->parent, content);
+ }
+ }
+
+ /* invalidate parent min, max widths */
+ for (b = box->parent; b; b = b->parent)
+ b->max_width = UNKNOWN_MAX_WIDTH;
+ box->width = UNKNOWN_WIDTH;
+}
+
+
+/**
* Check if a type is in a list.
*
* \param type the content_type to search for