Restartable box tree constructor. Yield between elements.

svn path=/trunk/netsurf/; revision=12912
This commit is contained in:
John Mark Bell 2011-09-29 19:15:54 +00:00
parent f97d7425a8
commit 74395ac888
8 changed files with 855 additions and 546 deletions

View File

@ -109,8 +109,8 @@ free_box_style(struct box *b)
*/
struct box * box_create(css_select_results *styles, css_computed_style *style,
bool style_owned, char *href, const char *target, char *title,
char *id, void *context)
bool style_owned, const char *href, const char *target,
const char *title, char *id, void *context)
{
unsigned int i;
struct box *box;

View File

@ -104,6 +104,7 @@ struct html_content;
#define UNKNOWN_WIDTH INT_MAX
#define UNKNOWN_MAX_WIDTH INT_MAX
typedef void (*box_construct_complete_cb)(struct html_content *c, bool success);
/** Type of a struct box. */
typedef enum {
@ -128,7 +129,8 @@ typedef enum {
MAKE_HEIGHT = 1 << 7, /* box causes its own height */
NEED_MIN = 1 << 8, /* minimum width is required for layout */
REPLACE_DIM = 1 << 9, /* replaced element has given dimensions */
IFRAME = 1 << 10 /* box contains an iframe */
IFRAME = 1 << 10, /* box contains an iframe */
CONVERT_CHILDREN = 1 << 11 /* wanted children converting */
} box_flags;
/* Sides of a box */
@ -211,9 +213,9 @@ struct box {
/** Width of space after current text (depends on font and size). */
int space;
char *href; /**< Link, or 0. */
const char *href; /**< Link, or 0. */
const char *target; /**< Link target, or 0. */
char *title; /**< Title, or 0. */
const char *title; /**< Title, or 0. */
unsigned int columns; /**< Number of columns for TABLE / TABLE_CELL. */
unsigned int rows; /**< Number of rows for TABLE only. */
@ -310,8 +312,8 @@ extern const char *TARGET_BLANK;
void *box_style_alloc(void *ptr, size_t len, void *pw);
struct box * box_create(css_select_results *styles, css_computed_style *style,
bool style_owned, char *href, const char *target, char *title,
char *id, void *context);
bool style_owned, const char *href, const char *target,
const char *title, char *id, void *context);
void box_add_child(struct box *parent, struct box *child);
void box_insert_sibling(struct box *box, struct box *new_box);
void box_unlink_and_free(struct box *box);
@ -336,7 +338,8 @@ bool box_handle_scrollbars(struct content *c, struct box *box,
bool box_vscrollbar_present(const struct box *box);
bool box_hscrollbar_present(const struct box *box);
bool xml_to_box(xmlNode *n, struct html_content *c);
bool xml_to_box(xmlNode *n, struct html_content *c,
box_construct_complete_cb cb);
bool box_normalise_block(struct box *block, struct html_content *c);

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,7 @@ static nserror html_clone(const struct content *old, struct content **newc);
static content_type html_content_type(void);
static void html_finish_conversion(html_content *c);
static void html_box_convert_done(html_content *c, bool success);
static nserror html_convert_css_callback(hlcache_handle *css,
const hlcache_event *event, void *pw);
static bool html_meta_refresh(html_content *c, xmlNode *head);
@ -91,6 +92,7 @@ static bool html_find_stylesheets(html_content *c, xmlNode *html);
static bool html_process_style_element(html_content *c, unsigned int *index,
xmlNode *style);
static void html_inline_style_done(struct content_css_data *css, void *pw);
static bool html_fetch_objects(html_content *c);
static bool html_replace_object(struct content_html_object *object,
const char *url);
static nserror html_object_callback(hlcache_handle *object,
@ -632,16 +634,46 @@ void html_finish_conversion(html_content *c)
}
/* convert xml tree to box tree */
LOG(("XML to box"));
LOG(("XML to box (%p)", c));
content_set_status(&c->base, messages_get("Processing"));
content_broadcast(&c->base, CONTENT_MSG_STATUS, msg_data);
if (xml_to_box(html, c) == false) {
if (xml_to_box(html, c, html_box_convert_done) == false) {
html_destroy_objects(c);
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
content_set_error(&c->base);
return;
}
}
/**
* Perform post-box-creation conversion of a document
*
* \param c HTML content to complete conversion of
* \param success Whether box tree construction was successful
*/
void html_box_convert_done(html_content *c, bool success)
{
union content_msg_data msg_data;
xmlNode *html;
LOG(("Done XML to box (%p)", c));
/* Clean up and report error if unsuccessful or aborted */
if (success == false || c->aborted) {
html_destroy_objects(c);
if (success == false)
msg_data.error = messages_get("NoMemory");
else
msg_data.error = messages_get("Stopped");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
content_set_error(&c->base);
return;
}
html = xmlDocGetRootElement(c->document);
assert(html != NULL);
#if ALWAYS_DUMP_BOX
box_dump(stderr, c->layout->children, 0);
#endif
@ -665,6 +697,9 @@ void html_finish_conversion(html_content *c)
binding_destroy_tree(c->parser_binding);
c->parser_binding = NULL;
/* Spawn object fetches */
html_fetch_objects(c);
content_set_ready(&c->base);
if (c->base.active == 0)
@ -1334,7 +1369,7 @@ nserror html_convert_css_callback(hlcache_handle *css,
/**
* Start a fetch for an object required by a page.
* Queue a fetch for an object required by a page.
*
* \param c content of type CONTENT_HTML
* \param url URL of object to fetch (copied)
@ -1352,18 +1387,13 @@ bool html_fetch_object(html_content *c, const char *url, struct box *box,
bool background)
{
struct content_html_object *object;
hlcache_child_context child;
char *url2;
url_func_result res;
nserror error;
/* If we've already been aborted, don't bother attempting the fetch */
if (c->aborted)
return true;
child.charset = c->encoding;
child.quirks = c->base.quirks;
/* Normalize the URL */
res = url_normalize(url, &url2);
if (res != URL_FUNC_OK) {
@ -1383,28 +1413,43 @@ bool html_fetch_object(html_content *c, const char *url, struct box *box,
object->box = box;
object->permitted_types = permitted_types;
object->background = background;
object->url = url2;
error = hlcache_handle_retrieve(url2, HLCACHE_RETRIEVE_SNIFF_TYPE,
content__get_url(&c->base), NULL,
html_object_callback, object, &child,
permitted_types, &object->content);
/* No longer need normalized url */
free(url2);
if (error != NSERROR_OK) {
talloc_free(object);
return error != NSERROR_NOMEM;
}
/* add to object list */
object->next = c->object_list;
c->object_list = object;
c->num_objects++;
c->base.active++;
return error != NSERROR_NOMEM;
return true;
}
/**
* Start fetches for objects requested by a page
*
* \param c Content object
* \return true on success, false otherwise
*/
bool html_fetch_objects(html_content *c)
{
struct content_html_object *object;
hlcache_child_context child;
nserror error;
child.charset = c->encoding;
child.quirks = c->base.quirks;
for (object = c->object_list; object != NULL; object = object->next) {
error = hlcache_handle_retrieve(object->url,
HLCACHE_RETRIEVE_SNIFF_TYPE,
content__get_url(&c->base), NULL,
html_object_callback, object, &child,
object->permitted_types, &object->content);
if (error == NSERROR_OK)
c->base.active++;
}
return c->base.active == c->num_objects;
}
@ -1857,7 +1902,7 @@ void html_destroy(struct content *c)
binding_destroy_tree(html->parser_binding);
if (html->document != NULL)
xmlFreeDoc(html->document);
binding_destroy_document(html->document);
/* Free base target */
if (html->base_target != NULL) {
@ -1916,6 +1961,8 @@ void html_destroy_objects(html_content *html)
hlcache_handle_release(victim->content);
}
free(victim->url);
html->object_list = victim->next;
talloc_free(victim);
}

View File

@ -78,6 +78,7 @@ struct content_html_object {
struct content *parent; /**< Parent document */
struct content_html_object *next; /**< Next in chain */
char *url; /**< URL of content */
struct hlcache_handle *content; /**< Content, or 0. */
struct box *box; /**< Node in box tree containing it. */
/** Bitmap of acceptable content types */

View File

@ -167,7 +167,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
{
html_content *html = (html_content *) c;
enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
char *title = 0;
const char *title = 0;
const char *url = 0;
const char *target = 0;
char status_buffer[200];

View File

@ -34,6 +34,15 @@
#include "utils/log.h"
#include "utils/talloc.h"
/**
* Private data attached to each DOM node
*/
typedef struct hubbub_private {
binding_private base;
uint32_t refcnt;
} hubbub_private;
typedef struct hubbub_ctx {
hubbub_parser *parser;
@ -69,6 +78,7 @@ static struct {
{ "xmlns", "http://www.w3.org/2000/xmlns/" }
};
static hubbub_private *create_private(uint32_t refcnt);
static inline char *c_string_from_hubbub_string(hubbub_ctx *ctx,
const hubbub_string *str);
static void create_namespaces(hubbub_ctx *ctx, xmlNode *root);
@ -168,7 +178,13 @@ binding_error binding_create_tree(void *arena, const char *charset, void **ctx)
free(c);
return BINDING_NOMEM;
}
c->document->_private = (void *) 0;
c->document->_private = create_private(0);
if (c->document->_private == NULL) {
xmlFreeDoc(c->document);
hubbub_parser_destroy(c->parser);
free(c);
return BINDING_NOMEM;
}
for (i = 0; i < sizeof(c->namespaces) / sizeof(c->namespaces[0]); i++) {
c->namespaces[i] = NULL;
@ -200,7 +216,7 @@ binding_error binding_destroy_tree(void *ctx)
hubbub_parser_destroy(c->parser);
if (c->owns_doc)
xmlFreeDoc(c->document);
binding_destroy_document(c->document);
c->parser = NULL;
c->encoding = NULL;
@ -290,8 +306,43 @@ struct form_control *binding_get_control_for_node(void *ctx, xmlNodePtr node)
return ctl;
}
void binding_destroy_document(xmlDocPtr doc)
{
xmlNode *n = (xmlNode *) doc;
while (n != NULL) {
free(n->_private);
if (n->children != NULL) {
n = n->children;
} else if (n->next != NULL) {
n = n->next;
} else {
while (n->parent != NULL && n->parent->next == NULL)
n = n->parent;
if (n->parent != NULL)
n = n->parent->next;
else
n = NULL;
}
}
xmlFreeDoc(doc);
}
/*****************************************************************************/
hubbub_private *create_private(uint32_t refcnt)
{
hubbub_private *pvt = calloc(1, sizeof(*pvt));
if (pvt != NULL)
pvt->refcnt = refcnt;
return pvt;
}
char *c_string_from_hubbub_string(hubbub_ctx *ctx, const hubbub_string *str)
{
return strndup((const char *) str->ptr, (int) str->len);
@ -328,7 +379,12 @@ hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result)
free(content);
return HUBBUB_NOMEM;
}
n->_private = (void *) (uintptr_t) 1;
n->_private = create_private(1);
if (n->_private == NULL) {
xmlFreeNode(n);
free(content);
return HUBBUB_NOMEM;
}
free(content);
@ -374,7 +430,14 @@ hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype,
free(name);
return HUBBUB_NOMEM;
}
n->_private = (void *) (uintptr_t) 1;
n->_private = create_private(1);
if (n->_private == NULL) {
xmlFreeDtd(n);
free(system);
free(public);
free(name);
return HUBBUB_NOMEM;
}
*result = (void *) n;
@ -413,10 +476,16 @@ hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result)
free(name);
return HUBBUB_NOMEM;
}
n->_private = (void *) (uintptr_t) 1;
n->_private = create_private(1);
if (n->_private == NULL) {
xmlFreeNode(n);
free(name);
return HUBBUB_NOMEM;
}
if (tag->n_attributes > 0 && add_attributes(ctx, (void *) n,
tag->attributes, tag->n_attributes) != HUBBUB_OK) {
free(n->_private);
xmlFreeNode(n);
free(name);
return HUBBUB_NOMEM;
@ -427,6 +496,7 @@ hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result)
/* Memory exhaustion */
if (form == NULL) {
free(n->_private);
xmlFreeNode(n);
free(name);
return HUBBUB_NOMEM;
@ -453,7 +523,11 @@ hubbub_error create_text(void *ctx, const hubbub_string *data, void **result)
if (n == NULL) {
return HUBBUB_NOMEM;
}
n->_private = (void *) (uintptr_t) 1;
n->_private = create_private(1);
if (n->_private == NULL) {
xmlFreeNode(n);
return HUBBUB_NOMEM;
}
*result = (void *) n;
@ -463,17 +537,18 @@ hubbub_error create_text(void *ctx, const hubbub_string *data, void **result)
hubbub_error ref_node(void *ctx, void *node)
{
hubbub_ctx *c = (hubbub_ctx *) ctx;
hubbub_private *pvt;
if (node == c->document) {
xmlDoc *n = (xmlDoc *) node;
uintptr_t count = (uintptr_t) n->_private;
pvt = n->_private;
n->_private = (void *) (++count);
pvt->refcnt++;
} else {
xmlNode *n = (xmlNode *) node;
uintptr_t count = (uintptr_t) n->_private;
pvt = n->_private;
n->_private = (void *) (++count);
pvt->refcnt++;
}
return HUBBUB_OK;
@ -482,23 +557,25 @@ hubbub_error ref_node(void *ctx, void *node)
hubbub_error unref_node(void *ctx, void *node)
{
hubbub_ctx *c = (hubbub_ctx *) ctx;
hubbub_private *pvt;
if (node == c->document) {
xmlDoc *n = (xmlDoc *) node;
uintptr_t count = (uintptr_t) n->_private;
pvt = n->_private;
assert(count != 0 && "Node has refcount of zero");
assert(pvt->refcnt != 0 && "Node has refcount of zero");
n->_private = (void *) (--count);
pvt->refcnt--;
} else {
xmlNode *n = (xmlNode *) node;
uintptr_t count = (uintptr_t) n->_private;
pvt = n->_private;
assert(count != 0 && "Node has refcount of zero");
assert(pvt->refcnt != 0 && "Node has refcount of zero");
n->_private = (void *) (--count);
pvt->refcnt--;
if (count == 0 && n->parent == NULL) {
if (pvt->refcnt == 0 && n->parent == NULL) {
free(pvt);
xmlFreeNode(n);
}
}
@ -585,13 +662,18 @@ hubbub_error remove_child(void *ctx, void *parent, void *child, void **result)
hubbub_error clone_node(void *ctx, void *node, bool deep, void **result)
{
xmlNode *n = (xmlNode *) node;
xmlNode *copy = xmlCopyNode(n, deep ? 1 : 2);
*result = xmlCopyNode(n, deep ? 1 : 2);
if (*result == NULL)
if (copy == NULL)
return HUBBUB_NOMEM;
((xmlNode *)(*result))->_private = (void *) (uintptr_t) 1;
copy->_private = create_private(1);
if (copy->_private == NULL) {
xmlFreeNode(copy);
return HUBBUB_NOMEM;
}
*result = copy;
return HUBBUB_OK;
}

View File

@ -23,9 +23,17 @@
#include <libxml/tree.h>
struct box;
struct form;
struct form_control;
/**
* Private data attached to each DOM node
*/
typedef struct binding_private {
struct box *box; /**< Root box if ELEMENT node, or NULL */
} binding_private;
typedef enum binding_error {
BINDING_OK,
BINDING_NOMEM,
@ -57,5 +65,7 @@ xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks);
struct form *binding_get_forms(void *ctx);
struct form_control *binding_get_control_for_node(void *ctx, xmlNodePtr node);
void binding_destroy_document(xmlDocPtr doc);
#endif