mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-03 09:44:24 +03:00
Use custom fetcher for inline CSS
This commit is contained in:
parent
21cbb49a6b
commit
97978e858b
@ -14,8 +14,8 @@ S_CSS := css.c dump.c internal.c select.c utils.c
|
||||
S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
|
||||
font.c form.c imagemap.c layout.c list.c search.c table.c \
|
||||
textplain.c \
|
||||
html.c html_css.c html_script.c html_interaction.c \
|
||||
html_redraw.c html_forms.c html_object.c
|
||||
html.c html_css.c html_css_fetcher.c html_script.c \
|
||||
html_interaction.c html_redraw.c html_forms.c html_object.c
|
||||
|
||||
S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c \
|
||||
libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c \
|
||||
|
42
css/css.c
42
css/css.c
@ -36,6 +36,30 @@
|
||||
/* Define to trace import fetches */
|
||||
#undef NSCSS_IMPORT_TRACE
|
||||
|
||||
struct content_css_data;
|
||||
|
||||
/**
|
||||
* Type of callback called when a CSS object has finished
|
||||
*
|
||||
* \param css CSS object that has completed
|
||||
* \param pw Client-specific data
|
||||
*/
|
||||
typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw);
|
||||
|
||||
/**
|
||||
* CSS content data
|
||||
*/
|
||||
struct content_css_data
|
||||
{
|
||||
css_stylesheet *sheet; /**< Stylesheet object */
|
||||
char *charset; /**< Character set of stylesheet */
|
||||
struct nscss_import *imports; /**< Array of imported sheets */
|
||||
uint32_t import_count; /**< Number of sheets imported */
|
||||
uint32_t next_to_register; /**< Index of next import to register */
|
||||
nscss_done_callback done; /**< Completion callback */
|
||||
void *pw; /**< Client data */
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS content data
|
||||
*/
|
||||
@ -67,6 +91,14 @@ static nserror nscss_clone(const struct content *old, struct content **newc);
|
||||
static bool nscss_matches_quirks(const struct content *c, bool quirks);
|
||||
static content_type nscss_content_type(void);
|
||||
|
||||
static nserror nscss_create_css_data(struct content_css_data *c,
|
||||
const char *url, const char *charset, bool quirks,
|
||||
nscss_done_callback done, void *pw);
|
||||
static css_error nscss_process_css_data(struct content_css_data *c, const char *data,
|
||||
unsigned int size);
|
||||
static css_error nscss_convert_css_data(struct content_css_data *c);
|
||||
static void nscss_destroy_css_data(struct content_css_data *c);
|
||||
|
||||
static void nscss_content_done(struct content_css_data *css, void *pw);
|
||||
static css_error nscss_handle_import(void *pw, css_stylesheet *parent,
|
||||
lwc_string *url, uint64_t media);
|
||||
@ -155,7 +187,7 @@ nserror nscss_create(const content_handler *handler,
|
||||
* \param pw Client data for \a done
|
||||
* \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion
|
||||
*/
|
||||
nserror nscss_create_css_data(struct content_css_data *c,
|
||||
static nserror nscss_create_css_data(struct content_css_data *c,
|
||||
const char *url, const char *charset, bool quirks,
|
||||
nscss_done_callback done, void *pw)
|
||||
{
|
||||
@ -227,8 +259,8 @@ bool nscss_process_data(struct content *c, const char *data, unsigned int size)
|
||||
* \param size Number of bytes to process
|
||||
* \return CSS_OK on success, appropriate error otherwise
|
||||
*/
|
||||
css_error nscss_process_css_data(struct content_css_data *c, const char *data,
|
||||
unsigned int size)
|
||||
static css_error nscss_process_css_data(struct content_css_data *c,
|
||||
const char *data, unsigned int size)
|
||||
{
|
||||
return css_stylesheet_append_data(c->sheet,
|
||||
(const uint8_t *) data, size);
|
||||
@ -262,7 +294,7 @@ bool nscss_convert(struct content *c)
|
||||
* \param c CSS data to convert
|
||||
* \return CSS error
|
||||
*/
|
||||
css_error nscss_convert_css_data(struct content_css_data *c)
|
||||
static css_error nscss_convert_css_data(struct content_css_data *c)
|
||||
{
|
||||
css_error error;
|
||||
|
||||
@ -310,7 +342,7 @@ void nscss_destroy(struct content *c)
|
||||
*
|
||||
* \param c CSS data to clean up
|
||||
*/
|
||||
void nscss_destroy_css_data(struct content_css_data *c)
|
||||
static void nscss_destroy_css_data(struct content_css_data *c)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
|
34
css/css.h
34
css/css.h
@ -25,33 +25,7 @@
|
||||
|
||||
#include "utils/errors.h"
|
||||
|
||||
struct content;
|
||||
struct content_css_data;
|
||||
struct hlcache_handle;
|
||||
struct http_parameter;
|
||||
struct nscss_import;
|
||||
|
||||
/**
|
||||
* Type of callback called when a CSS object has finished
|
||||
*
|
||||
* \param css CSS object that has completed
|
||||
* \param pw Client-specific data
|
||||
*/
|
||||
typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw);
|
||||
|
||||
/**
|
||||
* CSS content data
|
||||
*/
|
||||
struct content_css_data
|
||||
{
|
||||
css_stylesheet *sheet; /**< Stylesheet object */
|
||||
char *charset; /**< Character set of stylesheet */
|
||||
struct nscss_import *imports; /**< Array of imported sheets */
|
||||
uint32_t import_count; /**< Number of sheets imported */
|
||||
uint32_t next_to_register; /**< Index of next import to register */
|
||||
nscss_done_callback done; /**< Completion callback */
|
||||
void *pw; /**< Client data */
|
||||
};
|
||||
|
||||
/**
|
||||
* Imported stylesheet record
|
||||
@ -63,14 +37,6 @@ struct nscss_import {
|
||||
|
||||
nserror nscss_init(void);
|
||||
|
||||
nserror nscss_create_css_data(struct content_css_data *c,
|
||||
const char *url, const char *charset, bool quirks,
|
||||
nscss_done_callback done, void *pw);
|
||||
css_error nscss_process_css_data(struct content_css_data *c, const char *data,
|
||||
unsigned int size);
|
||||
css_error nscss_convert_css_data(struct content_css_data *c);
|
||||
void nscss_destroy_css_data(struct content_css_data *c);
|
||||
|
||||
css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h);
|
||||
struct nscss_import *nscss_get_imports(struct hlcache_handle *h, uint32_t *n);
|
||||
|
||||
|
@ -1954,10 +1954,8 @@ void browser_window_reload(struct browser_window *bw, bool all)
|
||||
sheets = html_get_stylesheets(c, &count);
|
||||
|
||||
for (i = STYLESHEET_START; i != count; i++) {
|
||||
if (sheets[i].type == HTML_STYLESHEET_EXTERNAL &&
|
||||
sheets[i].data.external != NULL) {
|
||||
content_invalidate_reuse_data(
|
||||
sheets[i].data.external);
|
||||
if (sheets[i].sheet != NULL) {
|
||||
content_invalidate_reuse_data(sheets[i].sheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -361,19 +361,10 @@ static bool save_complete_save_imported_sheets(save_complete_ctx *ctx,
|
||||
static bool save_complete_save_html_stylesheet(save_complete_ctx *ctx,
|
||||
struct html_stylesheet *sheet)
|
||||
{
|
||||
if (sheet->type == HTML_STYLESHEET_INTERNAL) {
|
||||
if (save_complete_save_imported_sheets(ctx,
|
||||
sheet->data.internal.data->imports,
|
||||
sheet->data.internal.data->import_count) == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sheet->data.external == NULL)
|
||||
if (sheet->sheet == NULL)
|
||||
return true;
|
||||
|
||||
return save_complete_save_stylesheet(ctx, sheet->data.external);
|
||||
return save_complete_save_stylesheet(ctx, sheet->sheet);
|
||||
}
|
||||
|
||||
static bool save_complete_save_html_stylesheets(save_complete_ctx *ctx,
|
||||
|
@ -94,6 +94,7 @@
|
||||
#include "utils/nsurl.h"
|
||||
#include "utils/types.h"
|
||||
|
||||
struct content;
|
||||
struct box;
|
||||
struct browser_window;
|
||||
struct column;
|
||||
|
@ -57,15 +57,8 @@ struct selection;
|
||||
*/
|
||||
struct html_stylesheet {
|
||||
/** Type of sheet */
|
||||
enum { HTML_STYLESHEET_EXTERNAL, HTML_STYLESHEET_INTERNAL } type;
|
||||
struct dom_node *node; /**< dom node associated with sheet */
|
||||
union {
|
||||
struct hlcache_handle *external;
|
||||
struct {
|
||||
struct content_css_data *data;
|
||||
bool done;
|
||||
} internal;
|
||||
} data; /**< Sheet data */
|
||||
struct hlcache_handle *sheet;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -73,7 +73,7 @@ static nserror css_error_to_nserror(css_error error)
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for fetchcache() for linked stylesheets.
|
||||
* Callback for fetchcache() for stylesheets.
|
||||
*/
|
||||
|
||||
static nserror
|
||||
@ -89,8 +89,7 @@ html_convert_css_callback(hlcache_handle *css,
|
||||
for (i = 0, s = parent->stylesheets;
|
||||
i != parent->stylesheet_count;
|
||||
i++, s++) {
|
||||
if (s->type == HTML_STYLESHEET_EXTERNAL &&
|
||||
s->data.external == css)
|
||||
if (s->sheet == css)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -115,7 +114,7 @@ html_convert_css_callback(hlcache_handle *css,
|
||||
nsurl_access(hlcache_handle_get_url(css)),
|
||||
event->data.error));
|
||||
hlcache_handle_release(css);
|
||||
s->data.external = NULL;
|
||||
s->sheet = NULL;
|
||||
parent->base.active--;
|
||||
LOG(("%d fetches active", parent->base.active));
|
||||
content_add_error(&parent->base, "?", 0);
|
||||
@ -170,13 +169,8 @@ nserror html_css_free_stylesheets(html_content *html)
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i != html->stylesheet_count; i++) {
|
||||
if ((html->stylesheets[i].type == HTML_STYLESHEET_EXTERNAL) &&
|
||||
(html->stylesheets[i].data.external != NULL)) {
|
||||
hlcache_handle_release(html->stylesheets[i].data.external);
|
||||
} else if ((html->stylesheets[i].type == HTML_STYLESHEET_INTERNAL) &&
|
||||
(html->stylesheets[i].data.internal.data != NULL)) {
|
||||
nscss_destroy_css_data(html->stylesheets[i].data.internal.data);
|
||||
free(html->stylesheets[i].data.internal.data);
|
||||
if (html->stylesheets[i].sheet != NULL) {
|
||||
hlcache_handle_release(html->stylesheets[i].sheet);
|
||||
}
|
||||
}
|
||||
free(html->stylesheets);
|
||||
@ -200,7 +194,7 @@ nserror html_css_quirks_stylesheets(html_content *c)
|
||||
0, content_get_url(&c->base), NULL,
|
||||
html_convert_css_callback, c, &child,
|
||||
CONTENT_CSS,
|
||||
&c->stylesheets[STYLESHEET_QUIRKS].data.external);
|
||||
&c->stylesheets[STYLESHEET_QUIRKS].sheet);
|
||||
if (ns_error != NSERROR_OK) {
|
||||
return ns_error;
|
||||
}
|
||||
@ -231,14 +225,10 @@ nserror html_css_new_stylesheets(html_content *c)
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
c->stylesheets[STYLESHEET_BASE].type = HTML_STYLESHEET_EXTERNAL;
|
||||
c->stylesheets[STYLESHEET_BASE].data.external = NULL;
|
||||
c->stylesheets[STYLESHEET_QUIRKS].type = HTML_STYLESHEET_EXTERNAL;
|
||||
c->stylesheets[STYLESHEET_QUIRKS].data.external = NULL;
|
||||
c->stylesheets[STYLESHEET_ADBLOCK].type = HTML_STYLESHEET_EXTERNAL;
|
||||
c->stylesheets[STYLESHEET_ADBLOCK].data.external = NULL;
|
||||
c->stylesheets[STYLESHEET_USER].type = HTML_STYLESHEET_EXTERNAL;
|
||||
c->stylesheets[STYLESHEET_USER].data.external = NULL;
|
||||
c->stylesheets[STYLESHEET_BASE].sheet = NULL;
|
||||
c->stylesheets[STYLESHEET_QUIRKS].sheet = NULL;
|
||||
c->stylesheets[STYLESHEET_ADBLOCK].sheet = NULL;
|
||||
c->stylesheets[STYLESHEET_USER].sheet = NULL;
|
||||
c->stylesheet_count = STYLESHEET_START;
|
||||
|
||||
child.charset = c->encoding;
|
||||
@ -247,7 +237,7 @@ nserror html_css_new_stylesheets(html_content *c)
|
||||
ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
|
||||
content_get_url(&c->base), NULL,
|
||||
html_convert_css_callback, c, &child, CONTENT_CSS,
|
||||
&c->stylesheets[STYLESHEET_BASE].data.external);
|
||||
&c->stylesheets[STYLESHEET_BASE].sheet);
|
||||
if (ns_error != NSERROR_OK) {
|
||||
return ns_error;
|
||||
}
|
||||
@ -260,8 +250,7 @@ nserror html_css_new_stylesheets(html_content *c)
|
||||
ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
|
||||
0, content_get_url(&c->base), NULL,
|
||||
html_convert_css_callback, c, &child, CONTENT_CSS,
|
||||
&c->stylesheets[STYLESHEET_ADBLOCK].
|
||||
data.external);
|
||||
&c->stylesheets[STYLESHEET_ADBLOCK].sheet);
|
||||
if (ns_error != NSERROR_OK) {
|
||||
return ns_error;
|
||||
}
|
||||
@ -274,7 +263,7 @@ nserror html_css_new_stylesheets(html_content *c)
|
||||
ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0,
|
||||
content_get_url(&c->base), NULL,
|
||||
html_convert_css_callback, c, &child, CONTENT_CSS,
|
||||
&c->stylesheets[STYLESHEET_USER].data.external);
|
||||
&c->stylesheets[STYLESHEET_USER].sheet);
|
||||
if (ns_error != NSERROR_OK) {
|
||||
return ns_error;
|
||||
}
|
||||
@ -285,141 +274,57 @@ nserror html_css_new_stylesheets(html_content *c)
|
||||
return ns_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle notification of inline style completion
|
||||
*
|
||||
* \param css Inline style object
|
||||
* \param pw Private data
|
||||
*/
|
||||
static void html_inline_style_done(struct content_css_data *css, void *pw)
|
||||
{
|
||||
html_content *html = pw;
|
||||
size_t i;
|
||||
|
||||
LOG(("Inline style %p done", css));
|
||||
|
||||
/* Search HTML content for sheet */
|
||||
for (i = 0; i < html->stylesheet_count; i++) {
|
||||
if (html->stylesheets[i].type == HTML_STYLESHEET_INTERNAL &&
|
||||
html->stylesheets[i].data.internal.data == css)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Not found: must have been replaced, so destroy it */
|
||||
if (i == html->stylesheet_count) {
|
||||
LOG(("Not found: destroying"));
|
||||
nscss_destroy_css_data(css);
|
||||
free(css);
|
||||
} else {
|
||||
html->stylesheets[i].data.internal.done = true;
|
||||
}
|
||||
|
||||
html->base.active--;
|
||||
LOG(("%d fetches active", html->base.active));
|
||||
if (html->base.active == 0) {
|
||||
html_begin_conversion(html);
|
||||
}
|
||||
}
|
||||
|
||||
static nserror
|
||||
html_stylesheet_from_domnode(html_content *c,
|
||||
struct html_stylesheet *s,
|
||||
dom_node *node)
|
||||
dom_node *node,
|
||||
hlcache_handle **sheet)
|
||||
{
|
||||
dom_node *child, *next;
|
||||
hlcache_child_context child;
|
||||
dom_string *style;
|
||||
nsurl *url;
|
||||
dom_exception exc;
|
||||
struct content_css_data *sheet, *old_sheet;
|
||||
bool old_sheet_done;
|
||||
nserror error;
|
||||
css_error csserror;
|
||||
uint32_t key;
|
||||
char urlbuf[64];
|
||||
|
||||
/* create stylesheet */
|
||||
sheet = calloc(1, sizeof(struct content_css_data));
|
||||
if (sheet == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
child.charset = c->encoding;
|
||||
child.quirks = c->base.quirks;
|
||||
|
||||
exc = dom_node_get_text_content(node, &style);
|
||||
if ((exc != DOM_NO_ERR) || (style == NULL)) {
|
||||
LOG(("No text content"));
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
error = nscss_create_css_data(sheet,
|
||||
nsurl_access(c->base_url), NULL, c->quirks,
|
||||
html_inline_style_done, c);
|
||||
error = html_css_fetcher_add_item(style, &key);
|
||||
if (error != NSERROR_OK) {
|
||||
free(sheet);
|
||||
dom_string_unref(style);
|
||||
return error;
|
||||
}
|
||||
|
||||
exc = dom_node_get_first_child(node, &child);
|
||||
if (exc != DOM_NO_ERR) {
|
||||
nscss_destroy_css_data(sheet);
|
||||
free(sheet);
|
||||
return NSERROR_DOM;
|
||||
dom_string_unref(style);
|
||||
|
||||
snprintf(urlbuf, sizeof(urlbuf), "x-ns-css:%u", key);
|
||||
|
||||
error = nsurl_create(urlbuf, &url);
|
||||
if (error != NSERROR_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
while (child != NULL) {
|
||||
dom_string *data;
|
||||
|
||||
exc = dom_node_get_text_content(child, &data);
|
||||
if (exc != DOM_NO_ERR) {
|
||||
dom_node_unref(child);
|
||||
nscss_destroy_css_data(sheet);
|
||||
free(sheet);
|
||||
return NSERROR_DOM;
|
||||
}
|
||||
|
||||
if (nscss_process_css_data(sheet,
|
||||
dom_string_data(data),
|
||||
dom_string_byte_length(data)) == false) {
|
||||
dom_string_unref(data);
|
||||
dom_node_unref(child);
|
||||
nscss_destroy_css_data(sheet);
|
||||
free(sheet);
|
||||
return NSERROR_CSS;
|
||||
}
|
||||
|
||||
dom_string_unref(data);
|
||||
|
||||
exc = dom_node_get_next_sibling(child, &next);
|
||||
if (exc != DOM_NO_ERR) {
|
||||
dom_node_unref(child);
|
||||
nscss_destroy_css_data(sheet);
|
||||
free(sheet);
|
||||
return NSERROR_DOM;
|
||||
}
|
||||
|
||||
dom_node_unref(child);
|
||||
child = next;
|
||||
error = hlcache_handle_retrieve(url, 0,
|
||||
content_get_url(&c->base), NULL,
|
||||
html_convert_css_callback, c, &child, CONTENT_CSS,
|
||||
sheet);
|
||||
if (error != NSERROR_OK) {
|
||||
nsurl_unref(url);
|
||||
return error;
|
||||
}
|
||||
|
||||
nsurl_unref(url);
|
||||
|
||||
c->base.active++;
|
||||
LOG(("%d fetches active", c->base.active));
|
||||
|
||||
LOG(("Updating sheet %p with %p", s->data.internal, sheet));
|
||||
|
||||
/* Update index */
|
||||
old_sheet = s->data.internal.data;
|
||||
old_sheet_done = s->data.internal.done;
|
||||
s->data.internal.data = sheet;
|
||||
s->data.internal.done = false;
|
||||
|
||||
/* Convert the content -- manually, as we want the result */
|
||||
csserror = nscss_convert_css_data(sheet);
|
||||
if (csserror != CSS_OK) {
|
||||
/* conversion failed */
|
||||
c->base.active--;
|
||||
LOG(("%d fetches active", c->base.active));
|
||||
nscss_destroy_css_data(sheet);
|
||||
free(sheet);
|
||||
s->data.internal.data = old_sheet;
|
||||
s->data.internal.done = old_sheet_done;
|
||||
return css_error_to_nserror(csserror);
|
||||
}
|
||||
|
||||
/* Clean up old sheet if it was already complete */
|
||||
if (old_sheet != NULL && old_sheet_done) {
|
||||
LOG(("Destroying old sheet %p", old_sheet));
|
||||
nscss_destroy_css_data(old_sheet);
|
||||
free(old_sheet);
|
||||
}
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
@ -472,10 +377,8 @@ html_create_style_element(html_content *c, dom_node *style)
|
||||
}
|
||||
c->stylesheets = stylesheets;
|
||||
|
||||
c->stylesheets[c->stylesheet_count].type = HTML_STYLESHEET_INTERNAL;
|
||||
c->stylesheets[c->stylesheet_count].node = style;
|
||||
c->stylesheets[c->stylesheet_count].data.internal.data = NULL;
|
||||
c->stylesheets[c->stylesheet_count].data.internal.done = false;
|
||||
c->stylesheets[c->stylesheet_count].sheet = NULL;
|
||||
c->stylesheet_count++;
|
||||
|
||||
return c->stylesheets + (c->stylesheet_count - 1);
|
||||
@ -486,11 +389,11 @@ bool html_css_update_style(html_content *c, dom_node *style)
|
||||
nserror error;
|
||||
unsigned int i;
|
||||
struct html_stylesheet *s;
|
||||
hlcache_handle *sheet = NULL;
|
||||
|
||||
/* Find sheet */
|
||||
for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
|
||||
if ((s->type == HTML_STYLESHEET_INTERNAL) &&
|
||||
(s->node == style))
|
||||
if (s->node == style)
|
||||
break;
|
||||
}
|
||||
if (i == c->stylesheet_count) {
|
||||
@ -504,13 +407,30 @@ bool html_css_update_style(html_content *c, dom_node *style)
|
||||
|
||||
LOG(("Found sheet %p slot %d for node %p", s, i, style));
|
||||
|
||||
error = html_stylesheet_from_domnode(c, s, style);
|
||||
error = html_stylesheet_from_domnode(c, style, &sheet);
|
||||
if (error != NSERROR_OK) {
|
||||
LOG(("Failed to update sheet"));
|
||||
content_broadcast_errorcode(&c->base, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sheet != NULL) {
|
||||
LOG(("Updating sheet %p with %p", s->sheet, sheet));
|
||||
|
||||
if (s->sheet != NULL) {
|
||||
switch (content_get_status(s->sheet)) {
|
||||
case CONTENT_STATUS_DONE:
|
||||
break;
|
||||
default:
|
||||
hlcache_handle_abort(s->sheet);
|
||||
c->base.active--;
|
||||
LOG(("%d fetches active", c->base.active));
|
||||
}
|
||||
hlcache_handle_release(s->sheet);
|
||||
}
|
||||
s->sheet = sheet;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -588,7 +508,6 @@ bool html_css_process_link(html_content *htmlc, dom_node *node)
|
||||
}
|
||||
|
||||
htmlc->stylesheets = stylesheets;
|
||||
htmlc->stylesheets[htmlc->stylesheet_count].type = HTML_STYLESHEET_EXTERNAL;
|
||||
|
||||
/* start fetch */
|
||||
child.charset = htmlc->encoding;
|
||||
@ -602,7 +521,7 @@ bool html_css_process_link(html_content *htmlc, dom_node *node)
|
||||
htmlc,
|
||||
&child,
|
||||
CONTENT_CSS,
|
||||
&htmlc->stylesheets[htmlc->stylesheet_count].data.external);
|
||||
&htmlc->stylesheets[htmlc->stylesheet_count].sheet);
|
||||
|
||||
nsurl_unref(joined);
|
||||
|
||||
@ -629,7 +548,7 @@ html_css_new_selection_context(html_content *c, css_select_ctx **ret_select_ctx)
|
||||
css_select_ctx *select_ctx;
|
||||
|
||||
/* check that the base stylesheet loaded; layout fails without it */
|
||||
if (c->stylesheets[STYLESHEET_BASE].data.external == NULL) {
|
||||
if (c->stylesheets[STYLESHEET_BASE].sheet == NULL) {
|
||||
return NSERROR_CSS_BASE;
|
||||
}
|
||||
|
||||
@ -651,11 +570,8 @@ html_css_new_selection_context(html_content *c, css_select_ctx **ret_select_ctx)
|
||||
origin = CSS_ORIGIN_USER;
|
||||
}
|
||||
|
||||
if ((hsheet->type == HTML_STYLESHEET_EXTERNAL) &&
|
||||
(hsheet->data.external != NULL)) {
|
||||
sheet = nscss_get_stylesheet(hsheet->data.external);
|
||||
} else if (hsheet->type == HTML_STYLESHEET_INTERNAL) {
|
||||
sheet = hsheet->data.internal.data->sheet;
|
||||
if (hsheet->sheet != NULL) {
|
||||
sheet = nscss_get_stylesheet(hsheet->sheet);
|
||||
}
|
||||
|
||||
if (sheet != NULL) {
|
||||
@ -679,6 +595,8 @@ nserror html_css_init(void)
|
||||
{
|
||||
nserror error;
|
||||
|
||||
html_css_fetcher_register();
|
||||
|
||||
error = nsurl_create("resource:default.css",
|
||||
&html_default_stylesheet_url);
|
||||
if (error != NSERROR_OK)
|
||||
|
298
render/html_css_fetcher.c
Normal file
298
render/html_css_fetcher.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
|
||||
* Copyright 2013 John-Mark Bell <jmb@netsurf-browser.org>
|
||||
*
|
||||
* This file is part of NetSurf.
|
||||
*
|
||||
* NetSurf is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* NetSurf is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <dom/dom.h>
|
||||
|
||||
#include <libwapcaplet/libwapcaplet.h>
|
||||
|
||||
#include "utils/config.h"
|
||||
#include "content/fetch.h"
|
||||
#include "render/html_internal.h"
|
||||
#include "utils/log.h"
|
||||
#include "utils/ring.h"
|
||||
#include "utils/nsurl.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
typedef struct html_css_fetcher_item {
|
||||
uint32_t key;
|
||||
dom_string *data;
|
||||
|
||||
struct html_css_fetcher_item *r_next, *r_prev;
|
||||
} html_css_fetcher_item;
|
||||
|
||||
typedef struct html_css_fetcher_context {
|
||||
struct fetch *parent_fetch;
|
||||
|
||||
nsurl *url;
|
||||
html_css_fetcher_item *item;
|
||||
|
||||
bool aborted;
|
||||
bool locked;
|
||||
|
||||
struct html_css_fetcher_context *r_next, *r_prev;
|
||||
} html_css_fetcher_context;
|
||||
|
||||
static uint32_t current_key = 0;
|
||||
static html_css_fetcher_item *items = NULL;
|
||||
static html_css_fetcher_context *ring = NULL;
|
||||
|
||||
static bool html_css_fetcher_initialise(lwc_string *scheme)
|
||||
{
|
||||
LOG(("html_css_fetcher_initialise called for %s", lwc_string_data(scheme)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void html_css_fetcher_finalise(lwc_string *scheme)
|
||||
{
|
||||
LOG(("html_css_fetcher_finalise called for %s", lwc_string_data(scheme)));
|
||||
}
|
||||
|
||||
static bool html_css_fetcher_can_fetch(const nsurl *url)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
|
||||
bool only_2xx, bool downgrade_tls, const char *post_urlenc,
|
||||
const struct fetch_multipart_data *post_multipart,
|
||||
const char **headers)
|
||||
{
|
||||
html_css_fetcher_context *ctx;
|
||||
lwc_string *path;
|
||||
uint32_t key;
|
||||
html_css_fetcher_item *item, *found = NULL;
|
||||
|
||||
/* format of a x-ns-css URL is:
|
||||
* x-ns-url:<key>
|
||||
* Where key is an unsigned 32bit integer
|
||||
*/
|
||||
|
||||
path = nsurl_get_component(url, NSURL_PATH);
|
||||
/* The path must exist */
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = strtoul(lwc_string_data(path), NULL, 10);
|
||||
|
||||
lwc_string_unref(path);
|
||||
|
||||
/* There must be at least one item */
|
||||
if (items == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = items;
|
||||
do {
|
||||
if (item->key == key) {
|
||||
found = item;
|
||||
break;
|
||||
}
|
||||
|
||||
item = item->r_next;
|
||||
} while (item != items);
|
||||
|
||||
/* We must have found the item */
|
||||
if (found == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx->parent_fetch = parent_fetch;
|
||||
ctx->url = nsurl_ref(url);
|
||||
ctx->item = found;
|
||||
|
||||
RING_INSERT(ring, ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static bool html_css_fetcher_start(void *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void html_css_fetcher_free(void *ctx)
|
||||
{
|
||||
html_css_fetcher_context *c = ctx;
|
||||
|
||||
nsurl_unref(c->url);
|
||||
if (c->item != NULL) {
|
||||
dom_string_unref(c->item->data);
|
||||
RING_REMOVE(items, c->item);
|
||||
free(c->item);
|
||||
}
|
||||
RING_REMOVE(ring, c);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void html_css_fetcher_abort(void *ctx)
|
||||
{
|
||||
html_css_fetcher_context *c = ctx;
|
||||
|
||||
/* To avoid the poll loop having to deal with the fetch context
|
||||
* disappearing from under it, we simply flag the abort here.
|
||||
* The poll loop itself will perform the appropriate cleanup.
|
||||
*/
|
||||
c->aborted = true;
|
||||
}
|
||||
|
||||
static void html_css_fetcher_send_callback(const fetch_msg *msg,
|
||||
html_css_fetcher_context *c)
|
||||
{
|
||||
c->locked = true;
|
||||
fetch_send_callback(msg, c->parent_fetch);
|
||||
c->locked = false;
|
||||
}
|
||||
|
||||
static void html_css_fetcher_poll(lwc_string *scheme)
|
||||
{
|
||||
fetch_msg msg;
|
||||
html_css_fetcher_context *c, *next;
|
||||
|
||||
if (ring == NULL) return;
|
||||
|
||||
/* Iterate over ring, processing each pending fetch */
|
||||
c = ring;
|
||||
do {
|
||||
/* Ignore fetches that have been flagged as locked.
|
||||
* This allows safe re-entrant calls to this function.
|
||||
* Re-entrancy can occur if, as a result of a callback,
|
||||
* the interested party causes fetch_poll() to be called
|
||||
* again.
|
||||
*/
|
||||
if (c->locked == true) {
|
||||
next = c->r_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only process non-aborted fetches */
|
||||
if (c->aborted) {
|
||||
/* Nothing to do */
|
||||
assert(c->locked == false);
|
||||
} else if (c->item != NULL) {
|
||||
char header[64];
|
||||
|
||||
fetch_set_http_code(c->parent_fetch, 200);
|
||||
|
||||
/* Any callback can result in the fetch being aborted.
|
||||
* Therefore, we _must_ check for this after _every_
|
||||
* call to html_css_fetcher_send_callback().
|
||||
*/
|
||||
snprintf(header, sizeof header,
|
||||
"Content-Type: text/css; charset=utf-8");
|
||||
msg.type = FETCH_HEADER;
|
||||
msg.data.header_or_data.buf = (const uint8_t *) header;
|
||||
msg.data.header_or_data.len = strlen(header);
|
||||
html_css_fetcher_send_callback(&msg, c);
|
||||
|
||||
if (c->aborted == false) {
|
||||
snprintf(header, sizeof header,
|
||||
"Content-Length: %"SSIZET_FMT,
|
||||
dom_string_byte_length(c->item->data));
|
||||
msg.type = FETCH_HEADER;
|
||||
msg.data.header_or_data.buf =
|
||||
(const uint8_t *) header;
|
||||
msg.data.header_or_data.len = strlen(header);
|
||||
html_css_fetcher_send_callback(&msg, c);
|
||||
}
|
||||
|
||||
if (c->aborted == false) {
|
||||
msg.type = FETCH_DATA;
|
||||
msg.data.header_or_data.buf =
|
||||
(const uint8_t *)
|
||||
dom_string_data(c->item->data);
|
||||
msg.data.header_or_data.len =
|
||||
dom_string_byte_length(c->item->data);
|
||||
html_css_fetcher_send_callback(&msg, c);
|
||||
}
|
||||
|
||||
if (c->aborted == false) {
|
||||
msg.type = FETCH_FINISHED;
|
||||
html_css_fetcher_send_callback(&msg, c);
|
||||
}
|
||||
} else {
|
||||
LOG(("Processing of %s failed!",
|
||||
nsurl_access(c->url)));
|
||||
|
||||
/* Ensure that we're unlocked here. If we aren't,
|
||||
* then html_css_fetcher_process() is broken.
|
||||
*/
|
||||
assert(c->locked == false);
|
||||
}
|
||||
|
||||
/* Compute next fetch item at the last possible moment as
|
||||
* processing this item may have added to the ring.
|
||||
*/
|
||||
next = c->r_next;
|
||||
|
||||
fetch_remove_from_queues(c->parent_fetch);
|
||||
fetch_free(c->parent_fetch);
|
||||
|
||||
/* Advance to next ring entry, exiting if we've reached
|
||||
* the start of the ring or the ring has become empty
|
||||
*/
|
||||
} while ( (c = next) != ring && ring != NULL);
|
||||
}
|
||||
|
||||
void html_css_fetcher_register(void)
|
||||
{
|
||||
lwc_string *scheme;
|
||||
|
||||
if (lwc_intern_string("x-ns-css", SLEN("x-ns-css"),
|
||||
&scheme) != lwc_error_ok) {
|
||||
die("Failed to initialise the fetch module "
|
||||
"(couldn't intern \"x-ns-css\").");
|
||||
}
|
||||
|
||||
fetch_add_fetcher(scheme,
|
||||
html_css_fetcher_initialise,
|
||||
html_css_fetcher_can_fetch,
|
||||
html_css_fetcher_setup,
|
||||
html_css_fetcher_start,
|
||||
html_css_fetcher_abort,
|
||||
html_css_fetcher_free,
|
||||
html_css_fetcher_poll,
|
||||
html_css_fetcher_finalise);
|
||||
}
|
||||
|
||||
nserror html_css_fetcher_add_item(dom_string *data, uint32_t *key)
|
||||
{
|
||||
html_css_fetcher_item *item = malloc(sizeof(*item));
|
||||
|
||||
if (item == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
*key = item->key = current_key++;
|
||||
item->data = dom_string_ref(data);
|
||||
|
||||
RING_INSERT(items, item);
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
@ -270,6 +270,10 @@ bool html_css_update_style(html_content *c, dom_node *style);
|
||||
|
||||
nserror html_css_new_selection_context(html_content *c, css_select_ctx **ret_select_ctx);
|
||||
|
||||
/* in render/html_css_fetcher.c */
|
||||
void html_css_fetcher_register(void);
|
||||
nserror html_css_fetcher_add_item(dom_string *data, uint32_t *key);
|
||||
|
||||
/* in render/html_object.c */
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user