1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

Merge branch 'css'

This commit is contained in:
Witold Filipczyk 2023-02-28 18:43:07 +01:00
commit 0ef89025ab
33 changed files with 8836 additions and 5015 deletions

View File

@ -131,6 +131,9 @@
/* Define if you want: LEDs support */ /* Define if you want: LEDs support */
#mesondefine CONFIG_LEDS #mesondefine CONFIG_LEDS
/* Define as 1 to use the libcss library */
#mesondefine CONFIG_LIBCSS
/* Define as 1 to use the libdom library. */ /* Define as 1 to use the libdom library. */
#mesondefine CONFIG_LIBDOM #mesondefine CONFIG_LIBDOM

View File

@ -873,6 +873,18 @@ if test "x$CONFIG_QUICKJS" = xyes; then
AC_SUBST(CONFIG_QUICKJS) AC_SUBST(CONFIG_QUICKJS)
AC_SUBST(CONFIG_XML) AC_SUBST(CONFIG_XML)
fi fi
# ===================================================================
# Check for libcss
# ===================================================================
if test "x$CONFIG_XML" = xyes; then
LIBCSS_CFLAGS=`$PKG_CONFIG $pkg_config_static --cflags libcss`
LIBCSS_LIBS=`$PKG_CONFIG $pkg_config_static --libs libcss`
LIBS="$LIBS $LIBCSS_LIBS"
CFLAGS="$CFLAGS $LIBCSS_CFLAGS"
fi
# =================================================================== # ===================================================================
# Check for Guile, optional even if installed. # Check for Guile, optional even if installed.
# =================================================================== # ===================================================================

View File

@ -406,6 +406,14 @@ if conf_data.get('CONFIG_ECMASCRIPT_SMJS') or conf_data.get('CONFIG_QUICKJS') or
deps += curldeps deps += curldeps
endif endif
conf_data.set('CONFIG_LIBCSS', false)
if conf_data.get('CONFIG_ECMASCRIPT_SMJS') or conf_data.get('CONFIG_QUICKJS') or conf_data.get('CONFIG_MUJS')
cssdeps = dependency('libcss', static: st, version: '>=0.9.1')
deps += cssdeps
conf_data.set('CONFIG_LIBCSS', true)
endif
if conf_data.get('CONFIG_SCRIPTING_LUA') if conf_data.get('CONFIG_SCRIPTING_LUA')
luadeps = dependency(luapkg, static: st) luadeps = dependency(luapkg, static: st)
deps += luadeps deps += luadeps

View File

