From fc6b96707730c54fb7ac4040680d79864169b5e0 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Mon, 27 Jul 2009 19:38:34 +0000 Subject: Calculate the in-memory size of stylesheets and provide some API to access this. svn path=/trunk/libcss/; revision=8830 --- include/libcss/stylesheet.h | 2 + src/select/hash.c | 29 ++++++++++ src/select/hash.h | 2 + src/stylesheet.c | 137 ++++++++++++++++++++++++++++++++++++++++++++ src/stylesheet.h | 2 + 5 files changed, 172 insertions(+) diff --git a/include/libcss/stylesheet.h b/include/libcss/stylesheet.h index bdb45fa..940e9b7 100644 --- a/include/libcss/stylesheet.h +++ b/include/libcss/stylesheet.h @@ -54,5 +54,7 @@ css_error css_stylesheet_used_quirks(css_stylesheet *sheet, bool *quirks); css_error css_stylesheet_get_disabled(css_stylesheet *sheet, bool *disabled); css_error css_stylesheet_set_disabled(css_stylesheet *sheet, bool disabled); +css_error css_stylesheet_size(css_stylesheet *sheet, size_t *size); + #endif diff --git a/src/select/hash.c b/src/select/hash.c index 9bcfb15..df6ce4e 100644 --- a/src/select/hash.c +++ b/src/select/hash.c @@ -25,6 +25,8 @@ struct css_selector_hash { lwc_context *ctx; + size_t hash_size; + css_allocator_fn alloc; void *pw; }; @@ -65,6 +67,9 @@ css_error css_selector_hash_create(lwc_context *dict, memset(h->slots, 0, DEFAULT_SLOTS * sizeof(hash_entry)); h->n_slots = DEFAULT_SLOTS; + h->hash_size = sizeof(css_selector_hash) + + DEFAULT_SLOTS * sizeof(hash_entry); + h->ctx = lwc_context_ref(dict); h->alloc = alloc; h->pw = pw; @@ -163,6 +168,8 @@ css_error css_selector_hash_insert(css_selector_hash *hash, entry->next = prev->next; prev->next = entry; } + + hash->hash_size += sizeof(hash_entry); } return CSS_OK; @@ -216,6 +223,8 @@ css_error css_selector_hash_remove(css_selector_hash *hash, prev->next = head->next; hash->alloc(head, 0, hash->pw); + + hash->hash_size -= sizeof(hash_entry); } return CSS_OK; @@ -317,6 +326,26 @@ css_error css_selector_hash_iterate(css_selector_hash *hash, return CSS_OK; } +/** + * Determine the memory-resident size of a hash + * + * \param hash Hash to consider + * \param size Pointer to location to receive byte count + * \return CSS_OK on success. + * + * \note The returned size will represent the size of the hash datastructures, + * and will not include the size of the data stored in the hash. + */ +css_error css_selector_hash_size(css_selector_hash *hash, size_t *size) +{ + if (hash == NULL || size == NULL) + return CSS_BADPARM; + + *size = hash->hash_size; + + return CSS_OK; +} + /****************************************************************************** * Private functions * ******************************************************************************/ diff --git a/src/select/hash.h b/src/select/hash.h index 59c8b76..9beaa6b 100644 --- a/src/select/hash.h +++ b/src/select/hash.h @@ -35,5 +35,7 @@ css_error css_selector_hash_iterate(css_selector_hash *hash, const struct css_selector **current, const struct css_selector ***next); +css_error css_selector_hash_size(css_selector_hash *hash, size_t *size); + #endif diff --git a/src/stylesheet.c b/src/stylesheet.c index 7ec55b2..9afd5cc 100644 --- a/src/stylesheet.c +++ b/src/stylesheet.c @@ -16,6 +16,7 @@ static css_error _add_selectors(css_stylesheet *sheet, css_rule *rule); static css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule); +static size_t _rule_size(const css_rule *rule); /** * Create a stylesheet @@ -144,6 +145,10 @@ css_error css_stylesheet_create(css_language_level level, sheet->alloc = alloc; sheet->pw = alloc_pw; + sheet->size = sizeof(css_stylesheet) + strlen(sheet->url); + if (sheet->title != NULL) + sheet->size += strlen(sheet->title); + *stylesheet = sheet; return CSS_OK; @@ -506,6 +511,42 @@ css_error css_stylesheet_set_disabled(css_stylesheet *sheet, bool disabled) return CSS_OK; } +/** + * Determine the memory-resident size of a stylesheet + * + * \param sheet Sheet to consider + * \param size Pointer to location to receive byte count + * \return CSS_OK on success. + * + * \note The returned size will not include the size of interned strings + * or imported stylesheets. + */ +css_error css_stylesheet_size(css_stylesheet *sheet, size_t *size) +{ + size_t bytes = 0; + css_error error; + + if (sheet == NULL || size == NULL) + return CSS_BADPARM; + + bytes = sheet->size; + + /* Selector hash */ + if (sheet->selectors != NULL) { + size_t hash_size; + + error = css_selector_hash_size(sheet->selectors, &hash_size); + if (error != CSS_OK) + return error; + + bytes += hash_size; + } + + *size = bytes; + + return CSS_OK; +} + /****************************************************************************** * Library-private API below here * ******************************************************************************/ @@ -1042,11 +1083,17 @@ css_error css_stylesheet_rule_append_style(css_stylesheet *sheet, cur = temp; cur->length += style->length; + /* Add this to the sheet's size */ + sheet->size += style->length; + /* Done with style */ css_stylesheet_style_destroy(sheet, style); } else { /* No current style, so use this one */ cur = style; + + /* Add to the sheet's size */ + sheet->size += style->length; } if (rule->type == CSS_RULE_SELECTOR) @@ -1192,6 +1239,9 @@ css_error css_stylesheet_add_rule(css_stylesheet *sheet, css_rule *rule, if (error != CSS_OK) return error; + /* Add to the sheet's size */ + sheet->size += _rule_size(rule); + if (parent != NULL) { css_rule_media *media = (css_rule_media *) parent; @@ -1252,6 +1302,9 @@ css_error css_stylesheet_remove_rule(css_stylesheet *sheet, css_rule *rule) if (error != CSS_OK) return error; + /* Reduce sheet's size */ + sheet->size -= _rule_size(rule); + if (rule->next == NULL) sheet->last_rule = rule->prev; else @@ -1392,3 +1445,87 @@ css_error _remove_selectors(css_stylesheet *sheet, css_rule *rule) return CSS_OK; } +/** + * Calculate the size of a rule + * + * \param r Rule to consider + * \return Size in bytes + * + * \note The returned size does not include interned strings. + */ +size_t _rule_size(const css_rule *r) +{ + size_t bytes = 0; + + if (r->type == CSS_RULE_SELECTOR) { + const css_rule_selector *rs = (const css_rule_selector *) r; + uint32_t i; + + bytes += sizeof(css_rule_selector); + + /* Process selector chains */ + bytes += r->items * sizeof(css_selector *); + for (i = 0; i < r->items; i++) { + const css_selector *s = rs->selectors[i]; + + do { + const css_selector_detail *d = &s->data; + + bytes += sizeof(css_selector); + + while (d->next) { + bytes += sizeof(css_selector_detail); + d++; + } + + s = s->combinator; + } while (s != NULL); + } + + if (rs->style != NULL) + bytes += rs->style->length; + } else if (r->type == CSS_RULE_CHARSET) { + bytes += sizeof(css_rule_charset); + } else if (r->type == CSS_RULE_IMPORT) { + bytes += sizeof(css_rule_import); + } else if (r->type == CSS_RULE_MEDIA) { + const css_rule_media *rm = (const css_rule_media *) r; + const css_rule *c; + + bytes += sizeof(css_rule_media); + + /* Process children */ + for (c = rm->first_child; c != NULL; c = c->next) + bytes += _rule_size(c); + } else if (r->type == CSS_RULE_FONT_FACE) { + const css_rule_font_face *rf = (const css_rule_font_face *) r; + + bytes += sizeof(css_rule_font_face); + + if (rf->style != NULL) + bytes += rf->style->length; + } else if (r->type == CSS_RULE_PAGE) { + const css_rule_page *rp = (const css_rule_page *) r; + const css_selector *s = rp->selector; + + /* Process selector chain */ + while (s != NULL) { + const css_selector_detail *d = &s->data; + + bytes += sizeof(css_selector); + + while (d->next) { + bytes += sizeof(css_selector_detail); + d++; + } + + s = s->combinator; + } + + if (rp->style != NULL) + bytes += rp->style->length; + } + + return bytes; +} + diff --git a/src/stylesheet.h b/src/stylesheet.h index 4ac560c..80b58b0 100644 --- a/src/stylesheet.h +++ b/src/stylesheet.h @@ -175,6 +175,8 @@ struct css_stylesheet { bool inline_style; /**< Is an inline style */ + size_t size; /**< Size, in bytes */ + css_url_resolution_fn resolve; /**< URL resolution function */ void *resolve_pw; /**< Private word */ -- cgit v1.2.1