mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-23 04:26:50 +03:00
Restartable box tree constructor. Yield between elements.
svn path=/trunk/netsurf/; revision=12912
This commit is contained in:
parent
f97d7425a8
commit
74395ac888
@ -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;
|
||||
|
15
render/box.h
15
render/box.h
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user