@ -234,6 +234,9 @@ examine_element(struct html_context *html_context, struct css_selector *base,
process_found_selector(selector, CST_PSEUDO, base); process_found_selector(selector, CST_PSEUDO, base);
} }
#ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
#else
if (element->attr.class_ && seltype <= CST_CLASS) { if (element->attr.class_ && seltype <= CST_CLASS) {
const char *class_ = element->attr.class_; const char *class_ = element->attr.class_;
@ -255,6 +258,8 @@ examine_element(struct html_context *html_context, struct css_selector *base,
selector = find_css_selector(selectors, CST_ID, rel, element->attr.id, -1); selector = find_css_selector(selectors, CST_ID, rel, element->attr.id, -1);
process_found_selector(selector, CST_ID, base); process_found_selector(selector, CST_ID, base);
} }
#endif
#endif
#undef process_found_selector #undef process_found_selector
#undef dbginfo #undef dbginfo

View File

@ -35,7 +35,11 @@ union option_info css_options_info[] = {
INIT_OPT_BOOL("document.css", N_("Enable CSS"), INIT_OPT_BOOL("document.css", N_("Enable CSS"),
"enable", OPT_ZERO, 1, "enable", OPT_ZERO, 1,
N_("Enable adding of CSS style info to documents.")), N_("Enable adding of CSS style info to documents.")),
#ifdef CONFIG_LIBCSS
INIT_OPT_BOOL("document.css", N_("Prefer libcss"),
"libcss", OPT_ZERO, 0,
N_("Enable experimental code using the libcss library instead of builtin implementation.")),
#endif
INIT_OPT_BOOL("document.css", N_("Ignore \"display: none\""), INIT_OPT_BOOL("document.css", N_("Ignore \"display: none\""),
"ignore_display_none", OPT_ZERO, 1, "ignore_display_none", OPT_ZERO, 1,
N_("When enabled, elements are rendered, even when their " N_("When enabled, elements are rendered, even when their "

831
src/document/css2/css.c Normal file
View File

@ -0,0 +1,831 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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 <libwapcaplet/libwapcaplet.h>
#include <dom/dom.h>
#include "utils/errors.h"
#include "utils/corestrings.h"
#include "utils/utils.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "content/content_protected.h"
#include "content/content_factory.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "desktop/system_colour.h"
#include "css/css.h"
#include "css/hints.h"
#include "css/internal.h"
/* 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
*/
typedef struct nscss_content
{
struct content base; /**< Underlying content object */
struct content_css_data data; /**< CSS data */
} nscss_content;
/**
* Context for import fetches
*/
typedef struct {
struct content_css_data *css; /**< Object containing import */
uint32_t index; /**< Index into parent sheet's
* imports array */
} nscss_import_ctx;
static bool nscss_convert(struct content *c);
static void nscss_destroy(struct content *c);
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);
static nserror nscss_import(hlcache_handle *handle,
const hlcache_event *event, void *pw);
static css_error nscss_import_complete(nscss_import_ctx *ctx);
static css_error nscss_register_imports(struct content_css_data *c);
static css_error nscss_register_import(struct content_css_data *c,
const hlcache_handle *import);
static css_stylesheet *blank_import;
/**
* Initialise a CSS content
*
* \param handler content handler
* \param imime_type mime-type
* \param params Content-Type parameters
* \param llcache handle to content
* \param fallback_charset The character set to fallback to.
* \param quirks allow quirks
* \param c Content to initialise
* \return NSERROR_OK or error cod eon faliure
*/
static nserror
nscss_create(const content_handler *handler,
lwc_string *imime_type,
const http_parameter *params,
llcache_handle *llcache,
const char *fallback_charset,
bool quirks,
struct content **c)
{
nscss_content *result;
const char *charset = NULL;
const char *xnsbase = NULL;
lwc_string *charset_value = NULL;
nserror error;
result = calloc(1, sizeof(nscss_content));
if (result == NULL)
return NSERROR_NOMEM;
error = content__init(&result->base, handler, imime_type,
params, llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(result);
return error;
}
/* Find charset specified on HTTP layer, if any */
error = http_parameter_list_find_item(params, corestring_lwc_charset,
&charset_value);
if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) {
/* No charset specified, use fallback, if any */
/** \todo libcss will take this as gospel, which is wrong */
charset = fallback_charset;
} else {
charset = lwc_string_data(charset_value);
}
/* Compute base URL for stylesheet */
xnsbase = llcache_handle_get_header(llcache, "X-NS-Base");
if (xnsbase == NULL) {
xnsbase = nsurl_access(content_get_url(&result->base));
}
error = nscss_create_css_data(&result->data,
xnsbase, charset, result->base.quirks,
nscss_content_done, result);
if (error != NSERROR_OK) {
content_broadcast_error(&result->base, NSERROR_NOMEM, NULL);
if (charset_value != NULL)
lwc_string_unref(charset_value);
free(result);
return error;
}
if (charset_value != NULL)
lwc_string_unref(charset_value);
*c = (struct content *) result;
return NSERROR_OK;
}
/**
* Create a struct content_css_data, creating a stylesheet object
*
* \param c Struct to populate
* \param url URL of stylesheet
* \param charset Stylesheet charset
* \param quirks Stylesheet quirks mode
* \param done Callback to call when content has completed
* \param pw Client data for \a done
* \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion
*/
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)
{
css_error error;
css_stylesheet_params params;
c->pw = pw;
c->done = done;
c->next_to_register = (uint32_t) -1;
c->import_count = 0;
c->imports = NULL;
if (charset != NULL)
c->charset = strdup(charset);
else
c->charset = NULL;
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_DEFAULT;
params.charset = charset;
params.url = url;
params.title = NULL;
params.allow_quirks = quirks;
params.inline_style = false;
params.resolve = nscss_resolve_url;
params.resolve_pw = NULL;
params.import = nscss_handle_import;
params.import_pw = c;
params.color = ns_system_colour;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
error = css_stylesheet_create(&params, &c->sheet);
if (error != CSS_OK) {
return NSERROR_NOMEM;
}
return NSERROR_OK;
}
/**
* Process CSS source data
*
* \param c Content structure
* \param data Data to process
* \param size Number of bytes to process
* \return true on success, false on failure
*/
static bool
nscss_process_data(struct content *c, const char *data, unsigned int size)
{
nscss_content *css = (nscss_content *) c;
css_error error;
error = nscss_process_css_data(&css->data, data, size);
if (error != CSS_OK && error != CSS_NEEDDATA) {
content_broadcast_error(c, NSERROR_CSS, NULL);
}
return (error == CSS_OK || error == CSS_NEEDDATA);
}
/**
* Process CSS data
*
* \param c CSS content object
* \param data Data to process
* \param size Number of bytes to process
* \return CSS_OK on success, appropriate error otherwise
*/
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);
}
/**
* Convert a CSS content ready for use
*
* \param c Content to convert
* \return true on success, false on failure
*/
bool nscss_convert(struct content *c)
{
nscss_content *css = (nscss_content *) c;
css_error error;
error = nscss_convert_css_data(&css->data);
if (error != CSS_OK) {
content_broadcast_error(c, NSERROR_CSS, NULL);
return false;
}
return true;
}
/**
* Convert CSS data ready for use
*
* \param c CSS data to convert
* \return CSS error
*/
static css_error nscss_convert_css_data(struct content_css_data *c)
{
css_error error;
error = css_stylesheet_data_done(c->sheet);
/* Process pending imports */
if (error == CSS_IMPORTS_PENDING) {
/* We must not have registered any imports yet */
assert(c->next_to_register == (uint32_t) -1);
/* Start registering, until we find one that
* hasn't finished fetching */
c->next_to_register = 0;
error = nscss_register_imports(c);
} else if (error == CSS_OK) {
/* No imports, and no errors, so complete conversion */
c->done(c, c->pw);
} else {
const char *url;
if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) {
NSLOG(netsurf, INFO, "Failed converting %p %s (%d)",
c, url, error);
} else {
NSLOG(netsurf, INFO, "Failed converting %p (%d)", c,
error);
}
}
return error;
}
/**
* Clean up a CSS content
*
* \param c Content to clean up
*/
void nscss_destroy(struct content *c)
{
nscss_content *css = (nscss_content *) c;
nscss_destroy_css_data(&css->data);
}
/**
* Clean up CSS data
*
* \param c CSS data to clean up
*/
static void nscss_destroy_css_data(struct content_css_data *c)
{
uint32_t i;
for (i = 0; i < c->import_count; i++) {
if (c->imports[i].c != NULL) {
hlcache_handle_release(c->imports[i].c);
}
c->imports[i].c = NULL;
}
free(c->imports);
if (c->sheet != NULL) {
css_stylesheet_destroy(c->sheet);
c->sheet = NULL;
}
free(c->charset);
}
nserror nscss_clone(const struct content *old, struct content **newc)
{
const nscss_content *old_css = (const nscss_content *) old;
nscss_content *new_css;
const uint8_t *data;
size_t size;
nserror error;
new_css = calloc(1, sizeof(nscss_content));
if (new_css == NULL)
return NSERROR_NOMEM;
/* Clone content */
error = content__clone(old, &new_css->base);
if (error != NSERROR_OK) {
content_destroy(&new_css->base);
return error;
}
/* Simply replay create/process/convert */
error = nscss_create_css_data(&new_css->data,
nsurl_access(content_get_url(&new_css->base)),
old_css->data.charset,
new_css->base.quirks,
nscss_content_done, new_css);
if (error != NSERROR_OK) {
content_destroy(&new_css->base);
return error;
}
data = content__get_source_data(&new_css->base, &size);
if (size > 0) {
if (nscss_process_data(&new_css->base,
(char *)data,
(unsigned int)size) == false) {
content_destroy(&new_css->base);
return NSERROR_CLONE_FAILED;
}
}
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nscss_convert(&new_css->base) == false) {
content_destroy(&new_css->base);
return NSERROR_CLONE_FAILED;
}
}
*newc = (struct content *) new_css;
return NSERROR_OK;
}
bool nscss_matches_quirks(const struct content *c, bool quirks)
{
return c->quirks == quirks;
}
/* exported interface documented in netsurf/css.h */
css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h)
{
nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
assert(c != NULL);
return c->data.sheet;
}
/* exported interface documented in netsurf/css.h */
struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n)
{
nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
assert(c != NULL);
assert(n != NULL);
*n = c->data.import_count;
return c->data.imports;
}
/**
* Compute the type of a content
*
* \return CONTENT_CSS
*/
content_type nscss_content_type(void)
{
return CONTENT_CSS;
}
/*****************************************************************************
* Object completion *
*****************************************************************************/
/**
* Handle notification that a CSS object is done
*
* \param css CSS object
* \param pw Private data
*/
void nscss_content_done(struct content_css_data *css, void *pw)
{
struct content *c = pw;
uint32_t i;
size_t size;
css_error error;
/* Retrieve the size of this sheet */
error = css_stylesheet_size(css->sheet, &size);
if (error != CSS_OK) {
content_broadcast_error(c, NSERROR_CSS, NULL);
content_set_error(c);
return;
}
c->size += size;
/* Add on the size of the imported sheets */
for (i = 0; i < css->import_count; i++) {
if (css->imports[i].c != NULL) {
struct content *import = hlcache_handle_get_content(
css->imports[i].c);
if (import != NULL) {
c->size += import->size;
}
}
}
/* Finally, catch the content's users up with reality */
content_set_ready(c);
content_set_done(c);
}
/*****************************************************************************
* Import handling *
*****************************************************************************/
/**
* Handle notification of the need for an imported stylesheet
*
* \param pw CSS object requesting the import
* \param parent Stylesheet requesting the import
* \param url URL of the imported sheet
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_handle_import(void *pw, css_stylesheet *parent,
lwc_string *url)
{
content_type accept = CONTENT_CSS;
struct content_css_data *c = pw;
nscss_import_ctx *ctx;
hlcache_child_context child;
struct nscss_import *imports;
const char *referer;
css_error error;
nserror nerror;
nsurl *ns_url;
nsurl *ns_ref;
assert(parent == c->sheet);
error = css_stylesheet_get_url(c->sheet, &referer);
if (error != CSS_OK) {
return error;
}
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return CSS_NOMEM;
ctx->css = c;
ctx->index = c->import_count;
/* Increase space in table */
imports = realloc(c->imports, (c->import_count + 1) *
sizeof(struct nscss_import));
if (imports == NULL) {
free(ctx);
return CSS_NOMEM;
}
c->imports = imports;
/** \todo fallback charset */
child.charset = NULL;
error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks);
if (error != CSS_OK) {
free(ctx);
return error;
}
/* Create content */
/** \todo Why aren't we getting a relative url part, to join? */
nerror = nsurl_create(lwc_string_data(url), &ns_url);
if (nerror != NSERROR_OK) {
free(ctx);
return CSS_NOMEM;
}
/** \todo Constructing nsurl for referer here is silly, avoid */
nerror = nsurl_create(referer, &ns_ref);
if (nerror != NSERROR_OK) {
nsurl_unref(ns_url);
free(ctx);
return CSS_NOMEM;
}
/* Avoid importing ourself */
if (nsurl_compare(ns_url, ns_ref, NSURL_COMPLETE)) {
c->imports[c->import_count].c = NULL;
/* No longer require context as we're not fetching anything */
free(ctx);
ctx = NULL;
} else {
nerror = hlcache_handle_retrieve(ns_url,
0, ns_ref, NULL, nscss_import, ctx,
&child, accept,
&c->imports[c->import_count].c);
if (nerror != NSERROR_OK) {
free(ctx);
return CSS_NOMEM;
}
}
nsurl_unref(ns_url);
nsurl_unref(ns_ref);
#ifdef NSCSS_IMPORT_TRACE
NSLOG(netsurf, INFO, "Import %d '%s' -> (handle: %p ctx: %p)",
c->import_count, lwc_string_data(url),
c->imports[c->import_count].c, ctx);
#endif
c->import_count++;
return CSS_OK;
}
/**
* Handler for imported stylesheet events
*
* \param handle Handle for stylesheet
* \param event Event object
* \param pw Callback context
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror nscss_import(hlcache_handle *handle,
const hlcache_event *event, void *pw)
{
nscss_import_ctx *ctx = pw;
css_error error = CSS_OK;
#ifdef NSCSS_IMPORT_TRACE
NSLOG(netsurf, INFO, "Event %d for %p (%p)", event->type, handle, ctx);
#endif
assert(ctx->css->imports[ctx->index].c == handle);
switch (event->type) {
case CONTENT_MSG_DONE:
error = nscss_import_complete(ctx);
break;
case CONTENT_MSG_ERROR:
hlcache_handle_release(handle);
ctx->css->imports[ctx->index].c = NULL;
error = nscss_import_complete(ctx);
/* Already released handle */
break;
default:
break;
}
/* Preserve out-of-memory. Anything else is OK */
return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK;
}
/**
* Handle an imported stylesheet completing
*
* \param ctx Import context
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_import_complete(nscss_import_ctx *ctx)
{
css_error error = CSS_OK;
/* If this import is the next to be registered, do so */
if (ctx->css->next_to_register == ctx->index)
error = nscss_register_imports(ctx->css);
#ifdef NSCSS_IMPORT_TRACE
NSLOG(netsurf, INFO, "Destroying import context %p for %d", ctx,
ctx->index);
#endif
/* No longer need import context */
free(ctx);
return error;
}
/*****************************************************************************
* Import registration *
*****************************************************************************/
/**
* Register imports with a stylesheet
*
* \param c CSS object containing the imports
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_register_imports(struct content_css_data *c)
{
uint32_t index;
css_error error;
assert(c->next_to_register != (uint32_t) -1);
assert(c->next_to_register < c->import_count);
/* Register imported sheets */
for (index = c->next_to_register; index < c->import_count; index++) {
/* Stop registering if we encounter one whose fetch hasn't
* completed yet. We'll resume at this point when it has
* completed.
*/
if (c->imports[index].c != NULL &&
content_get_status(c->imports[index].c) !=
CONTENT_STATUS_DONE) {
break;
}
error = nscss_register_import(c, c->imports[index].c);
if (error != CSS_OK)
return error;
}
/* Record identity of the next import to register */
c->next_to_register = (uint32_t) index;
if (c->next_to_register == c->import_count) {
/* No more imports: notify parent that we're DONE */
c->done(c, c->pw);
}
return CSS_OK;
}
/**
* Register an import with a stylesheet
*
* \param c CSS object that requested the import
* \param import Cache handle of import, or NULL for blank
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_register_import(struct content_css_data *c,
const hlcache_handle *import)
{
css_stylesheet *sheet;
css_error error;
if (import != NULL) {
nscss_content *s =
(nscss_content *) hlcache_handle_get_content(import);
sheet = s->data.sheet;
} else {
/* Create a blank sheet if needed. */
if (blank_import == NULL) {
css_stylesheet_params params;
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_DEFAULT;
params.charset = NULL;
params.url = "";
params.title = NULL;
params.allow_quirks = false;
params.inline_style = false;
params.resolve = nscss_resolve_url;
params.resolve_pw = NULL;
params.import = NULL;
params.import_pw = NULL;
params.color = ns_system_colour;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
error = css_stylesheet_create(&params, &blank_import);
if (error != CSS_OK) {
return error;
}
error = css_stylesheet_data_done(blank_import);
if (error != CSS_OK) {
css_stylesheet_destroy(blank_import);
return error;
}
}
sheet = blank_import;
}
error = css_stylesheet_register_import(c->sheet, sheet);
if (error != CSS_OK) {
return error;
}
return error;
}
/**
* Clean up after the CSS content handler
*/
static void nscss_fini(void)
{
if (blank_import != NULL) {
css_stylesheet_destroy(blank_import);
blank_import = NULL;
}
css_hint_fini();
}
static const content_handler css_content_handler = {
.fini = nscss_fini,
.create = nscss_create,
.process_data = nscss_process_data,
.data_complete = nscss_convert,
.destroy = nscss_destroy,
.clone = nscss_clone,
.matches_quirks = nscss_matches_quirks,
.type = nscss_content_type,
.no_share = false,
};
/* exported interface documented in netsurf/css.h */
nserror nscss_init(void)
{
nserror error;
error = content_factory_register_handler("text/css",
&css_content_handler);
if (error != NSERROR_OK)
goto error;
error = css_hint_init();
if (error != NSERROR_OK)
goto error;
return NSERROR_OK;
error:
nscss_fini();
return error;
}

