diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/parse/language.c | 282 | ||||
-rw-r--r-- | src/parse/parse.c | 28 | ||||
-rw-r--r-- | src/stylesheet.c | 185 | ||||
-rw-r--r-- | src/stylesheet.h | 13 |
4 files changed, 356 insertions, 152 deletions
diff --git a/src/parse/language.c b/src/parse/language.c index c031bd4..f4ba3ee 100644 --- a/src/parse/language.c +++ b/src/parse/language.c @@ -51,6 +51,11 @@ static inline css_error handleBlockContent(css_language *c, static inline css_error handleDeclaration(css_language *c, const parserutils_vector *vector); +/* At-rule parsing */ +static inline css_error parseMediaList(css_language *c, + const parserutils_vector *vector, int *ctx, + uint64_t *media); + /* Selector list parsing */ static inline css_error parseClass(css_language *c, const parserutils_vector *vector, int *ctx, @@ -267,10 +272,17 @@ css_error handleStartRuleset(css_language *c, const parserutils_vector *vector) parserutils_error perror; css_error error; context_entry entry = { CSS_PARSER_START_RULESET, NULL }; + context_entry *cur; + css_rule *parent_rule = NULL; css_rule *rule = NULL; assert(c != NULL); + /* Retrieve parent rule from stack, if any */ + cur = parserutils_stack_get_current(c->context); + if (cur != NULL && cur->type != CSS_PARSER_START_STYLESHEET) + parent_rule = cur->data; + error = css_stylesheet_rule_create(c->sheet, CSS_RULE_SELECTOR, &rule); if (error != CSS_OK) return error; @@ -289,7 +301,7 @@ css_error handleStartRuleset(css_language *c, const parserutils_vector *vector) return css_error_from_parserutils_error(perror); } - error = css_stylesheet_add_rule(c->sheet, rule); + error = css_stylesheet_add_rule(c->sheet, rule, parent_rule); if (error != CSS_OK) { parserutils_stack_pop(c->context, NULL); css_stylesheet_rule_destroy(c->sheet, rule); @@ -333,6 +345,8 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) const css_token *token = NULL; const css_token *atkeyword = NULL; int32_t ctx = 0; + css_rule *rule; + css_error error; /* vector contains: ATKEYWORD ws any0 */ @@ -349,8 +363,6 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) if (atkeyword->ilower == c->strings[CHARSET]) { if (c->state == BEFORE_CHARSET) { const css_token *charset; - css_rule *rule; - css_error error; /* any0 = STRING */ if (ctx == 0) @@ -377,7 +389,7 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) return error; } - error = css_stylesheet_add_rule(c->sheet, rule); + error = css_stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css_stylesheet_rule_destroy(c->sheet, rule); return error; @@ -392,9 +404,7 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) } } else if (atkeyword->ilower == c->strings[IMPORT]) { if (c->state != HAD_RULE) { - css_rule *rule; - css_media_type media = 0; - css_error error; + uint64_t media = 0; /* any0 = (STRING | URI) ws * (IDENT ws (',' ws IDENT ws)* )? */ @@ -407,54 +417,9 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) consumeWhitespace(vector, &ctx); /* Parse media list */ - token = parserutils_vector_iterate(vector, &ctx); - - while (token != NULL) { - if (token->type != CSS_TOKEN_IDENT) - return CSS_INVALID; - - if (token->ilower == c->strings[AURAL]) { - media |= CSS_MEDIA_AURAL; - } else if (token->ilower == - c->strings[BRAILLE]) { - media |= CSS_MEDIA_BRAILLE; - } else if (token->ilower == - c->strings[EMBOSSED]) { - media |= CSS_MEDIA_EMBOSSED; - } else if (token->ilower == - c->strings[HANDHELD]) { - media |= CSS_MEDIA_HANDHELD; - } else if (token->ilower == - c->strings[PRINT]) { - media |= CSS_MEDIA_PRINT; - } else if (token->ilower == - c->strings[PROJECTION]) { - media |= CSS_MEDIA_PROJECTION; - } else if (token->ilower == - c->strings[SCREEN]) { - media |= CSS_MEDIA_SCREEN; - } else if (token->ilower == - c->strings[SPEECH]) { - media |= CSS_MEDIA_SPEECH; - } else if (token->ilower == c->strings[TTY]) { - media |= CSS_MEDIA_TTY; - } else if (token->ilower == c->strings[TV]) { - media |= CSS_MEDIA_TV; - } else if (token->ilower == c->strings[ALL]) { - media |= CSS_MEDIA_ALL; - } else - return CSS_INVALID; - - consumeWhitespace(vector, &ctx); - - token = parserutils_vector_iterate(vector, - &ctx); - if (token != NULL && tokenIsChar(token, ',') == - false) - return CSS_INVALID; - - consumeWhitespace(vector, &ctx); - } + error = parseMediaList(c, vector, &ctx, &media); + if (error != CSS_OK) + return error; error = css_stylesheet_rule_create(c->sheet, CSS_RULE_IMPORT, &rule); @@ -468,7 +433,7 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) return error; } - error = css_stylesheet_add_rule(c->sheet, rule); + error = css_stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css_stylesheet_rule_destroy(c->sheet, rule); return error; @@ -481,22 +446,82 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) } else { return CSS_INVALID; } -#if 0 - /** \todo these depend on nested block support, so we'll disable them - * until we have such a thing. This means that we'll ignore the entire - * at-rule until then */ } else if (atkeyword->ilower == c->strings[MEDIA]) { - /** \todo any0 = IDENT ws (',' ws IDENT ws)* */ + uint64_t media = 0; + + /* any0 = IDENT ws (',' ws IDENT ws)* */ + + error = parseMediaList(c, vector, &ctx, &media); + if (error != CSS_OK) + return error; + + error = css_stylesheet_rule_create(c->sheet, + CSS_RULE_MEDIA, &rule); + if (error != CSS_OK) + return error; + + error = css_stylesheet_rule_set_media(c->sheet, rule, media); + if (error != CSS_OK) { + css_stylesheet_rule_destroy(c->sheet, rule); + return error; + } + + error = css_stylesheet_add_rule(c->sheet, rule, NULL); + if (error != CSS_OK) { + css_stylesheet_rule_destroy(c->sheet, rule); + return error; + } + + /* Rule is now owned by the sheet, + * so no need to destroy it */ + c->state = HAD_RULE; } else if (atkeyword->ilower == c->strings[PAGE]) { - /** \todo any0 = (':' IDENT)? ws */ + const css_token *token; + + /* any0 = (':' IDENT)? ws */ + + error = css_stylesheet_rule_create(c->sheet, + CSS_RULE_PAGE, &rule); + if (error != CSS_OK) + return error; + + consumeWhitespace(vector, &ctx); + + token = parserutils_vector_peek(vector, ctx); + if (token != NULL) { + css_selector *sel = NULL; + + error = parseSelector(c, vector, &ctx, &sel); + if (error != CSS_OK) { + css_stylesheet_rule_destroy(c->sheet, rule); + return error; + } + + error = css_stylesheet_rule_set_page_selector(c->sheet, + rule, sel); + if (error != CSS_OK) { + css_stylesheet_selector_destroy(c->sheet, sel); + css_stylesheet_rule_destroy(c->sheet, rule); + return error; + } + } + + error = css_stylesheet_add_rule(c->sheet, rule, NULL); + if (error != CSS_OK) { + css_stylesheet_rule_destroy(c->sheet, rule); + return error; + } + + /* Rule is now owned by the sheet, + * so no need to destroy it */ + c->state = HAD_RULE; -#endif } else { return CSS_INVALID; } - entry.data = (void *) atkeyword->ilower; + entry.data = rule; perror = parserutils_stack_push(c->context, (void *) &entry); if (perror != PARSERUTILS_OK) { @@ -529,36 +554,83 @@ css_error handleEndAtRule(css_language *c, const parserutils_vector *vector) css_error handleStartBlock(css_language *c, const parserutils_vector *vector) { - UNUSED(c); + parserutils_error perror; + context_entry entry = { CSS_PARSER_START_BLOCK, NULL }; + context_entry *cur; + UNUSED(vector); - /* We don't care about blocks. In CSS2.1 they're always attached to - * rulesets or at-rules. */ + /* If the current item on the stack isn't a block, + * then clone its data field. This ensures that the relevant rule + * is available when parsing the block contents. */ + cur = parserutils_stack_get_current(c->context); + if (cur != NULL && cur->type != CSS_PARSER_START_BLOCK) + entry.data = cur->data; + + perror = parserutils_stack_push(c->context, (void *) &entry); + if (perror != PARSERUTILS_OK) { + return css_error_from_parserutils_error(perror); + } return CSS_OK; } css_error handleEndBlock(css_language *c, const parserutils_vector *vector) { - UNUSED(c); + parserutils_error perror; + context_entry *entry; + css_rule *rule; + UNUSED(vector); - /* We don't care about blocks. In CSS 2.1 they're always attached to - * rulesets or at-rules. */ + entry = parserutils_stack_get_current(c->context); + if (entry == NULL || entry->type != CSS_PARSER_START_BLOCK) + return CSS_INVALID; + + rule = entry->data; + + perror = parserutils_stack_pop(c->context, NULL); + if (perror != PARSERUTILS_OK) { + return css_error_from_parserutils_error(perror); + } + + /* If the block we just popped off the stack was associated with a + * non-block stack entry, and that entry is not a top-level statement, + * then report the end of that entry, too. */ + if (rule != NULL && rule->ptype != CSS_RULE_PARENT_STYLESHEET) { + if (rule->type == CSS_RULE_SELECTOR) + return handleEndRuleset(c, vector); + } return CSS_OK; } css_error handleBlockContent(css_language *c, const parserutils_vector *vector) { - UNUSED(c); - UNUSED(vector); + context_entry *entry; + css_rule *rule; /* In CSS 2.1, block content comprises either declarations (if the * current block is associated with @page or a selector), or rulesets * (if the current block is associated with @media). */ - /** \todo implement nested blocks */ + entry = parserutils_stack_get_current(c->context); + if (entry == NULL || entry->data == NULL) + return CSS_INVALID; + + rule = entry->data; + if (rule == NULL || (rule->type != CSS_RULE_SELECTOR && + rule->type != CSS_RULE_PAGE && + rule->type != CSS_RULE_MEDIA)) + return CSS_INVALID; + + if (rule->type == CSS_RULE_MEDIA) { + /* Expect rulesets */ + return handleStartRuleset(c, vector); + } else { + /* Expect declarations */ + return handleDeclaration(c, vector); + } return CSS_OK; } @@ -577,8 +649,7 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) * + In ruleset */ entry = parserutils_stack_get_current(c->context); - if (entry == NULL || (entry->type != CSS_PARSER_START_RULESET && - entry->type != CSS_PARSER_START_ATRULE)) + if (entry == NULL || entry->data == NULL) return CSS_INVALID; rule = entry->data; @@ -586,6 +657,9 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) rule->type != CSS_RULE_PAGE)) return CSS_INVALID; + /* Strip any leading whitespace (can happen if in nested block) */ + consumeWhitespace(vector, &ctx); + /* IDENT ws ':' ws value * * In CSS 2.1, value is any1, so '{' or ATKEYWORD => parse error @@ -610,6 +684,61 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) } /****************************************************************************** + * At-rule parsing functions * + ******************************************************************************/ +css_error parseMediaList(css_language *c, + const parserutils_vector *vector, int *ctx, + uint64_t *media) +{ + uint64_t ret = 0; + const css_token *token; + + token = parserutils_vector_iterate(vector, ctx); + + while (token != NULL) { + if (token->type != CSS_TOKEN_IDENT) + return CSS_INVALID; + + if (token->ilower == c->strings[AURAL]) { + ret |= CSS_MEDIA_AURAL; + } else if (token->ilower == c->strings[BRAILLE]) { + ret |= CSS_MEDIA_BRAILLE; + } else if (token->ilower == c->strings[EMBOSSED]) { + ret |= CSS_MEDIA_EMBOSSED; + } else if (token->ilower == c->strings[HANDHELD]) { + ret |= CSS_MEDIA_HANDHELD; + } else if (token->ilower == c->strings[PRINT]) { + ret |= CSS_MEDIA_PRINT; + } else if (token->ilower == c->strings[PROJECTION]) { + ret |= CSS_MEDIA_PROJECTION; + } else if (token->ilower == c->strings[SCREEN]) { + ret |= CSS_MEDIA_SCREEN; + } else if (token->ilower == c->strings[SPEECH]) { + ret |= CSS_MEDIA_SPEECH; + } else if (token->ilower == c->strings[TTY]) { + ret |= CSS_MEDIA_TTY; + } else if (token->ilower == c->strings[TV]) { + ret |= CSS_MEDIA_TV; + } else if (token->ilower == c->strings[ALL]) { + ret |= CSS_MEDIA_ALL; + } else + return CSS_INVALID; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token != NULL && tokenIsChar(token, ',') == false) + return CSS_INVALID; + + consumeWhitespace(vector, ctx); + } + + *media = ret; + + return CSS_OK; +} + +/****************************************************************************** * Selector list parsing functions * ******************************************************************************/ @@ -969,6 +1098,9 @@ css_error parseSelectorList(css_language *c, const parserutils_vector *vector, css_selector *selector = NULL; int ctx = 0; + /* Strip any leading whitespace (can happen if in nested block) */ + consumeWhitespace(vector, &ctx); + /* selector_list -> selector [ ',' ws selector ]* */ error = parseSelector(c, vector, &ctx, &selector); diff --git a/src/parse/parse.c b/src/parse/parse.c index f7fd2fb..452658f 100644 --- a/src/parse/parse.c +++ b/src/parse/parse.c @@ -1273,7 +1273,7 @@ css_error parseBlockContent(css_parser *parser) if (parser->event != NULL) { parser->event( CSS_PARSER_BLOCK_CONTENT, - parser->tokens, + parser->tokens, parser->event_pw); } @@ -1282,6 +1282,30 @@ css_error parseBlockContent(css_parser *parser) } else if (lwc_string_length(token->ilower) == 1 && lwc_string_data(token->ilower)[0] == ';') { /* Grammar ambiguity. Assume semi */ + error = pushBack(parser, token); + if (error != CSS_OK) + return error; + +#if !defined(NDEBUG) && defined(DEBUG_EVENTS) + parserutils_vector_dump(parser->tokens, + __func__, tprinter); +#endif + if (parser->event != NULL) { + parser->event( + CSS_PARSER_BLOCK_CONTENT, + parser->tokens, + parser->event_pw); + } + + error = getToken(parser, &token); + if (error != CSS_OK) + return error; + + unref_interned_strings_in_tokens( + parser); + parserutils_vector_clear( + parser->tokens); + state->substate = WS; } else if (lwc_string_length(token->ilower) == 1 && lwc_string_data(token->ilower)[0] == '}') { @@ -2298,7 +2322,7 @@ static void tprinter(void *token) css_token *t = token; if (t->data.data) - printf("%d: %.*s", t->type, t->data.len, t->data.data); + printf("%d: %.*s", t->type, (int) t->data.len, t->data.data); else printf("%d", t->type); } diff --git a/src/stylesheet.c b/src/stylesheet.c index 41a3341..c48240a 100644 --- a/src/stylesheet.c +++ b/src/stylesheet.c @@ -281,7 +281,8 @@ css_error css_stylesheet_next_pending_import(css_stylesheet *parent, break; if (r->type == CSS_RULE_IMPORT && i->sheet == NULL) { - *url = lwc_context_string_ref(parent->dictionary, i->url); + *url = lwc_context_string_ref(parent->dictionary, + i->url); *media = i->media; return CSS_OK; @@ -604,9 +605,14 @@ css_error css_stylesheet_selector_destroy(css_stylesheet *sheet, d = c->combinator; for (detail = &c->data; detail;) { - lwc_context_string_unref(sheet->dictionary, detail->name); - if (detail->value != NULL) - lwc_context_string_unref(sheet->dictionary, detail->value); + lwc_context_string_unref(sheet->dictionary, + detail->name); + + if (detail->value != NULL) { + lwc_context_string_unref(sheet->dictionary, + detail->value); + } + if (detail->next) detail++; else @@ -618,8 +624,12 @@ css_error css_stylesheet_selector_destroy(css_stylesheet *sheet, for (detail = &selector->data; detail;) { lwc_context_string_unref(sheet->dictionary, detail->name); - if (detail->value != NULL) - lwc_context_string_unref(sheet->dictionary, detail->value); + + if (detail->value != NULL) { + lwc_context_string_unref(sheet->dictionary, + detail->value); + } + if (detail->next) detail++; else @@ -911,20 +921,12 @@ css_error css_stylesheet_rule_destroy(css_stylesheet *sheet, css_rule *rule) case CSS_RULE_PAGE: { css_rule_page *page = (css_rule_page *) rule; - uint32_t i; - - for (i = 0; i < rule->items; i++) { - css_selector *sel = page->selectors[i]; - - /* Detach from rule */ - sel->rule = NULL; - css_stylesheet_selector_destroy(sheet, sel); + if (page->selector != NULL) { + page->selector->rule = NULL; + css_stylesheet_selector_destroy(sheet, page->selector); } - if (page->selectors != NULL) - sheet->alloc(page->selectors, 0, sheet->pw); - if (page->style != NULL) css_stylesheet_style_destroy(sheet, page->style); } @@ -1085,13 +1087,70 @@ css_error css_stylesheet_rule_set_nascent_import(css_stylesheet *sheet, } /** + * Set the media of an @media rule + * + * \param sheet The stylesheet context + * \param rule The rule to add to (must be of type CSS_RULE_MEDIA) + * \param media The applicable media types for the rule + * \return CSS_OK on success, appropriate error otherwise + */ +css_error css_stylesheet_rule_set_media(css_stylesheet *sheet, + css_rule *rule, uint64_t media) +{ + css_rule_media *r = (css_rule_media *) rule; + + if (sheet == NULL || rule == NULL) + return CSS_BADPARM; + + /* Ensure rule is a CSS_RULE_MEDIA */ + assert(rule->type == CSS_RULE_MEDIA); + + /* Set the rule's media */ + r->media = media; + + return CSS_OK; +} + +/** + * Set an @page rule selector + * + * \param sheet The stylesheet context + * \param rule The rule to add to (must be of type CSS_RULE_PAGE) + * \param selector The page selector + * \return CSS_OK on success, appropriate error otherwise + */ +css_error css_stylesheet_rule_set_page_selector(css_stylesheet *sheet, + css_rule *rule, css_selector *selector) +{ + css_rule_page *r = (css_rule_page *) rule; + + if (sheet == NULL || rule == NULL || selector == NULL) + return CSS_BADPARM; + + /* Ensure rule is a CSS_RULE_PAGE */ + assert(rule->type == CSS_RULE_PAGE); + + /** \todo validate selector */ + + /* Set the rule's selector */ + r->selector = selector; + + /* Set selector's rule field */ + selector->rule = rule; + + return CSS_OK; +} + +/** * Add a rule to a stylesheet * - * \param sheet The stylesheet to add to - * \param rule The rule to add + * \param sheet The stylesheet to add to + * \param rule The rule to add + * \param parent The parent rule, or NULL for a top-level rule * \return CSS_OK on success, appropriate error otherwise */ -css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule) +css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule, + css_rule *parent) { css_error error; @@ -1108,19 +1167,41 @@ css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule) if (error != CSS_OK) return error; - /* Add rule to sheet */ - rule->ptype = CSS_RULE_PARENT_STYLESHEET; - rule->parent = sheet; - sheet->rule_count++; - - if (sheet->last_rule == NULL) { - rule->prev = rule->next = NULL; - sheet->rule_list = sheet->last_rule = rule; + if (parent != NULL) { + css_rule_media *media = (css_rule_media *) parent; + + /* Parent must be an @media rule, or NULL */ + assert(parent->type == CSS_RULE_MEDIA); + + /* Add rule to parent */ + rule->ptype = CSS_RULE_PARENT_RULE; + rule->parent = parent; + sheet->rule_count++; + + if (media->last_child == NULL) { + rule->prev = rule->next = NULL; + media->first_child = media->last_child = rule; + } else { + media->last_child->next = rule; + rule->prev = media->last_child; + rule->next = NULL; + media->last_child = rule; + } } else { - sheet->last_rule->next = rule; - rule->prev = sheet->last_rule; - rule->next = NULL; - sheet->last_rule = rule; + /* Add rule to sheet */ + rule->ptype = CSS_RULE_PARENT_STYLESHEET; + rule->parent = sheet; + sheet->rule_count++; + + if (sheet->last_rule == NULL) { + rule->prev = rule->next = NULL; + sheet->rule_list = sheet->last_rule = rule; + } else { + sheet->last_rule->next = rule; + rule->prev = sheet->last_rule; + rule->next = NULL; + sheet->last_rule = rule; + } } /** \todo needs to trigger some event announcing styles have changed */ @@ -1225,7 +1306,7 @@ css_error _add_selectors(css_stylesheet *sheet, css_rule *rule) for (r = m->first_child; r != NULL; r = r->next) { error = _add_selectors(sheet, r); if (error != CSS_OK) { - /* Failed, revert out changes */ + /* Failed, revert our changes */ for (r = r->prev; r != NULL; r = r->prev) { _remove_selectors(sheet, r); } @@ -1235,30 +1316,6 @@ css_error _add_selectors(css_stylesheet *sheet, css_rule *rule) } } break; - case CSS_RULE_PAGE: - { - css_rule_page *p = (css_rule_page *) rule; - int32_t i; - - for (i = 0; i < rule->items; i++) { - css_selector *sel = p->selectors[i]; - - error = css_selector_hash_insert(sheet->selectors, sel); - if (error != CSS_OK) { - /* Failed, revert our changes */ - for (i--; i >= 0; i--) { - sel = p->selectors[i]; - - /* Ignore errors */ - css_selector_hash_remove( - sheet->selectors, sel); - } - - return error; - } - } - } - break; } return CSS_OK; @@ -1305,20 +1362,6 @@ css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule) } } break; - case CSS_RULE_PAGE: - { - css_rule_page *p = (css_rule_page *) rule; - int32_t i; - - for (i = 0; i < rule->items; i++) { - css_selector *sel = p->selectors[i]; - - error = css_selector_hash_remove(sheet->selectors, sel); - if (error != CSS_OK) - return error; - } - } - break; } return CSS_OK; diff --git a/src/stylesheet.h b/src/stylesheet.h index 4cb890e..1fab87e 100644 --- a/src/stylesheet.h +++ b/src/stylesheet.h @@ -111,7 +111,7 @@ typedef struct css_rule_selector { typedef struct css_rule_media { css_rule base; - uint32_t media; + uint64_t media; css_rule *first_child; css_rule *last_child; @@ -126,7 +126,7 @@ typedef struct css_rule_font_face { typedef struct css_rule_page { css_rule base; - css_selector **selectors; + css_selector *selector; css_style *style; } css_rule_page; @@ -213,9 +213,14 @@ css_error css_stylesheet_rule_set_charset(css_stylesheet *sheet, css_error css_stylesheet_rule_set_nascent_import(css_stylesheet *sheet, css_rule *rule, lwc_string *url, uint64_t media); -/** \todo registering other rule-type data with css_rules */ +css_error css_stylesheet_rule_set_media(css_stylesheet *sheet, + css_rule *rule, uint64_t media); + +css_error css_stylesheet_rule_set_page_selector(css_stylesheet *sheet, + css_rule *rule, css_selector *sel); -css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule); +css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule, + css_rule *parent); css_error css_stylesheet_remove_rule(css_stylesheet *sheet, css_rule *rule); #endif |