From 03780dee6396a96fc3489f433838da998c89c4fe Mon Sep 17 00:00:00 2001 From: Robert Staudinger Date: Fri, 7 Aug 2009 13:16:51 +0200 Subject: [stylesheet] Implement ccss_stylesheet_unload() to unload css parts. Every selector now stores a descriptor of the CSS file or buffer it originates from. For unloading a file or buffer the internal stylesheet representation is iterated and all selectors and blocks with matching descriptors are destroyed. This also requires an update to ccss_node_get_style(), the descriptor for the inline style is passed to the callback, which the consumer must store in order to unload the inline style later on. The above change in turn obsoletes ccss_stylesheet_invalidate_node() since all unloading now uses a consistent API. Also fix a related memory leak, selectors and -groups would be left over when destroying a stylesheet. --- ccss-doc/ccss-sections.txt | 3 +- ccss-doc/tmpl/ccss-unused.sgml | 8 +++ ccss-doc/tmpl/node.sgml | 1 + ccss-doc/tmpl/stylesheet.sgml | 26 ++++++-- ccss/ccss-block-priv.h | 4 +- ccss/ccss-block.c | 18 +++++- ccss/ccss-grammar-parse.c | 77 +++++++++++++++++------ ccss/ccss-grammar-priv.h | 3 + ccss/ccss-grammar.c | 29 +++++++-- ccss/ccss-node-priv.h | 3 +- ccss/ccss-node.c | 9 ++- ccss/ccss-node.h | 6 +- ccss/ccss-selector-group.c | 80 ++++++++++++++++++++++++ ccss/ccss-selector-group.h | 4 ++ ccss/ccss-selector.c | 89 ++++++++++++++++++--------- ccss/ccss-selector.h | 32 ++++++---- ccss/ccss-stylesheet-priv.h | 2 + ccss/ccss-stylesheet.c | 136 +++++++++++++++++++++++++++++++---------- ccss/ccss-stylesheet.h | 17 ++++-- ccss/ccss.sym | 3 +- configure.in | 4 +- examples/Makefile.am | 3 + examples/example-10.c | 60 ++++++++++++++++++ examples/example-2.c | 3 +- 24 files changed, 500 insertions(+), 120 deletions(-) create mode 100644 examples/example-10.c diff --git a/ccss-doc/ccss-sections.txt b/ccss-doc/ccss-sections.txt index 2ed1f1f..c3c0a05 100644 --- a/ccss-doc/ccss-sections.txt +++ b/ccss-doc/ccss-sections.txt @@ -68,11 +68,12 @@ ccss_stylesheet_precedence_t ccss_stylesheet_destroy ccss_stylesheet_reference ccss_stylesheet_get_reference_count +ccss_stylesheet_add_from_buffer ccss_stylesheet_add_from_file ccss_stylesheet_foreach -ccss_stylesheet_invalidate_node ccss_stylesheet_query_type ccss_stylesheet_query +ccss_stylesheet_unload ccss_stylesheet_dump diff --git a/ccss-doc/tmpl/ccss-unused.sgml b/ccss-doc/tmpl/ccss-unused.sgml index 34891ab..a93cf66 100644 --- a/ccss-doc/tmpl/ccss-unused.sgml +++ b/ccss-doc/tmpl/ccss-unused.sgml @@ -330,6 +330,14 @@ ccss_selector_group_t @self: + + + + + +@self: +@instance: + diff --git a/ccss-doc/tmpl/node.sgml b/ccss-doc/tmpl/node.sgml index 75fb027..8111d22 100644 --- a/ccss-doc/tmpl/node.sgml +++ b/ccss-doc/tmpl/node.sgml @@ -256,6 +256,7 @@ ccss_node_t @self: +@descriptor: @Returns: diff --git a/ccss-doc/tmpl/stylesheet.sgml b/ccss-doc/tmpl/stylesheet.sgml index e1bb61f..ad21618 100644 --- a/ccss-doc/tmpl/stylesheet.sgml +++ b/ccss-doc/tmpl/stylesheet.sgml @@ -68,35 +68,39 @@ ccss_stylesheet_t @Returns: - + @self: -@css_file: +@buffer: +@size: @precedence: @user_data: @Returns: - + @self: -@func: +@css_file: +@precedence: @user_data: +@Returns: - + @self: -@instance: +@func: +@user_data: @@ -119,6 +123,16 @@ ccss_stylesheet_t @Returns: + + + + + +@self: +@descriptor: +@Returns: + + diff --git a/ccss/ccss-block-priv.h b/ccss/ccss-block-priv.h index db87467..a389b04 100644 --- a/ccss/ccss-block-priv.h +++ b/ccss/ccss-block-priv.h @@ -35,11 +35,13 @@ CCSS_BEGIN_DECLS **/ struct ccss_block_ { /*< private >*/ - GHashTable *properties; + unsigned int reference_count; + GHashTable *properties; }; ccss_block_t * ccss_block_create (void); void ccss_block_destroy (ccss_block_t *self); +ccss_block_t * ccss_block_reference (ccss_block_t *self); void ccss_block_dump (ccss_block_t const *self); diff --git a/ccss/ccss-block.c b/ccss/ccss-block.c index 5347892..2be2244 100644 --- a/ccss/ccss-block.c +++ b/ccss/ccss-block.c @@ -29,6 +29,7 @@ ccss_block_create (void) ccss_block_t *self; self = g_new0 (ccss_block_t, 1); + self->reference_count = 1; self->properties = g_hash_table_new_full ((GHashFunc) g_direct_hash, (GEqualFunc) g_direct_equal, NULL, @@ -42,10 +43,23 @@ ccss_block_destroy (ccss_block_t *self) { g_return_if_fail (self && self->properties); - g_hash_table_destroy (self->properties), self->properties = NULL; - g_free (self); + self->reference_count--; + + if (self->reference_count == 0) { + g_hash_table_destroy (self->properties), self->properties = NULL; + g_free (self); + } } +ccss_block_t * +ccss_block_reference (ccss_block_t *self) +{ + g_return_val_if_fail (self, NULL); + + self->reference_count++; + + return self; +} /** * ccss_block_add_property: diff --git a/ccss/ccss-grammar-parse.c b/ccss/ccss-grammar-parse.c index 937d5c1..6c44e7d 100644 --- a/ccss/ccss-grammar-parse.c +++ b/ccss/ccss-grammar-parse.c @@ -38,6 +38,7 @@ typedef struct { typedef struct { ccss_grammar_t const *grammar; ccss_stylesheet_precedence_t precedence; + unsigned int stylesheet_descriptor; void *user_data; GHashTable *blocks; GHashTable *groups; @@ -94,6 +95,7 @@ calculate_importance (ccss_stylesheet_precedence_t precedence, static ccss_selector_t * walk_additional_selector (CRAdditionalSel *cr_add_sel, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, bool is_important) { ccss_selector_t *selector; @@ -111,21 +113,35 @@ walk_additional_selector (CRAdditionalSel *cr_add_sel, switch (cr_add_sel->type) { case CLASS_ADD_SELECTOR: name = cr_string_peek_raw_str (cr_add_sel->content.class_name); - selector = ccss_class_selector_create (name, precedence, importance); + selector = ccss_class_selector_create (name, + precedence, + stylesheet_descriptor, + importance); break; case PSEUDO_CLASS_ADD_SELECTOR: name = cr_string_peek_raw_str (cr_add_sel->content.pseudo->name); - selector = ccss_pseudo_class_selector_create (name, precedence, importance); + selector = ccss_pseudo_class_selector_create (name, + precedence, + stylesheet_descriptor, + importance); break; case ID_ADD_SELECTOR: name = cr_string_peek_raw_str (cr_add_sel->content.id_name); - selector = ccss_id_selector_create (name, precedence, importance); + selector = ccss_id_selector_create (name, + precedence, + stylesheet_descriptor, + importance); break; case ATTRIBUTE_ADD_SELECTOR: name = cr_string_peek_raw_str (cr_add_sel->content.attr_sel->name); value = cr_string_peek_raw_str (cr_add_sel->content.attr_sel->value); match = map_attribute_selector_match (cr_add_sel->content.attr_sel->match_way); - selector = ccss_attribute_selector_create (name, value, match, precedence, importance); + selector = ccss_attribute_selector_create (name, + value, + match, + precedence, + stylesheet_descriptor, + importance); break; case NO_ADD_SELECTOR: default: @@ -135,7 +151,10 @@ walk_additional_selector (CRAdditionalSel *cr_add_sel, if (cr_add_sel->next) { ccss_selector_t *refinement; - refinement = walk_additional_selector (cr_add_sel->next, precedence, is_important); + refinement = walk_additional_selector (cr_add_sel->next, + precedence, + stylesheet_descriptor, + is_important); ccss_selector_refine (selector, refinement); } @@ -145,6 +164,7 @@ walk_additional_selector (CRAdditionalSel *cr_add_sel, static ccss_selector_t * walk_simple_selector_r (CRSimpleSel *cr_simple_sel, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, bool is_important) { ccss_selector_t *selector; @@ -155,9 +175,14 @@ walk_simple_selector_r (CRSimpleSel *cr_simple_sel, selector = NULL; importance = calculate_importance (precedence, is_important); if (UNIVERSAL_SELECTOR & cr_simple_sel->type_mask) { - selector = ccss_universal_selector_create (precedence, importance); + selector = ccss_universal_selector_create (precedence, + stylesheet_descriptor, + importance); } else if (TYPE_SELECTOR & cr_simple_sel->type_mask) { - selector = ccss_type_selector_create (cr_string_peek_raw_str (cr_simple_sel->name), precedence, importance); + selector = ccss_type_selector_create (cr_string_peek_raw_str (cr_simple_sel->name), + precedence, + stylesheet_descriptor, + importance); } else { char const *sel; sel = cr_simple_sel->name ? cr_string_peek_raw_str (cr_simple_sel->name) : NULL; @@ -169,13 +194,19 @@ walk_simple_selector_r (CRSimpleSel *cr_simple_sel, if (cr_simple_sel->add_sel) { ccss_selector_t *refinement; - refinement = walk_additional_selector (cr_simple_sel->add_sel, precedence, is_important); + refinement = walk_additional_selector (cr_simple_sel->add_sel, + precedence, + stylesheet_descriptor, + is_important); ccss_selector_refine (selector, refinement); } if (cr_simple_sel->next) { ccss_selector_t *descendant; - descendant = walk_simple_selector_r (cr_simple_sel->next, precedence, is_important); + descendant = walk_simple_selector_r (cr_simple_sel->next, + precedence, + stylesheet_descriptor, + is_important); if (COMB_WS == cr_simple_sel->next->combinator) { selector = ccss_selector_append_descendant (selector, descendant); @@ -195,6 +226,7 @@ walk_selector (CRSelector *cr_sel, ccss_block_t *block, GHashTable *groups, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, bool is_important, instance_info_t const *instance_info) { @@ -209,7 +241,9 @@ walk_selector (CRSelector *cr_sel, importance = calculate_importance (precedence, is_important); selector = ccss_instance_selector_create (instance_info->instance, - precedence, importance); + precedence, + stylesheet_descriptor, + importance); ccss_selector_set_block (selector, block); ccss_selector_group_add_selector (instance_info->result_group, selector); @@ -219,7 +253,10 @@ walk_selector (CRSelector *cr_sel, /* Handle `full' CSS statements. */ iter = cr_sel; do { - selector = walk_simple_selector_r (iter->simple_sel, precedence, is_important); + selector = walk_simple_selector_r (iter->simple_sel, + precedence, + stylesheet_descriptor, + is_important); if (selector) { ccss_selector_set_block (selector, block); @@ -354,18 +391,18 @@ end_selector_cb (CRDocHandler *handler, g_assert (info); if (info->block) { - walk_selector (cr_sel, info->block, info->groups, - info->precedence, false, - info->instance); + walk_selector (cr_sel, info->block, info->groups, + info->precedence, info->stylesheet_descriptor, + false, info->instance); info->block = NULL; } /* Properties marked `important' form a block of their own, * so they can be sorted into the cascade at the appropriate position. */ if (info->important_block) { - walk_selector (cr_sel, info->important_block, info->groups, - info->precedence, true, - info->instance); + walk_selector (cr_sel, info->important_block, info->groups, + info->precedence, info->stylesheet_descriptor, + true, info->instance); info->important_block = NULL; } } @@ -374,6 +411,7 @@ enum CRStatus ccss_grammar_parse_file (ccss_grammar_t const *self, char const *css_file, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, void *user_data, GHashTable *groups, GHashTable *blocks) @@ -391,6 +429,7 @@ ccss_grammar_parse_file (ccss_grammar_t const *self, handler->app_data = (gpointer) &info; info.grammar = self; info.precedence = precedence; + info.stylesheet_descriptor = stylesheet_descriptor; info.user_data = user_data; info.blocks = blocks; info.groups = groups; @@ -424,6 +463,7 @@ ccss_grammar_parse_buffer (ccss_grammar_t const *self, char const *buffer, size_t size, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, void *user_data, GHashTable *groups, GHashTable *blocks) @@ -442,6 +482,7 @@ ccss_grammar_parse_buffer (ccss_grammar_t const *self, handler->app_data = (gpointer) &info; info.grammar = self; info.precedence = precedence; + info.stylesheet_descriptor = stylesheet_descriptor; info.user_data = user_data; info.blocks = blocks; info.groups = groups; @@ -469,6 +510,7 @@ enum CRStatus ccss_grammar_parse_inline (ccss_grammar_t const *self, char const *buffer, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, ptrdiff_t instance, void *user_data, ccss_selector_group_t *result_group, @@ -494,6 +536,7 @@ ccss_grammar_parse_inline (ccss_grammar_t const *self, handler->app_data = (gpointer) &info; info.grammar = self; info.precedence = precedence; + info.stylesheet_descriptor = stylesheet_descriptor; info.blocks = blocks; info.user_data = user_data; info.groups = NULL; diff --git a/ccss/ccss-grammar-priv.h b/ccss/ccss-grammar-priv.h index c67e059..05ef177 100644 --- a/ccss/ccss-grammar-priv.h +++ b/ccss/ccss-grammar-priv.h @@ -50,6 +50,7 @@ enum CRStatus ccss_grammar_parse_file (ccss_grammar_t const *self, char const *css_file, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, void *user_data, GHashTable *groups, GHashTable *blocks); @@ -59,6 +60,7 @@ ccss_grammar_parse_buffer (ccss_grammar_t const *self, char const *buffer, size_t buffer_size, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, void *user_data, GHashTable *groups, GHashTable *blocks); @@ -67,6 +69,7 @@ enum CRStatus ccss_grammar_parse_inline (ccss_grammar_t const *self, char const *buffer, ccss_stylesheet_precedence_t precedence, + unsigned int stylesheet_descriptor, ptrdiff_t instance, void *user_data, ccss_selector_group_t *result_group, diff --git a/ccss/ccss-grammar.c b/ccss/ccss-grammar.c index 1ffde28..4a319c4 100644 --- a/ccss/ccss-grammar.c +++ b/ccss/ccss-grammar.c @@ -266,16 +266,25 @@ ccss_grammar_create_stylesheet_from_buffer (ccss_grammar_t *self, ccss_stylesheet_t *stylesheet; enum CRStatus ret; + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (buffer, NULL); + g_return_val_if_fail (size, NULL); + stylesheet = ccss_stylesheet_create (); stylesheet->grammar = ccss_grammar_reference (self); + stylesheet->current_descriptor++; - ret = ccss_grammar_parse_buffer (self, buffer, size, - CCSS_STYLESHEET_AUTHOR, user_data, - stylesheet->groups, stylesheet->blocks); + ret = ccss_grammar_parse_buffer (self, buffer, size, + CCSS_STYLESHEET_AUTHOR, + stylesheet->current_descriptor, + user_data, + stylesheet->groups, stylesheet->blocks); if (CR_OK == ret) { ccss_stylesheet_fix_dangling_selectors (stylesheet); return stylesheet; + } else { + /* TODO clean up using stylesheet->current_descriptor */ } return NULL; @@ -299,16 +308,24 @@ ccss_grammar_create_stylesheet_from_file (ccss_grammar_t *self, ccss_stylesheet_t *stylesheet; enum CRStatus ret; + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (css_file, NULL); + stylesheet = ccss_stylesheet_create (); stylesheet->grammar = ccss_grammar_reference (self); + stylesheet->current_descriptor++; - ret = ccss_grammar_parse_file (self, css_file, CCSS_STYLESHEET_AUTHOR, - user_data, stylesheet->groups, - stylesheet->blocks); + ret = ccss_grammar_parse_file (self, css_file, + CCSS_STYLESHEET_AUTHOR, + stylesheet->current_descriptor, + user_data, + stylesheet->groups, stylesheet->blocks); if (CR_OK == ret) { ccss_stylesheet_fix_dangling_selectors (stylesheet); return stylesheet; + } else { + /* TODO clean up using stylesheet->current_descriptor */ } return NULL; diff --git a/ccss/ccss-node-priv.h b/ccss/ccss-node-priv.h index 73e1e92..791fb88 100644 --- a/ccss/ccss-node-priv.h +++ b/ccss/ccss-node-priv.h @@ -59,7 +59,8 @@ ccss_node_get_attribute (ccss_node_t const *self, char const *name); char const * -ccss_node_get_style (ccss_node_t *self); +ccss_node_get_style (ccss_node_t *self, + unsigned int descriptor); bool ccss_node_get_viewport (ccss_node_t const *self, diff --git a/ccss/ccss-node.c b/ccss/ccss-node.c index 39d7a1d..306b2a5 100644 --- a/ccss/ccss-node.c +++ b/ccss/ccss-node.c @@ -81,7 +81,8 @@ get_attribute (ccss_node_t const *self, } static char const * -get_style (ccss_node_t const *self) +get_style (ccss_node_t const *self, + unsigned int descriptor) { return NULL; } @@ -275,14 +276,16 @@ ccss_node_get_attribute (ccss_node_t const *self, } char const * -ccss_node_get_style (ccss_node_t *self) +ccss_node_get_style (ccss_node_t *self, + unsigned int descriptor) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (self->node_class, NULL); g_return_val_if_fail (self->node_class->get_style, NULL); if (NULL == self->inline_style) - self->inline_style = self->node_class->get_style (self); + self->inline_style = self->node_class->get_style (self, + descriptor); return self->inline_style; } diff --git a/ccss/ccss-node.h b/ccss/ccss-node.h index c534c2a..409d273 100644 --- a/ccss/ccss-node.h +++ b/ccss/ccss-node.h @@ -134,12 +134,16 @@ typedef char * (*ccss_node_get_attribute_f) (ccss_node_t const *self, /** * ccss_node_get_style_f: * @self: a #ccss_node_t. + * @descriptor: handle to unload this style from the stylesheet later on. * * Hook function to query a #ccss_node_t's inline CSS style. * + * See: ccss_stylesheet_unload(). + * * Returns: the node's CSS properties or %NULL. **/ -typedef const char * (*ccss_node_get_style_f) (ccss_node_t const *self); +typedef const char * (*ccss_node_get_style_f) (ccss_node_t const *self, + unsigned int descriptor); /** * ccss_node_get_viewport_f: diff --git a/ccss/ccss-selector-group.c b/ccss/ccss-selector-group.c index b09cb91..ecdc391 100644 --- a/ccss/ccss-selector-group.c +++ b/ccss/ccss-selector-group.c @@ -98,6 +98,86 @@ ccss_selector_group_destroy (ccss_selector_group_t *self) g_free (self); } +typedef struct { + unsigned int descriptor; + GSList *empty_sets; + bool ret; +} traverse_unload_info_t; + +static bool +traverse_unload (size_t specificity, + ccss_selector_set_t *set, + traverse_unload_info_t *info) +{ + ccss_selector_t *selector; + GSList *iter; + + g_assert (info); + + iter = set->selectors; + while (iter) { + selector = (ccss_selector_t *) iter->data; + if (ccss_selector_get_descriptor (selector) == info->descriptor) { + ccss_selector_destroy (selector); + if (iter == set->selectors) { + /* Removing the last element? */ + iter = g_slist_delete_link (iter, iter); + if (NULL == iter) { + /* Yes, remember to remove the node. */ + info->empty_sets = g_slist_prepend (info->empty_sets, + GSIZE_TO_POINTER (specificity)); + set->selectors = NULL; + } else { + /* No, but new head. */ + set->selectors = iter; + } + } else { + iter = g_slist_delete_link (iter, iter); + } + info->ret = true; + } else { + iter = iter->next; + } + } + + return false; +} + +/** + * ccss_selector_group_unload: + * @self: a #ccss_selector_group_t. + * @descriptor descriptor of a part that was loaded. + * + * Unload a CSS file, buffer or inline style that was loaded into the selector group. + * + * Returns: %TRUE if anything had been unloaded. + */ +bool +ccss_selector_group_unload (ccss_selector_group_t *self, + unsigned int descriptor) +{ + GSList *iter; + traverse_unload_info_t info; + + g_return_val_if_fail (self, false); + g_return_val_if_fail (descriptor, false); + + info.descriptor = descriptor; + info.empty_sets = NULL; + info.ret = false; + + g_tree_foreach (self->sets, (GTraverseFunc) traverse_unload, &info); + + /* Prune empty sets. */ + iter = info.empty_sets; + while (iter) { + g_tree_remove (self->sets, iter->data); + iter = g_slist_delete_link (iter, iter); + } + + return info.ret; +} + /* * Takes ownership of the selector. */ diff --git a/ccss/ccss-selector-group.h b/ccss/ccss-selector-group.h index def0f72..c2c5e77 100644 --- a/ccss/ccss-selector-group.h +++ b/ccss/ccss-selector-group.h @@ -39,6 +39,10 @@ ccss_selector_group_create (void); void ccss_selector_group_destroy (ccss_selector_group_t *self); +bool +ccss_selector_group_unload (ccss_selector_group_t *self, + unsigned int descriptor); + bool ccss_selector_group_apply_type (ccss_selector_group_t const *self, char const *type, diff --git a/ccss/ccss-selector.c b/ccss/ccss-selector.c index 829c944..17ab68e 100644 --- a/ccss/ccss-selector.c +++ b/ccss/ccss-selector.c @@ -53,6 +53,7 @@ typedef enum { */ struct ccss_selector_ { ccss_selector_modality_t modality; + unsigned int stylesheet_descriptor; unsigned int importance : 2; unsigned int precedence : 5; unsigned int a : 5; @@ -63,7 +64,7 @@ struct ccss_selector_ { struct ccss_selector_ *refinement; struct ccss_selector_ *container; struct ccss_selector_ *antecessor; - ccss_block_t const *block; + ccss_block_t *block; }; static void @@ -73,6 +74,7 @@ selector_sync (ccss_selector_t const *self, g_assert (self && to); to->modality = self->modality; + to->stylesheet_descriptor = self->stylesheet_descriptor; to->importance = self->importance; to->precedence = self->precedence; to->a = self->a; @@ -83,7 +85,7 @@ selector_sync (ccss_selector_t const *self, to->refinement = NULL; to->container = NULL; to->antecessor = NULL; - to->block = self->block; + to->block = ccss_block_reference (self->block); } /* @@ -92,13 +94,15 @@ selector_sync (ccss_selector_t const *self, typedef ccss_selector_t ccss_universal_selector_t; ccss_selector_t * -ccss_universal_selector_create (unsigned int precedence, - ccss_selector_importance_t importance) +ccss_universal_selector_create (unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_universal_selector_t *self; self = g_new0 (ccss_universal_selector_t, 1); self->modality = CCSS_SELECTOR_MODALITY_UNIVERSAL; + self->stylesheet_descriptor = stylesheet_descriptor; self->importance = importance; self->precedence = precedence; @@ -141,8 +145,9 @@ typedef struct { ccss_selector_t * ccss_type_selector_create (char const *type_name, - unsigned int precedence, - ccss_selector_importance_t importance) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_type_selector_t *self; @@ -150,6 +155,7 @@ ccss_type_selector_create (char const *type_name, self = g_new0 (ccss_type_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_TYPE; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.d = 1; @@ -192,16 +198,19 @@ type_selector_serialize (ccss_type_selector_t const *self, */ ccss_selector_t * ccss_base_type_selector_create (char const *type_name, - unsigned int precedence, - ccss_selector_importance_t importance, - unsigned int specificity_e) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance, + unsigned int specificity_e) { ccss_selector_t *self; - self = ccss_type_selector_create (type_name, precedence, importance); + self = ccss_type_selector_create (type_name, + precedence, + stylesheet_descriptor, + importance); self->modality = CCSS_SELECTOR_MODALITY_BASE_TYPE; - self->importance = importance; - self->precedence = precedence; + self->a = 0; self->b = 0; self->c = 0; @@ -221,8 +230,9 @@ typedef struct { ccss_selector_t * ccss_class_selector_create (char const *class_name, - unsigned int precedence, - ccss_selector_importance_t importance) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_class_selector_t *self; @@ -230,6 +240,7 @@ ccss_class_selector_create (char const *class_name, self = g_new0 (ccss_class_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_CLASS; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.c = 1; @@ -276,8 +287,9 @@ typedef struct { ccss_selector_t * ccss_id_selector_create (char const *id, - unsigned int precedence, - ccss_selector_importance_t importance) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_id_selector_t *self; @@ -285,6 +297,7 @@ ccss_id_selector_create (char const *id, self = g_new0 (ccss_id_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_ID; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.b = 1; @@ -332,11 +345,12 @@ typedef struct { } ccss_attribute_selector_t; ccss_selector_t * -ccss_attribute_selector_create (char const *name, - char const *value, - ccss_attribute_selector_match_t match, - unsigned int precedence, - ccss_selector_importance_t importance) +ccss_attribute_selector_create (char const *name, + char const *value, + ccss_attribute_selector_match_t match, + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_attribute_selector_t *self; @@ -344,6 +358,7 @@ ccss_attribute_selector_create (char const *name, self = g_new0 (ccss_attribute_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_ATTRIBUTE; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.c = 1; @@ -404,8 +419,9 @@ typedef struct { ccss_selector_t * ccss_pseudo_class_selector_create (char const *pseudo_class, - unsigned int precedence, - ccss_selector_importance_t importance) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_pseudo_class_selector_t *self; @@ -413,6 +429,7 @@ ccss_pseudo_class_selector_create (char const *pseudo_class, self = g_new0 (ccss_pseudo_class_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_PSEUDO_CLASS; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.d = 1; @@ -459,8 +476,9 @@ typedef struct { ccss_selector_t * ccss_instance_selector_create (ptrdiff_t instance, - unsigned int precedence, - ccss_selector_importance_t importance) + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance) { ccss_instance_selector_t *self; @@ -468,6 +486,7 @@ ccss_instance_selector_create (ptrdiff_t instance, self = g_new0 (ccss_instance_selector_t, 1); self->parent.modality = CCSS_SELECTOR_MODALITY_INSTANCE; + self->parent.stylesheet_descriptor = stylesheet_descriptor; self->parent.importance = importance; self->parent.precedence = precedence; self->parent.a = 1; @@ -612,6 +631,11 @@ ccss_selector_destroy (ccss_selector_t *self) ccss_selector_destroy (self->antecessor), self->antecessor = NULL; } + /* Only the innermost type selector references the block. */ + if (self->block) { + ccss_block_destroy (self->block); + } + switch (self->modality) { case CCSS_SELECTOR_MODALITY_UNIVERSAL: universal_selector_destroy ((ccss_universal_selector_t *) self); @@ -778,12 +802,12 @@ ccss_selector_get_block (ccss_selector_t const *self) } void -ccss_selector_set_block (ccss_selector_t *self, - ccss_block_t const *block) +ccss_selector_set_block (ccss_selector_t *self, + ccss_block_t *block) { - g_assert (self); + g_assert (self && self->block == NULL); - self->block = block; + self->block = ccss_block_reference (block); } ccss_selector_importance_t @@ -833,6 +857,12 @@ ccss_selector_get_key (ccss_selector_t const *self) return NULL; } +unsigned int +ccss_selector_get_descriptor (ccss_selector_t const *self) +{ + return self->stylesheet_descriptor; +} + uint32_t ccss_selector_get_specificity (ccss_selector_t const *self) { @@ -1125,6 +1155,7 @@ ccss_selector_dump (ccss_selector_t const *self) selector = g_string_new (NULL); ccss_selector_serialize_selector (self, selector); g_string_append (selector, " /* "); + g_string_append_printf (selector, "'%d' ", self->stylesheet_descriptor); ccss_selector_serialize_specificity (self, selector); g_string_append (selector, " */\n"); printf ("%s", selector->str); diff --git a/ccss/ccss-selector.h b/ccss/ccss-selector.h index 3338e6d..d1420ff 100644 --- a/ccss/ccss-selector.h +++ b/ccss/ccss-selector.h @@ -53,59 +53,69 @@ typedef enum { ccss_selector_t * ccss_universal_selector_create (unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); ccss_selector_t * ccss_type_selector_create (char const *type_name, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); ccss_selector_t * ccss_base_type_selector_create (char const *type_name, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance, unsigned int specificity_e); ccss_selector_t * ccss_class_selector_create (char const *class_name, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); ccss_selector_t * ccss_id_selector_create (char const *id, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); ccss_selector_t * ccss_attribute_selector_create (char const *name, char const *value, ccss_attribute_selector_match_t match, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); ccss_selector_t * ccss_pseudo_class_selector_create (char const *pseudo_class, - unsigned int precedence, - ccss_selector_importance_t importance); + unsigned int precedence, + unsigned int stylesheet_descriptor, + ccss_selector_importance_t importance); ccss_selector_t * ccss_instance_selector_create (ptrdiff_t instance, unsigned int precedence, + unsigned int stylesheet_descriptor, ccss_selector_importance_t importance); +void ccss_selector_destroy (ccss_selector_t *self); + ccss_selector_t * ccss_selector_copy (ccss_selector_t const *original); ccss_selector_t * ccss_selector_copy_as_base (ccss_selector_t const *original, - int specificity_e); - -void ccss_selector_destroy (ccss_selector_t *self); + int specificity_e); -void ccss_selector_refine (ccss_selector_t *self, ccss_selector_t *selector); -ccss_selector_t * ccss_selector_append_child (ccss_selector_t *self, ccss_selector_t *selector); -ccss_selector_t * ccss_selector_append_descendant (ccss_selector_t *self, ccss_selector_t *selector); +void ccss_selector_refine (ccss_selector_t *self, ccss_selector_t *selector); +ccss_selector_t * ccss_selector_append_child (ccss_selector_t *self, ccss_selector_t *selector); +ccss_selector_t * ccss_selector_append_descendant (ccss_selector_t *self, ccss_selector_t *selector); bool ccss_selector_is_type (ccss_selector_t const *self); bool ccss_selector_is_class (ccss_selector_t const *self); -bool ccss_selector_is_id (ccss_selector_t const *self); +bool ccss_selector_is_id (ccss_selector_t const *self); -ccss_block_t const * ccss_selector_get_block (ccss_selector_t const *self); -void ccss_selector_set_block (ccss_selector_t *self, ccss_block_t const *block); +ccss_block_t const * ccss_selector_get_block (ccss_selector_t const *self); +void ccss_selector_set_block (ccss_selector_t *self, + ccss_block_t *block); char const * ccss_selector_get_key (ccss_selector_t const *self); ccss_selector_importance_t ccss_selector_get_importance (ccss_selector_t const *self); /*ccss_stylesheet_precedence_t ccss_selector_get_precedence (ccss_selector_t const *self);*/ +unsigned int ccss_selector_get_descriptor (ccss_selector_t const *self); uint32_t ccss_selector_get_specificity (ccss_selector_t const *self); void ccss_selector_get_specificity_values (ccss_selector_t const *self, unsigned int *a, diff --git a/ccss/ccss-stylesheet-priv.h b/ccss/ccss-stylesheet-priv.h index 4cc6c1e..8efab44 100644 --- a/ccss/ccss-stylesheet-priv.h +++ b/ccss/ccss-stylesheet-priv.h @@ -34,6 +34,7 @@ CCSS_BEGIN_DECLS * @grammar: The grammar for this stylesheet. * @blocks: List owning all blocks parsed from the stylesheet. * @groups: Associates type names with all applying selectors. + * @current_descriptor: descriptor of the recently loaded CSS file or buffer. * * Represents a parsed instance of a stylesheet. **/ @@ -43,6 +44,7 @@ struct ccss_stylesheet_ { ccss_grammar_t *grammar; GHashTable *blocks; GHashTable *groups; + unsigned int current_descriptor; }; ccss_stylesheet_t * diff --git a/ccss/ccss-stylesheet.c b/ccss/ccss-stylesheet.c index 3253e01..c22e2b9 100644 --- a/ccss/ccss-stylesheet.c +++ b/ccss/ccss-stylesheet.c @@ -37,9 +37,14 @@ ccss_stylesheet_create (void) self = g_new0 (ccss_stylesheet_t, 1); self->reference_count = 1; - self->blocks = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) ccss_block_destroy); - self->groups = g_hash_table_new (g_str_hash, g_str_equal); + self->blocks = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) ccss_block_destroy); + self->groups = g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, + (GDestroyNotify) ccss_selector_group_destroy); return self; } @@ -90,16 +95,17 @@ ccss_stylesheet_fix_dangling_selectors (ccss_stylesheet_t *self) /** * ccss_stylesheet_add_from_file: - * @self: #ccss_stylesheet_t instance or %NULL. + * @self: a #ccss_stylesheet_t. * @css_file: file to parse. * @precedence: see #ccss_stylesheet_precedence_t. * @user_data: user-data passed to property- and function-handlers. * * Load a CSS file with a given precedence. * - * Returns: a #ccss_stylesheet_t representation of the CSS file. + * Returns: a stylesheet descriptor that can be used to unload the CSS file + * contents from the stylesheet instance. **/ -ccss_stylesheet_t * +unsigned int ccss_stylesheet_add_from_file (ccss_stylesheet_t *self, char const *css_file, ccss_stylesheet_precedence_t precedence, @@ -107,16 +113,88 @@ ccss_stylesheet_add_from_file (ccss_stylesheet_t *self, { enum CRStatus ret; - g_return_val_if_fail (self && css_file, NULL); + g_return_val_if_fail (self, 0); + g_return_val_if_fail (css_file, 0); + self->current_descriptor++; ret = ccss_grammar_parse_file (self->grammar, css_file, precedence, + self->current_descriptor, user_data, self->groups, self->blocks); if (CR_OK == ret) { ccss_stylesheet_fix_dangling_selectors (self); - return self; + return self->current_descriptor; + } else { + /* TODO clean up using self->current_descriptor */ + return 0; } +} - return NULL; +/** + * ccss_stylesheet_add_from_buffer: + * @self: a #ccss_stylesheet_t. + * @buffer: buffer to parse. + * @size: size of the buffer. + * @precedence: see #ccss_stylesheet_precedence_t. + * @user_data: user-data passed to property- and function-handlers. + * + * Load a CSS file with a given precedence. + * + * Returns: a stylesheet descriptor that can be used to unload the CSS file + * contents from the stylesheet instance. + **/ +unsigned int +ccss_stylesheet_add_from_buffer (ccss_stylesheet_t *self, + char const *buffer, + size_t size, + ccss_stylesheet_precedence_t precedence, + void *user_data) +{ + enum CRStatus ret; + + g_return_val_if_fail (self, 0); + g_return_val_if_fail (buffer, 0); + g_return_val_if_fail (size, 0); + + self->current_descriptor++; + ret = ccss_grammar_parse_buffer (self->grammar, buffer, size, precedence, + self->current_descriptor, + user_data, + self->groups, self->blocks); + if (CR_OK == ret) { + ccss_stylesheet_fix_dangling_selectors (self); + return self->current_descriptor; + } else { + /* TODO clean up using self->current_descriptor */ + return 0; + } +} + +/** + * ccss_stylesheet_unload: + * @self: a #ccss_stylesheet_t. + * @descriptor descriptor of a part that was loaded. + * + * Unload a CSS file, buffer or inline style that was loaded into the stylesheet. + * + * Returns: %TRUE if anything had been unloaded. + */ +bool +ccss_stylesheet_unload (ccss_stylesheet_t *self, + unsigned int descriptor) +{ + ccss_selector_group_t *group; + GHashTableIter iter; + bool ret; + + g_return_val_if_fail (self, false); + + ret = false; + g_hash_table_iter_init (&iter, self->groups); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &group)) { + ret |= ccss_selector_group_unload (group, descriptor); + } + + return ret; } /** @@ -278,13 +356,14 @@ query_type_r (ccss_stylesheet_t const *self, * Do not recurse containers. */ static bool -query_node (ccss_stylesheet_t const *self, - ccss_node_t *node, - ccss_style_t *style) +query_node (ccss_stylesheet_t *self, + ccss_node_t *node, + ccss_style_t *style) { ccss_selector_group_t const *universal_group; ccss_selector_group_t *result_group; char const *inline_css; + unsigned int prospective_descriptor; enum CRStatus status; bool ret; @@ -304,7 +383,8 @@ query_node (ccss_stylesheet_t const *self, ret |= query_type_r (self, node, node, false, result_group); /* Handle inline styling. */ - inline_css = ccss_node_get_style (node); + prospective_descriptor = self->current_descriptor + 1; + inline_css = ccss_node_get_style (node, prospective_descriptor); if (inline_css) { ptrdiff_t instance; instance = ccss_node_get_instance (node); @@ -316,10 +396,16 @@ query_node (ccss_stylesheet_t const *self, status = ccss_grammar_parse_inline (self->grammar, inline_css, CCSS_STYLESHEET_AUTHOR, + prospective_descriptor, instance, NULL, result_group, self->blocks); ret |= (status == CR_OK); + if (CR_OK == ret) { + self->current_descriptor = prospective_descriptor; + } else { + /* TODO clean up using prospective_descriptor. */ + } } } @@ -415,10 +501,10 @@ inherit_container_style (ccss_style_t const *container_style, * successful or if no inheritance is required. **/ static bool -query_container_r (ccss_stylesheet_t const *self, - ccss_node_t *node, - GHashTable *inherit, - ccss_style_t *style) +query_container_r (ccss_stylesheet_t *self, + ccss_node_t *node, + GHashTable *inherit, + ccss_style_t *style) { ccss_node_t *container; ccss_style_t *container_style; @@ -523,22 +609,6 @@ ccss_stylesheet_query (ccss_stylesheet_t *self, return style; } -/** - * ccss_stylesheet_invalidate_node: - * @self: a #ccss_stylesheet_t. - * @instance: an instance identifyer, as returned by #ccss_node_get_instance_f. - * - * Frees parsed inline CSS asocciated to a document node. - **/ -void -ccss_stylesheet_invalidate_node (ccss_stylesheet_t const *self, - ptrdiff_t instance) -{ - g_assert (self && self->blocks); - - g_hash_table_remove (self->blocks, (gconstpointer) instance); -} - /** * ccss_stylesheet_foreach: * @self: a #ccss_stylesheet_t. diff --git a/ccss/ccss-stylesheet.h b/ccss/ccss-stylesheet.h index 8a6ccde..3f81893 100644 --- a/ccss/ccss-stylesheet.h +++ b/ccss/ccss-stylesheet.h @@ -58,12 +58,23 @@ ccss_stylesheet_get_reference_count (ccss_stylesheet_t const *self); struct ccss_grammar_ * ccss_stylesheet_get_grammar (ccss_stylesheet_t const *self); -ccss_stylesheet_t * +unsigned int ccss_stylesheet_add_from_file (ccss_stylesheet_t *self, char const *css_file, ccss_stylesheet_precedence_t precedence, void *user_data); +unsigned int +ccss_stylesheet_add_from_buffer (ccss_stylesheet_t *self, + char const *buffer, + size_t size, + ccss_stylesheet_precedence_t precedence, + void *user_data); + +bool +ccss_stylesheet_unload (ccss_stylesheet_t *self, + unsigned int descriptor); + ccss_style_t * ccss_stylesheet_query_type (ccss_stylesheet_t *self, char const *type_name); @@ -72,10 +83,6 @@ ccss_style_t * ccss_stylesheet_query (ccss_stylesheet_t *self, ccss_node_t *node); -void -ccss_stylesheet_invalidate_node (ccss_stylesheet_t const *self, - ptrdiff_t instance); - /** * ccss_stylesheet_iterator_f: * @self: a #ccss_stylesheet_t. diff --git a/ccss/ccss.sym b/ccss/ccss.sym index 511f6b8..6f031db 100644 --- a/ccss/ccss.sym +++ b/ccss/ccss.sym @@ -31,12 +31,13 @@ ccss_style_get_string ccss_style_set_property ccss_style_hash ccss_style_interpret_property +ccss_stylesheet_add_from_buffer ccss_stylesheet_add_from_file ccss_stylesheet_destroy ccss_stylesheet_dump ccss_stylesheet_foreach ccss_stylesheet_get_reference_count -ccss_stylesheet_invalidate_node ccss_stylesheet_query ccss_stylesheet_query_type ccss_stylesheet_reference +ccss_stylesheet_unload diff --git a/configure.in b/configure.in index e32ba86..15fe81f 100644 --- a/configure.in +++ b/configure.in @@ -7,8 +7,8 @@ AC_PREREQ(2.54) m4_define([ccss_version_major], [0]) -m4_define([ccss_version_minor], [4]) -m4_define([ccss_version_micro], [1]) +m4_define([ccss_version_minor], [5]) +m4_define([ccss_version_micro], [0]) m4_define([ccss_version_extra], []) m4_define([ccss_version], [ccss_version_major.ccss_version_minor.ccss_version_micro[]ccss_version_extra]) diff --git a/examples/Makefile.am b/examples/Makefile.am index 30f4029..d351e09 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -25,6 +25,7 @@ noinst_PROGRAMS = \ example-7 \ example-8 \ example-9 \ + example-10 \ $(NULL) noinst_LTLIBRARIES = libexample-8-noinst.la @@ -65,6 +66,8 @@ libexample_8_la_SOURCES = example-8.c example_9_SOURCES = example-9.c +example_10_SOURCES = example-10.c + EXTRA_DIST = \ example-3.png \ example-5.svg \ diff --git a/examples/example-10.c b/examples/example-10.c new file mode 100644 index 0000000..b0c249e --- /dev/null +++ b/examples/example-10.c @@ -0,0 +1,60 @@ +/* vim: set ts=8 sw=8 noexpandtab: */ + +#include +#include +#include +#include "config.h" + +static char const _css_1[] = " \ + a { \ + bar: 1; \ + } \ +"; + +static char const _css_2[] = " \ + a { \ + baz: 2; \ + } \ + b { \ + frob: 3; \ + } \ +"; + +int +main (int argc, + char **argv) +{ + ccss_grammar_t *grammar; + ccss_stylesheet_t *stylesheet; + unsigned int descriptor; + + grammar = ccss_grammar_create_css (); + stylesheet = ccss_grammar_create_stylesheet (grammar); + ccss_grammar_destroy (grammar); + + g_debug ("Empty stylesheet"); + ccss_stylesheet_dump (stylesheet); + + descriptor = ccss_stylesheet_add_from_buffer (stylesheet, + _css_1, sizeof (_css_1), + CCSS_STYLESHEET_AUTHOR, + NULL); + g_debug ("With buffer 1 ('%d')", descriptor); + ccss_stylesheet_dump (stylesheet); + + descriptor = ccss_stylesheet_add_from_buffer (stylesheet, + _css_2, sizeof (_css_2), + CCSS_STYLESHEET_AUTHOR, + NULL); + g_debug ("With buffer 2 ('%d')", descriptor); + ccss_stylesheet_dump (stylesheet); + + ccss_stylesheet_unload (stylesheet, descriptor); + g_debug ("Back to just buffer 1"); + ccss_stylesheet_dump (stylesheet); + + ccss_stylesheet_destroy (stylesheet); + + return EXIT_SUCCESS; +} + diff --git a/examples/example-2.c b/examples/example-2.c index 716ce60..088a1cc 100644 --- a/examples/example-2.c +++ b/examples/example-2.c @@ -26,7 +26,8 @@ get_instance (node_t const *self) } static char const * -get_style (node_t const *self) +get_style (node_t const *self, + unsigned int descriptor) { return self->inline_css; } -- cgit v1.2.3