1615
src/document/css2/css.cpp Normal file

File diff suppressed because it is too large Load Diff

23
src/document/css2/css.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef EL__DOCUMENT_CSS2_CSS_H
#define EL__DOCUMENT_CSS2_CSS_H
#include <libcss/libcss.h>
#ifdef __cplusplus
extern "C" {
#endif
struct html_context;
struct html_element;
struct uri;
css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs);
void select_css(struct html_context *html_context, struct html_element *element);
void parse_css(struct html_context *html_context, char *name);
void import_css2(struct html_context *html_context, struct uri *uri);
#ifdef __cplusplus
}
#endif
#endif

1833
src/document/css2/dump.c Normal file

File diff suppressed because it is too large Load Diff

30
src/document/css2/dump.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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/>.
*/
#ifndef NETSURF_CSS_DUMP_H_
#define NETSURF_CSS_DUMP_H_
/**
* Dump a computed style \a style to the give file handle \a stream.
*
* \param stream Stream to write to
* \param style Computed style to dump
*/
void nscss_dump_computed_style(FILE *stream, const css_computed_style *style);
#endif

1691
src/document/css2/hints.c Normal file

File diff suppressed because it is too large Load Diff

55
src/document/css2/hints.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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/>.
*/
#ifndef NETSURF_CSS_HINTS_H_
#define NETSURF_CSS_HINTS_H_
#include <stdint.h>
#include <libcss/libcss.h>
nserror css_hint_init(void);
void css_hint_fini(void);
/**
* Callback to retrieve presentational hints for a node
*
* \param[in] pw HTML document
* \param[in] node DOM node
* \param[out] nhints number of hints retrieved
* \param[out] hints retrieved hints
* \return CSS_OK on success,
* CSS_PROPERTY_NOT_SET if there is no hint for the requested property,
* CSS_NOMEM on memory exhaustion.
*/
css_error node_presentational_hint(
void *pw,
void *node,
uint32_t *nhints,
css_hint **hints);
/**
* Parser for colours specified in attribute values.
*
* \param data Data to parse (NUL-terminated)
* \param result Pointer to location to receive resulting css_color
* \return true on success, false on invalid input
*/
bool nscss_parse_colour(const char *data, css_color *result);
#endif

View File

