diff --git a/src/document/libdom/css.c b/src/document/libdom/css.c index c50c22ae..cbecef0e 100644 --- a/src/document/libdom/css.c +++ b/src/document/libdom/css.c @@ -97,7 +97,11 @@ static css_error node_presentational_hint(void *pw, void *node, return CSS_OK; } - +static css_error +resolve_url_empty(void *pw, const char *base, lwc_string *rel, lwc_string **abs) +{ + return CSS_OK; +} css_error resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) @@ -2309,3 +2313,122 @@ import_css2(struct html_context *html_context, struct uri *uri) // css->import_level--; } } + +void * +el_match_selector(const char *selector, void *node) +{ + struct string text; + css_error code; + size_t size; + uint32_t count; + css_stylesheet_params params; + css_stylesheet *sheet = NULL; + css_select_ctx *select_ctx = NULL; + css_select_results *style = NULL; + uint8_t color_type; + css_color color_shade; + + css_media media = { + .type = CSS_MEDIA_SCREEN, + }; + + css_unit_ctx unit_len_ctx = {0}; + unit_len_ctx.viewport_width = 800; // TODO + unit_len_ctx.viewport_height = 600; // TODO + unit_len_ctx.device_dpi = F_90; //device_dpi; + + /** \todo Change nsoption font sizes to px. */ +/// f_size = FDIV(FMUL(F_96, FDIV(INTTOFIX(nsoption_int(font_size)), F_10)), F_72); +/// f_min = FDIV(FMUL(F_96, FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)), F_72); + + unsigned int f_size = FDIV(FMUL(F_96, FDIV(INTTOFIX(50), F_10)), F_72); // TODO + unsigned int f_min = FDIV(FMUL(F_96, FDIV(INTTOFIX(50), F_10)), F_72); // TODO + + unit_len_ctx.font_size_default = f_size; + unit_len_ctx.font_size_minimum = f_min; + void *ret = NULL; + + params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; + params.level = CSS_LEVEL_21; + params.charset = "UTF-8"; + params.url = "foo"; + params.title = "foo"; + params.allow_quirks = false; + params.inline_style = false; + params.resolve = resolve_url_empty; + params.resolve_pw = NULL; + params.import = NULL; + params.import_pw = NULL; + params.color = NULL; + params.color_pw = NULL; + params.font = NULL; + params.font_pw = NULL; + + if (!selector) { + return NULL; + } + if (!init_string(&text)) { + return NULL; + } + add_to_string(&text, selector); + add_to_string(&text, "{color:#123456}"); + + /* create a stylesheet */ + code = css_stylesheet_create(¶ms, &sheet); + + if (code != CSS_OK) { + goto empty; + } + code = css_stylesheet_append_data(sheet, (const uint8_t *) text.source, text.length); + + if (code != CSS_OK && code != CSS_NEEDDATA) { + goto empty; + } + code = css_stylesheet_data_done(sheet); + if (code != CSS_OK) { + goto empty; + } + code = css_stylesheet_size(sheet, &size); + + /* prepare a selection context containing the stylesheet */ + code = css_select_ctx_create(&select_ctx); + + if (code != CSS_OK) { + goto empty; + } + code = css_select_ctx_append_sheet(select_ctx, sheet, CSS_ORIGIN_AUTHOR, NULL); + + if (code != CSS_OK) { + goto empty; + } + code = css_select_ctx_count_sheets(select_ctx, &count); + + if (code != CSS_OK) { + goto empty; + } + code = css_select_style(select_ctx, node, &unit_len_ctx, &media, NULL, &selection_handler, 0, &style); + + if (code != CSS_OK) { + goto empty; + } + + color_type = css_computed_color(style->styles[CSS_PSEUDO_ELEMENT_NONE], &color_shade); + + if (color_type && color_shade == 0xff123456) { + ret = node; + } + +empty: + if (style) { + css_select_results_destroy(style); + } + if (select_ctx) { + css_select_ctx_destroy(select_ctx); + } + if (sheet) { + css_stylesheet_destroy(sheet); + } + done_string(&text); + + return ret; +} diff --git a/src/document/libdom/doc.h b/src/document/libdom/doc.h index 056a2f19..d63f8044 100644 --- a/src/document/libdom/doc.h +++ b/src/document/libdom/doc.h @@ -11,6 +11,7 @@ struct string; void *document_parse_text(const char *charset, char *data, size_t length); void *document_parse(struct document *document, struct string *source); void free_document(void *doc); +void *el_match_selector(const char *selector, void *node); #ifdef __cplusplus } diff --git a/src/ecmascript/spidermonkey/document.cpp b/src/ecmascript/spidermonkey/document.cpp index 92aaeb7f..5c379727 100644 --- a/src/ecmascript/spidermonkey/document.cpp +++ b/src/ecmascript/spidermonkey/document.cpp @@ -1819,6 +1819,62 @@ document_getElementsByTagName(JSContext *ctx, unsigned int argc, JS::Value *vp) return true; } +void * +walk_tree_query(dom_node *node, char *selector, int depth) +{ + dom_exception exc; + dom_node *child; + void *res = NULL; + dom_node_type typ; + + /* Only interested in element nodes */ + exc = dom_node_get_node_type(node, &typ); + if (typ != DOM_ELEMENT_NODE) { + return NULL; + } + + if (res = el_match_selector(selector, node)) { + /* There was an error; return */ + return res; + } + /* Get the node's first child */ + exc = dom_node_get_first_child(node, &child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_first_child\n"); + return NULL; + } else if (child != NULL) { + /* node has children; decend to children's depth */ + depth++; + + /* Loop though all node's children */ + do { + dom_node *next_child; + + /* Visit node's descendents */ + res = walk_tree_query(child, selector, depth); + /* There was an error; return */ + if (res) { + dom_node_unref(child); + return res; + } + + /* Go to next sibling */ + exc = dom_node_get_next_sibling(child, &next_child); + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for " + "node_get_next_sibling\n"); + dom_node_unref(child); + return NULL; + } + + dom_node_unref(child); + child = next_child; + } while (child != NULL); /* No more children */ + } + return NULL; +} + static bool document_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp) { @@ -1841,8 +1897,31 @@ document_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp) args.rval().setNull(); return true; } -// TODO - args.rval().setNull(); + dom_node *root = NULL; /* root element of document */ + /* Get root element */ + dom_exception exc = dom_document_get_document_element(document->dom, &root); + + if (exc != DOM_NO_ERR) { + args.rval().setNull(); + return true; + } + char *selector = jsval_to_string(ctx, args[0]); + + if (!selector) { + dom_node_unref(root); + args.rval().setNull(); + return true; + } + void *ret = walk_tree_query(root, selector, 0); + mem_free(selector); + dom_node_unref(root); + + if (!ret) { + args.rval().setNull(); + } else { + JSObject *el = getElement(ctx, ret); + args.rval().setObject(*el); + } return true; } diff --git a/test/ecmascript/assert/document.querySelector.html b/test/ecmascript/assert/document.querySelector.html index 855ecb7d..7f21815c 100644 --- a/test/ecmascript/assert/document.querySelector.html +++ b/test/ecmascript/assert/document.querySelector.html @@ -11,6 +11,8 @@ function myFunction() { var y = document.querySelector('.b'); console.assert(!(y === null), 'Class b'); + var inp = y.innerHTML; + console.assert(inp === 'Class b.', 'Class b.'); } console.error('document.querySelector.html');