@ -0,0 +1,63 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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 <string.h>
#include <libcss/libcss.h>
#include "utils/nsurl.h"
#include "css/internal.h"
/* exported interface documented in content/handlers/css/internal.h */
css_error nscss_resolve_url(void *pw, const char *base,
lwc_string *rel, lwc_string **abs)
{
lwc_error lerror;
nserror error;
nsurl *nsbase;
nsurl *nsabs;
/* Create nsurl from base */
/* TODO: avoid this */
error = nsurl_create(base, &nsbase);
if (error != NSERROR_OK) {
return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID;
}
/* Resolve URI */
error = nsurl_join(nsbase, lwc_string_data(rel), &nsabs);
if (error != NSERROR_OK) {
nsurl_unref(nsbase);
return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID;
}
nsurl_unref(nsbase);
/* Intern it */
lerror = lwc_intern_string(nsurl_access(nsabs),
nsurl_length(nsabs), abs);
if (lerror != lwc_error_ok) {
*abs = NULL;
nsurl_unref(nsabs);
return lerror == lwc_error_oom ? CSS_NOMEM : CSS_INVALID;
}
nsurl_unref(nsabs);
return CSS_OK;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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/>.
*/
#ifndef NETSURF_CSS_INTERNAL_H_
#define NETSURF_CSS_INTERNAL_H_
/**
* URL resolution callback for libcss
*
* \param pw Resolution context
* \param base Base URI
* \param rel Relative URL
* \param abs Pointer to location to receive resolved URL
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion,
* CSS_INVALID if resolution failed.
*/
css_error nscss_resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs);
#endif

View File

@ -0,0 +1 @@
srcs += files('css.cpp')

1892
src/document/css2/select.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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/>.
*/
#ifndef NETSURF_CSS_SELECT_H_
#define NETSURF_CSS_SELECT_H_
#include <stdint.h>
#include <dom/dom.h>
#include <libcss/libcss.h>
struct content;
struct nsurl;
/**
* Selection context
*/
typedef struct nscss_select_ctx
{
css_select_ctx *ctx;
bool quirks;
struct nsurl *base_url;
lwc_string *universal;
const css_computed_style *root_style;
const css_computed_style *parent_style;
} nscss_select_ctx;
css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
const char *charset, const char *url, bool allow_quirks);
css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
const css_media *media, const css_stylesheet *inline_style);
css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
const css_computed_style *parent);
css_error named_ancestor_node(void *pw, void *node,
const css_qname *qname, void **ancestor);
css_error node_is_visited(void *pw, void *node, bool *match);
#endif

259
src/document/css2/utils.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright 2004 James Bursa <james@netsurf-browser.org>
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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 "utils/nsoption.h"
#include "utils/log.h"
#include "css/utils.h"
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = F_90;
/** Medium screen density for device viewing distance. */
css_fixed nscss_baseline_pixel_density = F_96;
/**
* Map viewport-relative length units to either vh or vw.
*
* Non-viewport-relative units are unchanged.
*
* \param[in] ctx Length conversion context.
* \param[in] unit Unit to map.
* \return the mapped unit.
*/
static inline css_unit css_utils__fudge_viewport_units(
const nscss_len_ctx *ctx,
css_unit unit)
{
switch (unit) {
case CSS_UNIT_VI:
assert(ctx->root_style != NULL);
if (css_computed_writing_mode(ctx->root_style) ==
CSS_WRITING_MODE_HORIZONTAL_TB) {
unit = CSS_UNIT_VW;
} else {
unit = CSS_UNIT_VH;
}
break;
case CSS_UNIT_VB:
assert(ctx->root_style != NULL);
if (css_computed_writing_mode(ctx->root_style) ==
CSS_WRITING_MODE_HORIZONTAL_TB) {
unit = CSS_UNIT_VH;
} else {
unit = CSS_UNIT_VW;
}
break;
case CSS_UNIT_VMIN:
if (ctx->vh < ctx->vw) {
unit = CSS_UNIT_VH;
} else {
unit = CSS_UNIT_VW;
}
break;
case CSS_UNIT_VMAX:
if (ctx->vh > ctx->vw) {
unit = CSS_UNIT_VH;
} else {
unit = CSS_UNIT_VW;
}
break;
default: break;
}
return unit;
}
/* exported interface documented in content/handlers/css/utils.h */
css_fixed nscss_len2pt(
const nscss_len_ctx *ctx,
css_fixed length,
css_unit unit)
{
/* Length must not be relative */
assert(unit != CSS_UNIT_EM &&
unit != CSS_UNIT_EX &&
unit != CSS_UNIT_CAP &&
unit != CSS_UNIT_CH &&
unit != CSS_UNIT_IC &&
unit != CSS_UNIT_REM &&
unit != CSS_UNIT_RLH);
unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
/* We assume the screen and any other output has the same dpi */
/* 1in = DPIpx => 1px = (72/DPI)pt */
case CSS_UNIT_PX: return FDIV(FMUL(length, F_72), F_96);
/* 1in = 72pt */
case CSS_UNIT_IN: return FMUL(length, F_72);
/* 1in = 2.54cm => 1cm = (72/2.54)pt */
case CSS_UNIT_CM: return FMUL(length,
FDIV(F_72, FLTTOFIX(2.54)));
/* 1in = 25.4mm => 1mm = (72/25.4)pt */
case CSS_UNIT_MM: return FMUL(length,
FDIV(F_72, FLTTOFIX(25.4)));
/* 1in = 101.6q => 1mm = (72/101.6)pt */
case CSS_UNIT_Q: return FMUL(length,
FDIV(F_72, FLTTOFIX(101.6)));
case CSS_UNIT_PT: return length;
/* 1pc = 12pt */
case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12));
case CSS_UNIT_VH: return FDIV(FMUL(FDIV(FMUL(length, ctx->vh), F_100), F_72), F_96);
case CSS_UNIT_VW: return FDIV(FMUL(FDIV(FMUL(length,ctx->vw), F_100), F_72), F_96);
default: break;
}
return 0;
}
/* exported interface documented in content/handlers/css/utils.h */
css_fixed nscss_len2px(
const nscss_len_ctx *ctx,
css_fixed length,
css_unit unit,
const css_computed_style *style)
{
/* We assume the screen and any other output has the same dpi */
css_fixed px_per_unit;
unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
case CSS_UNIT_EM:
case CSS_UNIT_EX:
case CSS_UNIT_CAP:
case CSS_UNIT_CH:
case CSS_UNIT_IC:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
assert(style != NULL);
css_computed_font_size(style, &font_size, &font_unit);
/* Convert to points */
font_size = nscss_len2pt(ctx, font_size, font_unit);
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10);
}
/* Convert to pixels (manually, to maximise precision)
* 1in = 72pt => 1pt = (DPI/72)px */
px_per_unit = FDIV(FMUL(font_size, F_96), F_72);
/* Scale non-em units to em. We have fixed ratios. */
switch (unit) {
case CSS_UNIT_EX:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
break;
case CSS_UNIT_CAP:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.9));
break;
case CSS_UNIT_CH:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4));
break;
case CSS_UNIT_IC:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(1.1));
break;
default: break;
}
}
break;
case CSS_UNIT_PX:
px_per_unit = F_1;
break;
/* 1in = 96 CSS pixels */
case CSS_UNIT_IN:
px_per_unit = F_96;
break;
/* 1in = 2.54cm => 1cm = (DPI/2.54)px */
case CSS_UNIT_CM:
px_per_unit = FDIV(F_96, FLTTOFIX(2.54));
break;
/* 1in = 25.4mm => 1mm = (DPI/25.4)px */
case CSS_UNIT_MM:
px_per_unit = FDIV(F_96, FLTTOFIX(25.4));
break;
/* 1in = 101.6q => 1q = (DPI/101.6)px */
case CSS_UNIT_Q:
px_per_unit = FDIV(F_96, FLTTOFIX(101.6));
break;
/* 1in = 72pt => 1pt = (DPI/72)px */
case CSS_UNIT_PT:
px_per_unit = FDIV(F_96, F_72);
break;
/* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */
case CSS_UNIT_PC:
px_per_unit = FDIV(F_96, INTTOFIX(6));
break;
case CSS_UNIT_REM:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
assert(ctx->root_style != NULL);
css_computed_font_size(ctx->root_style,
&font_size, &font_unit);
/* Convert to points */
font_size = nscss_len2pt(ctx, font_size, font_unit);
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10);
}
/* Convert to pixels (manually, to maximise precision)
* 1in = 72pt => 1pt = (DPI/72)px */
px_per_unit = FDIV(FMUL(font_size, F_96), F_72);
break;
}
/* 1rlh = <user_font_size>pt => 1rlh = (DPI/user_font_size)px */
case CSS_UNIT_RLH:
px_per_unit = FDIV(F_96, FDIV(
INTTOFIX(nsoption_int(font_size)),
INTTOFIX(10)));
break;
case CSS_UNIT_VH:
px_per_unit = FDIV(ctx->vh, F_100);
break;
case CSS_UNIT_VW:
px_per_unit = FDIV(ctx->vw, F_100);
break;
default:
px_per_unit = 0;
break;
}
px_per_unit = nscss_pixels_css_to_physical(px_per_unit);
/* Ensure we round px_per_unit to the nearest whole number of pixels:
* the use of FIXTOINT() below will truncate. */
px_per_unit += F_0_5;
/* Calculate total number of pixels */
return FMUL(length, TRUNCATEFIX(px_per_unit));
}

176
src/document/css2/utils.h Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* 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/>.
*/
#ifndef NETSURF_CSS_UTILS_H_
#define NETSURF_CSS_UTILS_H_
#include <libcss/libcss.h>
#include "netsurf/css.h"
/** DPI of the screen, in fixed point units */
extern css_fixed nscss_screen_dpi;
/** Medium screen density for device viewing distance. */
extern css_fixed nscss_baseline_pixel_density;
/**
* Length conversion context data.
*/
typedef struct nscss_len_ctx {
/**
* Viewport width in px.
* Only used if unit is vh, vw, vi, vb, vmin, or vmax.
*/
int vw;
/**
* Viewport height in px.
* Only used if unit is vh, vw, vi, vb, vmin, or vmax.
*/
int vh;
/**
* Computed style for the document root element.
* May be NULL if unit is not rem, or rlh.
*/
const css_computed_style *root_style;
} nscss_len_ctx;
/**
* Convert an absolute CSS length to points.
*
* \param[in] ctx Length conversion context.
* \param[in] length Absolute CSS length.
* \param[in] unit Unit of the length.
* \return length in points
*/
css_fixed nscss_len2pt(
const nscss_len_ctx *ctx,
css_fixed length,
css_unit unit);
/**
* Convert a CSS length to pixels.
*
* \param[in] ctx Length conversion context.
* \param[in] length Length to convert.
* \param[in] unit Corresponding unit.
* \param[in] style Computed style applying to length.
* May be NULL if unit is not em, ex, cap, ch, or ic.
* \return length in pixels
*/
css_fixed nscss_len2px(
const nscss_len_ctx *ctx,
css_fixed length,
css_unit unit,
const css_computed_style *style);
/**
* Convert css pixels to physical pixels.
*
* \param[in] css_pixels Length in css pixels.
* \return length in physical pixels
*/
static inline css_fixed nscss_pixels_css_to_physical(
css_fixed css_pixels)
{
return FDIV(FMUL(css_pixels, nscss_screen_dpi),
nscss_baseline_pixel_density);
}
/**
* Convert physical pixels to css pixels.
*
* \param[in] physical_pixels Length in physical pixels.
* \return length in css pixels
*/
static inline css_fixed nscss_pixels_physical_to_css(
css_fixed physical_pixels)
{
return FDIV(FMUL(physical_pixels, nscss_baseline_pixel_density),
nscss_screen_dpi);
}
/**
* Temporary helper wrappers for for libcss computed style getter, while
* we don't support flexbox related property values.
*/
static inline uint8_t ns_computed_display(
const css_computed_style *style, bool root)
{
uint8_t value = css_computed_display(style, root);
if (value == CSS_DISPLAY_FLEX) {
return CSS_DISPLAY_BLOCK;
} else if (value == CSS_DISPLAY_INLINE_FLEX) {
return CSS_DISPLAY_INLINE_BLOCK;
}
return value;
}
static inline uint8_t ns_computed_display_static(
const css_computed_style *style)
{
uint8_t value = css_computed_display_static(style);
if (value == CSS_DISPLAY_FLEX) {
return CSS_DISPLAY_BLOCK;
} else if (value == CSS_DISPLAY_INLINE_FLEX) {
return CSS_DISPLAY_INLINE_BLOCK;
}
return value;
}
static inline uint8_t ns_computed_min_height(
const css_computed_style *style,
css_fixed *length, css_unit *unit)
{
uint8_t value = css_computed_min_height(style, length, unit);
if (value == CSS_MIN_HEIGHT_AUTO) {
value = CSS_MIN_HEIGHT_SET;
*length = 0;
*unit = CSS_UNIT_PX;
}
return value;
}
static inline uint8_t ns_computed_min_width(
const css_computed_style *style,
css_fixed *length, css_unit *unit)
{
uint8_t value = css_computed_min_width(style, length, unit);
if (value == CSS_MIN_WIDTH_AUTO) {
value = CSS_MIN_WIDTH_SET;
*length = 0;
*unit = CSS_UNIT_PX;
}
return value;
}
#endif

View File

@ -1,4 +1,3 @@
#ifndef EL__DOCUMENT_HTML_INTERNAL_H #ifndef EL__DOCUMENT_HTML_INTERNAL_H
#define EL__DOCUMENT_HTML_INTERNAL_H #define EL__DOCUMENT_HTML_INTERNAL_H
@ -6,10 +5,17 @@
#include "document/html/parser.h" #include "document/html/parser.h"
#include "util/lists.h" #include "util/lists.h"
#ifdef CONFIG_LIBCSS
#undef restrict
#define restrict __restrict
#include <libcss/libcss.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct document;
struct document_options; struct document_options;
struct uri; struct uri;
@ -40,14 +46,38 @@ enum html_whitespace_state {
HTML_SPACE_ADD, HTML_SPACE_ADD,
}; };
#ifdef CONFIG_LIBCSS
typedef struct nscss_select_ctx
{
css_select_ctx *ctx;
bool quirks;
struct nsurl *base_url;
lwc_string *universal;
const css_computed_style *root_style;
const css_computed_style *parent_style;
} nscss_select_ctx;
struct el_sheet {
LIST_HEAD(struct el_sheet);
css_stylesheet *sheet;
};
#endif
struct html_context { struct html_context {
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
struct document *document;
LIST_OF(struct el_sheet) sheets;
css_select_ctx *select_ctx;
/* The default stylesheet is initially merged into it. When parsing CSS /* The default stylesheet is initially merged into it. When parsing CSS
* from <style>-tags and external stylesheets if enabled is merged * from <style>-tags and external stylesheets if enabled is merged
* added to it. */ * added to it. */
#endif
struct css_stylesheet css_styles; struct css_stylesheet css_styles;
#endif #endif
/* These are global per-document base values, alterable by the <base> /* These are global per-document base values, alterable by the <base>
* element. */ * element. */
struct uri *base_href; struct uri *base_href;
@ -139,7 +169,7 @@ struct html_context {
#define html_top ((struct html_element *) html_context->stack.next) #define html_top ((struct html_element *) html_context->stack.next)
#define html_bottom ((struct html_element *) html_context->stack.prev) #define html_bottom ((struct html_element *) html_context->stack.prev)
#define elformat (html_top->attr) #define elformat (html_top->attr)
#define par_elformat (html_top->parattr) #define par_elformat (html_top->parattr)
#define html_is_preformatted() (elformat.style.attr & AT_PREFORMATTED) #define html_is_preformatted() (elformat.style.attr & AT_PREFORMATTED)
@ -153,10 +183,14 @@ void html_focusable(struct html_context *html_context, char *a);
void html_skip(struct html_context *html_context, char *a); void html_skip(struct html_context *html_context, char *a);
char *get_target(struct document_options *options, char *a); char *get_target(struct document_options *options, char *a);
void void import_css_stylesheet(struct css_stylesheet *css, struct uri *base_uri,
import_css_stylesheet(struct css_stylesheet *css, struct uri *base_uri,
const char *unterminated_url, int len); const char *unterminated_url, int len);
#ifdef CONFIG_LIBCSS
void import_css2_stylesheet(struct html_context *, struct uri *base_uri,
const char *unterminated_url, int len);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -49,6 +49,11 @@
/* Unsafe macros */ /* Unsafe macros */
#include "document/html/internal.h" #include "document/html/internal.h"
#ifdef CONFIG_LIBCSS
#include <libcss/libcss.h>
#include "document/css2/css.h"
#endif
/* TODO: This needs rewrite. Yes, no kidding. */ /* TODO: This needs rewrite. Yes, no kidding. */
static int static int
@ -201,6 +206,48 @@ add_fragment_identifier(struct html_context *html_context,
} }
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
void
import_css2_stylesheet(struct html_context *html_context, struct uri *base_uri, const char *unterminated_url, int len)
{
char *url;
char *import_url;
struct uri *uri;
assert(html_context);
assert(base_uri);
if (!html_context->options->css_enable
|| !html_context->options->css_import)
return;
/* unterminated_url might not end with '\0', but join_urls
* requires that, so make a copy. */
url = memacpy(unterminated_url, len);
if (!url) return;
/* HTML <head> urls should already be fine but we can.t detect them. */
import_url = join_urls(base_uri, url);
mem_free(url);
if (!import_url) return;
uri = get_uri(import_url, URI_BASE);
mem_free(import_url);
if (!uri) return;
/* Request the imported stylesheet as part of the document ... */
html_context->special_f(html_context, SP_STYLESHEET, uri);
/* ... and then attempt to import from the cache. */
import_css2(html_context, uri);
done_uri(uri);
}
#endif
void void
import_css_stylesheet(struct css_stylesheet *css, struct uri *base_uri, import_css_stylesheet(struct css_stylesheet *css, struct uri *base_uri,
const char *unterminated_url, int len) const char *unterminated_url, int len)
@ -758,7 +805,7 @@ done_html_parser_state(struct html_context *html_context,
* The title of the document. This is in the document charset, * The title of the document. This is in the document charset,
* and entities have not been decoded. */ * and entities have not been decoded. */
struct html_context * struct html_context *
init_html_parser(struct uri *uri, struct document_options *options, init_html_parser(struct uri *uri, struct document *document,
char *start, char *end, char *start, char *end,
struct string *head, struct string *title, struct string *head, struct string *title,
void (*put_chars)(struct html_context *, const char *, int), void (*put_chars)(struct html_context *, const char *, int),
@ -767,6 +814,7 @@ init_html_parser(struct uri *uri, struct document_options *options,
{ {
struct html_context *html_context; struct html_context *html_context;
struct html_element *e; struct html_element *e;
struct document_options *options = &document->options;
assert(uri && options); assert(uri && options);
if_assert_failed return NULL; if_assert_failed return NULL;
@ -775,6 +823,9 @@ init_html_parser(struct uri *uri, struct document_options *options,
if (!html_context) return NULL; if (!html_context) return NULL;
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
html_context->document = document;
#endif
html_context->css_styles.import = import_css_stylesheet; html_context->css_styles.import = import_css_stylesheet;
init_css_selector_set(&html_context->css_styles.selectors); init_css_selector_set(&html_context->css_styles.selectors);
#endif #endif
@ -832,7 +883,7 @@ init_html_parser(struct uri *uri, struct document_options *options,
html_top->invisible = 0; html_top->invisible = 0;
html_top->name = NULL; html_top->name = NULL;
html_top->namelen = 0; html_top->namelen = 0;
html_top->options = NULL; html_top->options = NULL;
html_top->linebreak = 1; html_top->linebreak = 1;
html_top->type = ELEMENT_DONT_KILL; html_top->type = ELEMENT_DONT_KILL;
@ -841,11 +892,27 @@ init_html_parser(struct uri *uri, struct document_options *options,
html_context->table_level = 0; html_context->table_level = 0;
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
html_context->css_styles.import_data = html_context; #ifdef CONFIG_LIBCSS
if (options->libcss_enable) {
if (options->css_enable) {
css_error code;
if (options->css_enable) init_list(html_context->sheets);
mirror_css_stylesheet(&default_stylesheet, /* prepare a selection context containing the stylesheet */
&html_context->css_styles); code = css_select_ctx_create(&html_context->select_ctx);
if (code != CSS_OK) {
//fprintf(stderr, "css_select_ctx_create code=%d\n", code);
}
}
} else
#endif
do {
html_context->css_styles.import_data = html_context;
if (options->css_enable)
mirror_css_stylesheet(&default_stylesheet,
&html_context->css_styles);
} while (0);
#endif #endif
return html_context; return html_context;
@ -855,10 +922,23 @@ void
done_html_parser(struct html_context *html_context) done_html_parser(struct html_context *html_context)
{ {
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
if (html_context->options->css_enable) #ifdef CONFIG_LIBCSS
done_css_stylesheet(&html_context->css_styles); if (html_context->options->libcss_enable) {
if (html_context->options->css_enable) {
struct el_sheet *el;
css_error code = css_select_ctx_destroy(html_context->select_ctx);
foreach (el, html_context->sheets) {
code = css_stylesheet_destroy(el->sheet);
}
free_list(html_context->sheets);
}
} else
#endif
do {
if (html_context->options->css_enable)
done_css_stylesheet(&html_context->css_styles);
} while (0);
#endif #endif
mem_free(html_context->base_target); mem_free(html_context->base_target);
done_uri(html_context->base_href); done_uri(html_context->base_href);

View File

@ -14,6 +14,7 @@
extern "C" { extern "C" {
#endif #endif
struct document;
struct document_options; struct document_options;
struct el_form_control; struct el_form_control;
struct frameset_desc; struct frameset_desc;
@ -178,7 +179,7 @@ struct html_element {
/* Interface for the renderer */ /* Interface for the renderer */
struct html_context * struct html_context *
init_html_parser(struct uri *uri, struct document_options *options, init_html_parser(struct uri *uri, struct document *document,
char *start, char *end, char *start, char *end,
struct string *head, struct string *title, struct string *head, struct string *title,
void (*put_chars)(struct html_context *, const char *, int), void (*put_chars)(struct html_context *, const char *, int),

View File

@ -186,11 +186,16 @@ void
html_apply_canvas_bgcolor(struct html_context *html_context) html_apply_canvas_bgcolor(struct html_context *html_context)
{ {
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
if (!html_context->options->libcss_enable)
#endif
/* If there are any CSS twaks regarding bgcolor, make sure we will get /* If there are any CSS twaks regarding bgcolor, make sure we will get
* it _and_ prefer it over bgcolor attribute. */ * it _and_ prefer it over bgcolor attribute. */
do {
if (html_context->options->css_enable) if (html_context->options->css_enable)
css_apply(html_context, html_top, &html_context->css_styles, css_apply(html_context, html_top, &html_context->css_styles,
&html_context->stack); &html_context->stack);
} while (0);
#endif #endif
if (par_elformat.color.background != elformat.style.color.background) { if (par_elformat.color.background != elformat.style.color.background) {

View File

@ -923,15 +923,29 @@ html_link(struct html_context *html_context, char *a,
if (!link.href) goto free_and_return; if (!link.href) goto free_and_return;
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
if (link.type == LT_STYLESHEET #ifdef CONFIG_LIBCSS
&& supports_html_media_attr(link.media)) { if (html_context->options->libcss_enable) {
int len = strlen(link.href); if (link.type == LT_STYLESHEET
&& supports_html_media_attr(link.media)) {
int len = strlen(link.href);
import_css_stylesheet(&html_context->css_styles, import_css2_stylesheet(html_context, html_context->base_href, link.href, len);
html_context->base_href, link.href, len); }
}
if (!link_display) goto free_and_return; if (!link_display) goto free_and_return;
} else
#endif
do {
if (link.type == LT_STYLESHEET
&& supports_html_media_attr(link.media)) {
int len = strlen(link.href);
import_css_stylesheet(&html_context->css_styles,
html_context->base_href, link.href, len);
}
if (!link_display) goto free_and_return;
} while (0);
#endif #endif
/* Ignore few annoying links.. */ /* Ignore few annoying links.. */

View File

@ -16,6 +16,9 @@
#include "document/css/apply.h" #include "document/css/apply.h"
#include "document/css/css.h" #include "document/css/css.h"
#include "document/css/parser.h" #include "document/css/parser.h"
#ifdef CONFIG_LIBCSS
#include "document/css2/css.h"
#endif
#include "document/html/parser/forms.h" #include "document/html/parser/forms.h"
#include "document/html/parser/general.h" #include "document/html/parser/general.h"
#include "document/html/parser/link.h" #include "document/html/parser/link.h"
@ -896,17 +899,31 @@ start_element(struct element_info *ei,
/* If this is a style tag, parse it. */ /* If this is a style tag, parse it. */
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
if (ei->open == html_style && html_context->options->css_enable) { #ifdef CONFIG_LIBCSS
char *media if (html_context->options->libcss_enable) {
= get_attr_val(attr, "media", html_context->doc_cp); if (ei->open == html_style && html_context->options->css_enable) {
int support = supports_html_media_attr(media); char *media = get_attr_val(attr, "media", html_context->doc_cp);
mem_free_if(media); int support = supports_html_media_attr(media);
mem_free_if(media);
if (support) if (support) {
css_parse_stylesheet(&html_context->css_styles, parse_css(html_context, name);
html_context->base_href, }
html, eof); }
} } else
#endif
do {
if (ei->open == html_style && html_context->options->css_enable) {
char *media = get_attr_val(attr, "media", html_context->doc_cp);
int support = supports_html_media_attr(media);
mem_free_if(media);
if (support)
css_parse_stylesheet(&html_context->css_styles,
html_context->base_href,
html, eof);
}
} while (0);
#endif #endif
/* If this element is inline, non-nestable, and not <li>, and the next /* If this element is inline, non-nestable, and not <li>, and the next
@ -977,31 +994,40 @@ start_element(struct element_info *ei,
/* Apply CSS styles. */ /* Apply CSS styles. */
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
if (html_top->options && html_context->options->css_enable) { #ifdef CONFIG_LIBCSS
/* XXX: We should apply CSS otherwise as well, but that'll need if (html_context->options->libcss_enable) {
* some deeper changes in order to have options filled etc. if (html_context->options->css_enable) {
* Probably just applying CSS from more places, since we select_css(html_context, html_top);
* usually have type != ET_NESTABLE when we either (1) }
* rescan on your own from somewhere else (2) html_stack_dup() } else
* in our own way. --pasky */ #endif
mem_free_set(&html_top->attr.id, do {
get_attr_val(attr, "id", html_context->doc_cp)); if (html_top->options && html_context->options->css_enable) {
mem_free_set(&html_top->attr.class_, /* XXX: We should apply CSS otherwise as well, but that'll need
get_attr_val(attr, "class", html_context->doc_cp)); * some deeper changes in order to have options filled etc.
/* Call it now to gain some of the stuff which might affect * Probably just applying CSS from more places, since we
* formatting of some elements. */ * usually have type != ET_NESTABLE when we either (1)
/* FIXME: The caching of the CSS selector is broken, since t can * rescan on your own from somewhere else (2) html_stack_dup()
* lead to wrong styles being applied to following elements, so * in our own way. --pasky */
* disabled for now. */ mem_free_set(&html_top->attr.id,
selector = get_css_selector_for_element(html_context, html_top, get_attr_val(attr, "id", html_context->doc_cp));
mem_free_set(&html_top->attr.class_,
get_attr_val(attr, "class", html_context->doc_cp));
/* Call it now to gain some of the stuff which might affect
* formatting of some elements. */
/* FIXME: The caching of the CSS selector is broken, since t can
* lead to wrong styles being applied to following elements, so
* disabled for now. */
selector = get_css_selector_for_element(html_context, html_top,
&html_context->css_styles, &html_context->css_styles,
&html_context->stack); &html_context->stack);
if (selector) { if (selector) {
apply_css_selector_style(html_context, html_top, selector); apply_css_selector_style(html_context, html_top, selector);
done_css_selector(selector); done_css_selector(selector);
}
} }
} } while (0);
#endif #endif
/* 1. Put any linebreaks that the element calls for, and 2. register /* 1. Put any linebreaks that the element calls for, and 2. register
@ -1019,17 +1045,26 @@ start_element(struct element_info *ei,
/* Apply CSS styles again. */ /* Apply CSS styles again. */
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
if (selector && html_top->options) { #ifdef CONFIG_LIBCSS
/* Call it now to override default colors of the elements. */ if (html_context->options->libcss_enable) {
selector = get_css_selector_for_element(html_context, html_top, if (html_context->options->css_enable) {
select_css(html_context, html_top);
}
} else
#endif
do {
if (selector && html_top->options) {
/* Call it now to override default colors of the elements. */
selector = get_css_selector_for_element(html_context, html_top,
&html_context->css_styles, &html_context->css_styles,
&html_context->stack); &html_context->stack);
if (selector) { if (selector) {
apply_css_selector_style(html_context, html_top, selector); apply_css_selector_style(html_context, html_top, selector);
done_css_selector(selector); done_css_selector(selector);
}
} }
} } while (0);
#endif #endif
/* If this element was not <br>, clear the was_br flag. */ /* If this element was not <br>, clear the was_br flag. */

View File

@ -1,4 +1,3 @@
#ifndef EL__DOCUMENT_HTML_PARSER_PARSE_H #ifndef EL__DOCUMENT_HTML_PARSER_PARSE_H
#define EL__DOCUMENT_HTML_PARSER_PARSE_H #define EL__DOCUMENT_HTML_PARSER_PARSE_H

View File

@ -2597,7 +2597,7 @@ render_html_document(struct cache_entry *cached, struct document *document,
start = buffer->source; start = buffer->source;
end = buffer->source + buffer->length; end = buffer->source + buffer->length;
html_context = init_html_parser(cached->uri, &document->options, html_context = init_html_parser(cached->uri, document,
start, end, &head, &title, start, end, &head, &title,
put_chars_conv, line_break, put_chars_conv, line_break,
html_special); html_special);

View File

@ -1,6 +1,9 @@
if conf_data.get('CONFIG_CSS') if conf_data.get('CONFIG_CSS')
subdir('css') subdir('css')
endif endif
if conf_data.get('CONFIG_LIBCSS')
subdir('css2')
endif
if conf_data.get('CONFIG_DOM') if conf_data.get('CONFIG_DOM')
subdir('dom') subdir('dom')
endif endif

View File

@ -75,6 +75,9 @@ init_document_options(struct session *ses, struct document_options *doo)
/* Boolean options. */ /* Boolean options. */
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
doo->libcss_enable = get_opt_bool("document.css.libcss", ses);
#endif
doo->css_enable = get_opt_bool("document.css.enable", ses); doo->css_enable = get_opt_bool("document.css.enable", ses);
doo->css_ignore_display_none = get_opt_bool("document.css.ignore_display_none", ses); doo->css_ignore_display_none = get_opt_bool("document.css.ignore_display_none", ses);
doo->css_import = get_opt_bool("document.css.import", ses); doo->css_import = get_opt_bool("document.css.import", ses);

View File

@ -76,6 +76,9 @@ struct document_options {
/* XXX: Keep boolean options grouped to save padding */ /* XXX: Keep boolean options grouped to save padding */
#ifdef CONFIG_CSS #ifdef CONFIG_CSS
#ifdef CONFIG_LIBCSS
unsigned int libcss_enable:1;
#endif
/** @name CSS stuff /** @name CSS stuff
* @{ */ * @{ */
unsigned int css_enable:1; unsigned int css_enable:1;

View File

@ -41,234 +41,6 @@
#include <map> #include <map>
#if 0
static void
dump_text(struct source_renderer *renderer, unsigned char *html, int length)
{
struct html_context *html_context = renderer->html_context;
unsigned char *eof = html + length;
unsigned char *base_pos = html;
if (length > 0 && (eof[-1] == '\n')) {
length--;
eof--;
}
#ifdef CONFIG_CSS
if (html_context->was_style) {
/// css_parse_stylesheet(&html_context->css_styles, html_context->base_href, html, eof);
return;
}
#endif
//fprintf(stderr, "html='%s'\n", html);
if (length <= 0) {
return;
}
int noupdate = 0;
main_loop:
while (html < eof) {
char *name, *attr, *end;
int namelen, endingtag;
int dotcounter = 0;
if (!noupdate) {
html_context->part = renderer->part;
html_context->eoff = eof;
base_pos = html;
} else {
noupdate = 0;
}
if (isspace((unsigned char)*html) && !html_is_preformatted()) {
char *h = html;
while (h < eof && isspace((unsigned char)*h))
h++;
if (h + 1 < eof && h[0] == '<' && h[1] == '/') {
if (!parse_element(h, eof, &name, &namelen, &attr, &end)) {
put_chrs(html_context, base_pos, html - base_pos);
base_pos = html = h;
html_context->putsp = HTML_SPACE_ADD;
goto element;
}
}
html++;
if (!(html_context->position + (html - base_pos - 1)))
goto skip_w; /* ??? */
if (*(html - 1) == ' ') { /* Do not replace with isspace((unsigned char)) ! --Zas */
/* BIG performance win; not sure if it doesn't cause any bug */
if (html < eof && !isspace((unsigned char)*html)) {
noupdate = 1;
continue;
}
put_chrs(html_context, base_pos, html - base_pos);
} else {
put_chrs(html_context, base_pos, html - base_pos - 1);
put_chrs(html_context, " ", 1);
}
skip_w:
while (html < eof && isspace((unsigned char)*html))
html++;
continue;
}
if (html_is_preformatted()) {
html_context->putsp = HTML_SPACE_NORMAL;
if (*html == ASCII_TAB) {
put_chrs(html_context, base_pos, html - base_pos);
put_chrs(html_context, " ",
8 - (html_context->position % 8));
html++;
continue;
} else if (*html == ASCII_CR || *html == ASCII_LF) {
put_chrs(html_context, base_pos, html - base_pos);
if (html - base_pos == 0 && html_context->line_breax > 0)
html_context->line_breax--;
next_break:
if (*html == ASCII_CR && html < eof - 1
&& html[1] == ASCII_LF)
html++;
ln_break(html_context, 1);
html++;
if (*html == ASCII_CR || *html == ASCII_LF) {
html_context->line_breax = 0;
goto next_break;
}
continue;
} else if (html + 5 < eof && *html == '&') {
/* Really nasty hack to make &#13; handling in
* <pre>-tags lynx-compatible. It works around
* the entity handling done in the renderer,
* since checking #13 value there would require
* something along the lines of NBSP_CHAR or
* checking for '\n's in AT_PREFORMATTED text. */
/* See bug 52 and 387 for more info. */
int length = html - base_pos;
int newlines;
html = (char *) count_newline_entities(html, eof, &newlines);
if (newlines) {
put_chrs(html_context, base_pos, length);
ln_break(html_context, newlines);
continue;
}
}
}
while ((unsigned char)*html < ' ') {
if (html - base_pos)
put_chrs(html_context, base_pos, html - base_pos);
dotcounter++;
base_pos = ++html;
if (*html >= ' ' || isspace((unsigned char)*html) || html >= eof) {
char *dots = (char *)fmem_alloc(dotcounter);
if (dots) {
memset(dots, '.', dotcounter);
put_chrs(html_context, dots, dotcounter);
fmem_free(dots);
}
goto main_loop;
}
}
if (html + 2 <= eof && html[0] == '<' && (html[1] == '!' || html[1] == '?')
&& !(html_context->was_xmp || html_context->was_style)) {
put_chrs(html_context, base_pos, html - base_pos);
html = skip_comment(html, eof);
continue;
}
if (*html != '<' || parse_element(html, eof, &name, &namelen, &attr, &end)) {
html++;
noupdate = 1;
continue;
}
element:
endingtag = *name == '/'; name += endingtag; namelen -= endingtag;
if (!endingtag && html_context->putsp == HTML_SPACE_ADD && !html_top->invisible)
put_chrs(html_context, " ", 1);
put_chrs(html_context, base_pos, html - base_pos);
if (!html_is_preformatted() && !endingtag && html_context->putsp == HTML_SPACE_NORMAL) {
char *ee = end;
char *nm;
/// while (!parse_element(ee, eof, &nm, NULL, NULL, &ee))
/// if (*nm == '/')
/// goto ng;
if (ee < eof && isspace((unsigned char)*ee)) {
put_chrs(html_context, " ", 1);
}
}
//ng:
// html = process_element(name, namelen, endingtag, end, html, eof, attr, html_context);
}
if (noupdate) put_chrs(html_context, base_pos, html - base_pos);
//ln_break(html_context, 1);
/* Restore the part in case the html_context was trashed in the last
* iteration so that when destroying the stack in the caller we still
* get the right part pointer. */
html_context->part = renderer->part;
html_context->putsp = HTML_SPACE_SUPPRESS;
html_context->position = 0;
html_context->was_br = 0;
}
#define HTML_MAX_DOM_STRUCTURE_DEPTH 1024
bool
dump_dom_structure(struct source_renderer *renderer, void *nod, int depth)
{
xmlpp::Node *node = nod;
if (depth >= HTML_MAX_DOM_STRUCTURE_DEPTH) {
return false;
}
xmlpp::ustring tag_name = node->get_name();
struct element_info2 *ei = get_tag_value(tag_name.c_str(), tag_name.size());
if (!ei) return true;
start_element_2(ei, renderer, node);
/* Get the node's first child */
auto children = node->get_children();
auto it = children.begin();
auto end = children.end();
for (;it != end; ++it) {
xmlpp::Element *el = dynamic_cast<xmlpp::Element *>(*it);
if (el) {
dump_dom_structure(renderer, el, depth + 1);
} else {
xmlpp::TextNode *text = dynamic_cast<xmlpp::TextNode *>(*it);
if (text) {
if (renderer->html_context->skip_select || renderer->html_context->skip_textarea) continue;
xmlpp::ustring v = text->get_content();
dump_text(renderer, v.c_str(), v.size());
}
}
}
end_element_2(ei, renderer, node);
/*
if (ei && ei->close) {
ei->close(renderer, node, NULL, NULL, NULL, NULL);
}
*/
return true;
}
#endif
static void static void
dump_element(std::map<int, xmlpp::Element *> *mapa, struct string *buf, xmlpp::Element *element) dump_element(std::map<int, xmlpp::Element *> *mapa, struct string *buf, xmlpp::Element *element)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -13,5 +13,5 @@
</style> </style>
<style>) I, love, garbage { dont: you? } </style> <style>) I, love, garbage { dont: you? } </style>
<a href="foo" style="color:">no value</a> <a href="foo" style="color:">no value</a>
<div style="{background:#fff}">white bg</div> <div style="background:#fff">white bg</div>
<p>should become red when we start supporting escaping of string delimiters</p> <p>should become red when we start supporting escaping of string delimiters</p>