summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Makefile.common3
-rw-r--r--build/Makefile.config4
-rw-r--r--src/select/propset.h18
-rw-r--r--src/select/select.c455
-rw-r--r--test/data/select/tests1.dat27
-rw-r--r--test/dump.h2
-rw-r--r--test/dump_computed.h301
-rw-r--r--test/select-auto.c10
8 files changed, 688 insertions, 132 deletions
diff --git a/build/Makefile.common b/build/Makefile.common
index f6bc147..73a4880 100644
--- a/build/Makefile.common
+++ b/build/Makefile.common
@@ -24,6 +24,9 @@ TARGET_TESTS :=
# Source files
SOURCES :=
+# Include configuration Makefile fragment
+include build/Makefile.config
+
# Include Makefile fragments in subdirectories
define do_include
diff --git a/build/Makefile.config b/build/Makefile.config
new file mode 100644
index 0000000..1d27350
--- /dev/null
+++ b/build/Makefile.config
@@ -0,0 +1,4 @@
+# Configuration Makefile fragment
+
+# Cater for local configuration changes
+-include build/Makefile.config.override
diff --git a/src/select/propset.h b/src/select/propset.h
index ff9658c..bdc85bb 100644
--- a/src/select/propset.h
+++ b/src/select/propset.h
@@ -457,8 +457,13 @@ static inline css_error set_background_image(
*bits = (*bits & ~BACKGROUND_IMAGE_MASK) |
((type & 0x1) << BACKGROUND_IMAGE_SHIFT);
- style->background_image.data = (uint8_t *) url->data;
- style->background_image.len = url->len;
+ if (url != NULL) {
+ style->background_image.data = (uint8_t *) url->data;
+ style->background_image.len = url->len;
+ } else {
+ style->background_image.data = NULL;
+ style->background_image.len = 0;
+ }
return CSS_OK;
}
@@ -500,8 +505,13 @@ static inline css_error set_list_style_image(
*bits = (*bits & ~LIST_STYLE_IMAGE_MASK) |
((type & 0x1) << LIST_STYLE_IMAGE_SHIFT);
- style->list_style_image.data = (uint8_t *) url->data;
- style->list_style_image.len = url->len;
+ if (url != NULL) {
+ style->list_style_image.data = (uint8_t *) url->data;
+ style->list_style_image.len = url->len;
+ } else {
+ style->list_style_image.data = NULL;
+ style->list_style_image.len = 0;
+ }
return CSS_OK;
}
diff --git a/src/select/select.c b/src/select/select.c
index 2397bf8..5fafcd1 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -58,16 +58,33 @@ typedef struct css_select_state {
css_origin current_origin; /* Origin of current sheet */
uint32_t current_specificity; /* Specificity of current rule */
+ /* Useful interned strings */
+ const parserutils_hash_entry *universal;
+ const parserutils_hash_entry *first_child;
+ const parserutils_hash_entry *link;
+ const parserutils_hash_entry *visited;
+ const parserutils_hash_entry *hover;
+ const parserutils_hash_entry *active;
+ const parserutils_hash_entry *focus;
+ const parserutils_hash_entry *left;
+ const parserutils_hash_entry *right;
+ const parserutils_hash_entry *first;
+ const parserutils_hash_entry *first_line;
+ const parserutils_hash_entry *first_letter;
+ const parserutils_hash_entry *before;
+ const parserutils_hash_entry *after;
+
prop_state props[N_OPCODES];
} css_select_state;
static css_error select_from_sheet(css_select_ctx *ctx,
const css_stylesheet *sheet, css_select_state *state);
+static css_error intern_strings_for_sheet(css_select_ctx *ctx,
+ const css_stylesheet *sheet, css_select_state *state);
static css_error match_selectors_in_sheet(css_select_ctx *ctx,
const css_stylesheet *sheet, css_select_state *state);
static css_error match_selector_chain(css_select_ctx *ctx,
- const css_selector *selector, css_select_state *state,
- const parserutils_hash_entry *universal);
+ const css_selector *selector, css_select_state *state);
static css_error match_named_combinator(css_select_ctx *ctx,
css_combinator type, const parserutils_hash_entry *name,
css_select_state *state, void *node, void **next_node);
@@ -89,6 +106,16 @@ static bool outranks_existing(uint16_t op, bool important,
#include "select/properties.c"
/**
+ * Enumeration of property groups
+ */
+enum prop_group {
+ GROUP_NORMAL = 0x0,
+ GROUP_UNCOMMON = 0x1,
+ GROUP_PAGE = 0x2,
+ GROUP_AURAL = 0x3
+};
+
+/**
* Dispatch table for properties, indexed by opcode
*/
static struct prop_table {
@@ -96,107 +123,108 @@ static struct prop_table {
css_select_state *state);
css_error (*initial)(css_computed_style *style);
- uint32_t inherited : 1;
+ uint32_t inherited : 1,
+ group : 2;
} properties[N_OPCODES] = {
- { cascade_azimuth, initial_azimuth, 1 },
- { cascade_background_attachment, initial_background_attachment, 0 },
- { cascade_background_color, initial_background_color, 0 },
- { cascade_background_image, initial_background_image, 0 },
- { cascade_background_position, initial_background_position, 0 },
- { cascade_background_repeat, initial_background_repeat, 0 },
- { cascade_border_collapse, initial_border_collapse, 1 },
- { cascade_border_spacing, initial_border_spacing, 1 },
- { cascade_border_top_color, initial_border_top_color, 0 },
- { cascade_border_right_color, initial_border_right_color, 0 },
- { cascade_border_bottom_color, initial_border_bottom_color, 0 },
- { cascade_border_left_color, initial_border_left_color, 0 },
- { cascade_border_top_style, initial_border_top_style, 0 },
- { cascade_border_right_style, initial_border_right_style, 0 },
- { cascade_border_bottom_style, initial_border_bottom_style, 0 },
- { cascade_border_left_style, initial_border_left_style, 0 },
- { cascade_border_top_width, initial_border_top_width, 0 },
- { cascade_border_right_width, initial_border_right_width, 0 },
- { cascade_border_bottom_width, initial_border_bottom_width, 0 },
- { cascade_border_left_width, initial_border_left_width, 0 },
- { cascade_bottom, initial_bottom, 0 },
- { cascade_caption_side, initial_caption_side, 1 },
- { cascade_clear, initial_clear, 0 },
- { cascade_clip, initial_clip, 0 },
- { cascade_color, initial_color, 1 },
- { cascade_content, initial_content, 0 },
- { cascade_counter_increment, initial_counter_increment, 0 },
- { cascade_counter_reset, initial_counter_reset, 0 },
- { cascade_cue_after, initial_cue_after, 0 },
- { cascade_cue_before, initial_cue_before, 0 },
- { cascade_cursor, initial_cursor, 1 },
- { cascade_direction, initial_direction, 1 },
- { cascade_display, initial_display, 0 },
- { cascade_elevation, initial_elevation, 1 },
- { cascade_empty_cells, initial_empty_cells, 1 },
- { cascade_float, initial_float, 0 },
- { cascade_font_family, initial_font_family, 1 },
- { cascade_font_size, initial_font_size, 1 },
- { cascade_font_style, initial_font_style, 1 },
- { cascade_font_variant, initial_font_variant, 1 },
- { cascade_font_weight, initial_font_weight, 1 },
- { cascade_height, initial_height, 0 },
- { cascade_left, initial_left, 0 },
- { cascade_letter_spacing, initial_letter_spacing, 1 },
- { cascade_line_height, initial_line_height, 1 },
- { cascade_list_style_image, initial_list_style_image, 1 },
- { cascade_list_style_position, initial_list_style_position, 1 },
- { cascade_list_style_type, initial_list_style_type, 1 },
- { cascade_margin_top, initial_margin_top, 0 },
- { cascade_margin_right, initial_margin_right, 0 },
- { cascade_margin_bottom, initial_margin_bottom, 0 },
- { cascade_margin_left, initial_margin_left, 0 },
- { cascade_max_height, initial_max_height, 0 },
- { cascade_max_width, initial_max_width, 0 },
- { cascade_min_height, initial_min_height, 0 },
- { cascade_min_width, initial_min_width, 0 },
- { cascade_orphans, initial_orphans, 1 },
- { cascade_outline_color, initial_outline_color, 0 },
- { cascade_outline_style, initial_outline_style, 0 },
- { cascade_outline_width, initial_outline_width, 0 },
- { cascade_overflow, initial_overflow, 0 },
- { cascade_padding_top, initial_padding_top, 0 },
- { cascade_padding_right, initial_padding_right, 0 },
- { cascade_padding_bottom, initial_padding_bottom, 0 },
- { cascade_padding_left, initial_padding_left, 0 },
- { cascade_page_break_after, initial_page_break_after, 0 },
- { cascade_page_break_before, initial_page_break_before, 0 },
- { cascade_page_break_inside, initial_page_break_inside, 1 },
- { cascade_pause_after, initial_pause_after, 0 },
- { cascade_pause_before, initial_pause_before, 0 },
- { cascade_pitch_range, initial_pitch_range, 1 },
- { cascade_pitch, initial_pitch, 1 },
- { cascade_play_during, initial_play_during, 0 },
- { cascade_position, initial_position, 0 },
- { cascade_quotes, initial_quotes, 1 },
- { cascade_richness, initial_richness, 1 },
- { cascade_right, initial_right, 0 },
- { cascade_speak_header, initial_speak_header, 1 },
- { cascade_speak_numeral, initial_speak_numeral, 1 },
- { cascade_speak_punctuation, initial_speak_punctuation, 1 },
- { cascade_speak, initial_speak, 1 },
- { cascade_speech_rate, initial_speech_rate, 1 },
- { cascade_stress, initial_stress, 1 },
- { cascade_table_layout, initial_table_layout, 0 },
- { cascade_text_align, initial_text_align, 1 },
- { cascade_text_decoration, initial_text_decoration, 0 },
- { cascade_text_indent, initial_text_indent, 1 },
- { cascade_text_transform, initial_text_transform, 1 },
- { cascade_top, initial_top, 0 },
- { cascade_unicode_bidi, initial_unicode_bidi, 0 },
- { cascade_vertical_align, initial_vertical_align, 0 },
- { cascade_visibility, initial_visibility, 1 },
- { cascade_voice_family, initial_voice_family, 1 },
- { cascade_volume, initial_volume, 1 },
- { cascade_white_space, initial_white_space, 1 },
- { cascade_widows, initial_widows, 1 },
- { cascade_width, initial_width, 0 },
- { cascade_word_spacing, initial_word_spacing, 1 },
- { cascade_z_index, initial_z_index, 0 }
+ { cascade_azimuth, initial_azimuth, 1, GROUP_AURAL},
+ { cascade_background_attachment, initial_background_attachment, 0, GROUP_NORMAL },
+ { cascade_background_color, initial_background_color, 0, GROUP_NORMAL },
+ { cascade_background_image, initial_background_image, 0, GROUP_NORMAL },
+ { cascade_background_position, initial_background_position, 0, GROUP_NORMAL },
+ { cascade_background_repeat, initial_background_repeat, 0, GROUP_NORMAL },
+ { cascade_border_collapse, initial_border_collapse, 1, GROUP_NORMAL },
+ { cascade_border_spacing, initial_border_spacing, 1, GROUP_UNCOMMON },
+ { cascade_border_top_color, initial_border_top_color, 0, GROUP_NORMAL },
+ { cascade_border_right_color, initial_border_right_color, 0, GROUP_NORMAL },
+ { cascade_border_bottom_color, initial_border_bottom_color, 0, GROUP_NORMAL },
+ { cascade_border_left_color, initial_border_left_color, 0, GROUP_NORMAL },
+ { cascade_border_top_style, initial_border_top_style, 0, GROUP_NORMAL },
+ { cascade_border_right_style, initial_border_right_style, 0, GROUP_NORMAL },
+ { cascade_border_bottom_style, initial_border_bottom_style, 0, GROUP_NORMAL },
+ { cascade_border_left_style, initial_border_left_style, 0, GROUP_NORMAL },
+ { cascade_border_top_width, initial_border_top_width, 0, GROUP_NORMAL },
+ { cascade_border_right_width, initial_border_right_width, 0, GROUP_NORMAL },
+ { cascade_border_bottom_width, initial_border_bottom_width, 0, GROUP_NORMAL },
+ { cascade_border_left_width, initial_border_left_width, 0, GROUP_NORMAL },
+ { cascade_bottom, initial_bottom, 0, GROUP_NORMAL },
+ { cascade_caption_side, initial_caption_side, 1, GROUP_NORMAL },
+ { cascade_clear, initial_clear, 0, GROUP_NORMAL },
+ { cascade_clip, initial_clip, 0, GROUP_UNCOMMON },
+ { cascade_color, initial_color, 1, GROUP_NORMAL },
+ { cascade_content, initial_content, 0, GROUP_UNCOMMON },
+ { cascade_counter_increment, initial_counter_increment, 0, GROUP_UNCOMMON },
+ { cascade_counter_reset, initial_counter_reset, 0, GROUP_UNCOMMON },
+ { cascade_cue_after, initial_cue_after, 0, GROUP_AURAL },
+ { cascade_cue_before, initial_cue_before, 0, GROUP_AURAL },
+ { cascade_cursor, initial_cursor, 1, GROUP_UNCOMMON },
+ { cascade_direction, initial_direction, 1, GROUP_NORMAL },
+ { cascade_display, initial_display, 0, GROUP_NORMAL },
+ { cascade_elevation, initial_elevation, 1, GROUP_AURAL },
+ { cascade_empty_cells, initial_empty_cells, 1, GROUP_NORMAL },
+ { cascade_float, initial_float, 0, GROUP_NORMAL },
+ { cascade_font_family, initial_font_family, 1, GROUP_NORMAL },
+ { cascade_font_size, initial_font_size, 1, GROUP_NORMAL },
+ { cascade_font_style, initial_font_style, 1, GROUP_NORMAL },
+ { cascade_font_variant, initial_font_variant, 1, GROUP_NORMAL },
+ { cascade_font_weight, initial_font_weight, 1, GROUP_NORMAL },
+ { cascade_height, initial_height, 0, GROUP_NORMAL },
+ { cascade_left, initial_left, 0, GROUP_NORMAL },
+ { cascade_letter_spacing, initial_letter_spacing, 1, GROUP_UNCOMMON },
+ { cascade_line_height, initial_line_height, 1, GROUP_NORMAL },
+ { cascade_list_style_image, initial_list_style_image, 1, GROUP_NORMAL },
+ { cascade_list_style_position, initial_list_style_position, 1, GROUP_NORMAL },
+ { cascade_list_style_type, initial_list_style_type, 1, GROUP_NORMAL },
+ { cascade_margin_top, initial_margin_top, 0, GROUP_NORMAL },
+ { cascade_margin_right, initial_margin_right, 0, GROUP_NORMAL },
+ { cascade_margin_bottom, initial_margin_bottom, 0, GROUP_NORMAL },
+ { cascade_margin_left, initial_margin_left, 0, GROUP_NORMAL },
+ { cascade_max_height, initial_max_height, 0, GROUP_NORMAL },
+ { cascade_max_width, initial_max_width, 0, GROUP_NORMAL },
+ { cascade_min_height, initial_min_height, 0, GROUP_NORMAL },
+ { cascade_min_width, initial_min_width, 0, GROUP_NORMAL },
+ { cascade_orphans, initial_orphans, 1, GROUP_PAGE },
+ { cascade_outline_color, initial_outline_color, 0, GROUP_UNCOMMON },
+ { cascade_outline_style, initial_outline_style, 0, GROUP_NORMAL },
+ { cascade_outline_width, initial_outline_width, 0, GROUP_UNCOMMON },
+ { cascade_overflow, initial_overflow, 0, GROUP_NORMAL },
+ { cascade_padding_top, initial_padding_top, 0, GROUP_NORMAL },
+ { cascade_padding_right, initial_padding_right, 0, GROUP_NORMAL },
+ { cascade_padding_bottom, initial_padding_bottom, 0, GROUP_NORMAL },
+ { cascade_padding_left, initial_padding_left, 0, GROUP_NORMAL },
+ { cascade_page_break_after, initial_page_break_after, 0, GROUP_PAGE },
+ { cascade_page_break_before, initial_page_break_before, 0, GROUP_PAGE },
+ { cascade_page_break_inside, initial_page_break_inside, 1, GROUP_PAGE },
+ { cascade_pause_after, initial_pause_after, 0, GROUP_AURAL },
+ { cascade_pause_before, initial_pause_before, 0, GROUP_AURAL },
+ { cascade_pitch_range, initial_pitch_range, 1, GROUP_AURAL },
+ { cascade_pitch, initial_pitch, 1, GROUP_AURAL },
+ { cascade_play_during, initial_play_during, 0, GROUP_AURAL },
+ { cascade_position, initial_position, 0, GROUP_NORMAL },
+ { cascade_quotes, initial_quotes, 1, GROUP_UNCOMMON },
+ { cascade_richness, initial_richness, 1, GROUP_AURAL },
+ { cascade_right, initial_right, 0, GROUP_NORMAL },
+ { cascade_speak_header, initial_speak_header, 1, GROUP_AURAL },
+ { cascade_speak_numeral, initial_speak_numeral, 1, GROUP_AURAL },
+ { cascade_speak_punctuation, initial_speak_punctuation, 1, GROUP_AURAL },
+ { cascade_speak, initial_speak, 1, GROUP_AURAL },
+ { cascade_speech_rate, initial_speech_rate, 1, GROUP_AURAL },
+ { cascade_stress, initial_stress, 1, GROUP_AURAL },
+ { cascade_table_layout, initial_table_layout, 0, GROUP_NORMAL },
+ { cascade_text_align, initial_text_align, 1, GROUP_NORMAL },
+ { cascade_text_decoration, initial_text_decoration, 0, GROUP_NORMAL },
+ { cascade_text_indent, initial_text_indent, 1, GROUP_NORMAL },
+ { cascade_text_transform, initial_text_transform, 1, GROUP_NORMAL },
+ { cascade_top, initial_top, 0, GROUP_NORMAL },
+ { cascade_unicode_bidi, initial_unicode_bidi, 0, GROUP_NORMAL },
+ { cascade_vertical_align, initial_vertical_align, 0, GROUP_NORMAL },
+ { cascade_visibility, initial_visibility, 1, GROUP_NORMAL },
+ { cascade_voice_family, initial_voice_family, 1, GROUP_AURAL },
+ { cascade_volume, initial_volume, 1, GROUP_AURAL },
+ { cascade_white_space, initial_white_space, 1, GROUP_NORMAL },
+ { cascade_widows, initial_widows, 1, GROUP_PAGE },
+ { cascade_width, initial_width, 0, GROUP_NORMAL },
+ { cascade_word_spacing, initial_word_spacing, 1, GROUP_UNCOMMON },
+ { cascade_z_index, initial_z_index, 0, GROUP_NORMAL }
};
/**
@@ -385,7 +413,7 @@ css_error css_select_ctx_get_sheet(css_select_ctx *ctx, uint32_t index,
* \param pseudo_element Pseudo element to select for, instead
* \param pseudo_classes Currently active pseudo classes
* \param media Currently active media types
- * \param result Pointer to style to populate
+ * \param result Pointer to style to populate (assumed clean)
* \param handler Dispatch table of handler functions
* \param pw Client-specific private data for handler functions
* \return CSS_OK on success, appropriate error otherwise.
@@ -435,7 +463,45 @@ css_error css_select_style(css_select_ctx *ctx, void *node,
* Those properties which are inherited need to be set as inherit.
* Those which are not inherited need to be set to their default value.
*/
- /** \todo fixup unset properties */
+ for (i = 0; i < N_OPCODES; i++) {
+ /* Do nothing if this property is set */
+ if (state.props[i].set)
+ continue;
+
+ /* Do nothing if this property is inherited (the default state
+ * of a clean computed style is for everything to be set to
+ * inherit) */
+ if (properties[i].inherited)
+ continue;
+
+ /* Remaining properties are neither inherited nor already set.
+ * Thus, we set them to their initial values here. Except,
+ * however, if the property in question resides in one of the
+ * extension blocks and the extension block has yet to be
+ * allocated. In that case, we do nothing and leave it to the
+ * property accessors to return the initial values for the
+ * property. */
+ if (properties[i].group == GROUP_NORMAL) {
+ error = properties[i].initial(result);
+ if (error != CSS_OK)
+ return error;
+ } else if (properties[i].group == GROUP_UNCOMMON &&
+ result->uncommon != NULL) {
+ error = properties[i].initial(result);
+ if (error != CSS_OK)
+ return error;
+ } else if (properties[i].group == GROUP_PAGE &&
+ result->page != NULL) {
+ error = properties[i].initial(result);
+ if (error != CSS_OK)
+ return error;
+ } else if (properties[i].group == GROUP_AURAL &&
+ result->aural != NULL) {
+ error = properties[i].initial(result);
+ if (error != CSS_OK)
+ return error;
+ }
+ }
return CSS_OK;
}
@@ -482,6 +548,10 @@ css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet,
state->sheet = s;
state->current_origin = s->origin;
+ error = intern_strings_for_sheet(ctx, s, state);
+ if (error != CSS_OK)
+ return error;
+
error = match_selectors_in_sheet(ctx, s, state);
if (error != CSS_OK)
return error;
@@ -499,10 +569,105 @@ css_error select_from_sheet(css_select_ctx *ctx, const css_stylesheet *sheet,
return CSS_OK;
}
+css_error intern_strings_for_sheet(css_select_ctx *ctx,
+ const css_stylesheet *sheet, css_select_state *state)
+{
+ parserutils_error perror;
+
+ UNUSED(ctx);
+
+ /* Universal selector */
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "*", SLEN("*"), &state->universal);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ /* Pseudo classes */
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "first-child", SLEN("first-child"),
+ &state->first_child);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "link", SLEN("link"),
+ &state->link);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "visited", SLEN("visited"),
+ &state->visited);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "hover", SLEN("hover"),
+ &state->hover);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "active", SLEN("active"),
+ &state->active);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "focus", SLEN("focus"),
+ &state->focus);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "left", SLEN("left"),
+ &state->left);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "right", SLEN("right"),
+ &state->right);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "first", SLEN("first"),
+ &state->first);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ /* Pseudo elements */
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "first-line", SLEN("first-line"),
+ &state->first_line);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "first_letter", SLEN("first-letter"),
+ &state->first_letter);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "before", SLEN("before"),
+ &state->before);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ perror = parserutils_hash_insert(sheet->dictionary,
+ (const uint8_t *) "after", SLEN("after"),
+ &state->after);
+ if (perror != PARSERUTILS_OK)
+ return css_error_from_parserutils_error(perror);
+
+ return CSS_OK;
+}
+
css_error match_selectors_in_sheet(css_select_ctx *ctx,
const css_stylesheet *sheet, css_select_state *state)
{
- const parserutils_hash_entry *universal;
const parserutils_hash_entry *element;
const css_selector **selectors;
const uint8_t *name;
@@ -521,12 +686,6 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx,
if (perror != PARSERUTILS_OK)
return css_error_from_parserutils_error(perror);
- /* Intern universal selector string */
- perror = parserutils_hash_insert(sheet->dictionary,
- (const uint8_t *) "*", 1, &universal);
- if (perror != PARSERUTILS_OK)
- return css_error_from_parserutils_error(perror);
-
/* Find hash chain that applies to current node */
error = css_selector_hash_find(sheet->selectors, element, &selectors);
if (error != CSS_OK)
@@ -534,7 +693,7 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx,
/* Process any matching selectors */
while (*selectors != NULL) {
- error = match_selector_chain(ctx, *selectors, state, universal);
+ error = match_selector_chain(ctx, *selectors, state);
if (error != CSS_OK)
return error;
@@ -545,13 +704,14 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx,
}
/* Find hash chain for universal selector */
- error = css_selector_hash_find(sheet->selectors, universal, &selectors);
+ error = css_selector_hash_find(sheet->selectors, state->universal,
+ &selectors);
if (error != CSS_OK)
return error;
/* Process any matching selectors */
while (*selectors != NULL) {
- error = match_selector_chain(ctx, *selectors, state, universal);
+ error = match_selector_chain(ctx, *selectors, state);
if (error != CSS_OK)
return error;
@@ -565,8 +725,7 @@ css_error match_selectors_in_sheet(css_select_ctx *ctx,
}
css_error match_selector_chain(css_select_ctx *ctx,
- const css_selector *selector, css_select_state *state,
- const parserutils_hash_entry *universal)
+ const css_selector *selector, css_select_state *state)
{
const css_selector *s = selector;
void *node = state->node;
@@ -579,7 +738,7 @@ css_error match_selector_chain(css_select_ctx *ctx,
/* First, consider any named combinator on this selector */
if (s->data.comb != CSS_COMBINATOR_NONE &&
- s->combinator->data.name != universal) {
+ s->combinator->data.name != state->universal) {
error = match_named_combinator(ctx, s->data.comb,
s->combinator->data.name, state, node,
&next_node);
@@ -602,7 +761,7 @@ css_error match_selector_chain(css_select_ctx *ctx,
/* If we had a universal combinator, then consider that */
if (s->data.comb != CSS_COMBINATOR_NONE &&
- s->combinator->data.name == universal) {
+ s->combinator->data.name == state->universal) {
error = match_universal_combinator(ctx, s->data.comb,
s->combinator, state, node, &next_node);
if (error != CSS_OK)
@@ -762,12 +921,64 @@ css_error match_detail(css_select_ctx *ctx, void *node,
match);
break;
case CSS_SELECTOR_PSEUDO_CLASS:
- /** \todo pseudo classes */
- *match = false;
+ if (detail->name == state->first_child &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_FIRST_CHILD))
+ *match = true;
+ else if (detail->name == state->link &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_LINK))
+ *match = true;
+ else if (detail->name == state->visited &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_VISITED))
+ *match = true;
+ else if (detail->name == state->hover &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_HOVER))
+ *match = true;
+ else if (detail->name == state->active &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_ACTIVE))
+ *match = true;
+ else if (detail->name == state->focus &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_FOCUS))
+ *match = true;
+ else if (detail->name == state->left &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_LEFT))
+ *match = true;
+ else if (detail->name == state->right &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_RIGHT))
+ *match = true;
+ else if (detail->name == state->first &&
+ (state->pseudo_classes &
+ CSS_PSEUDO_CLASS_FIRST))
+ *match = true;
+ else
+ *match = false;
break;
case CSS_SELECTOR_PSEUDO_ELEMENT:
- /** \todo pseudo elements */
- *match = false;
+ if (detail->name == state->first_line &&
+ (state->pseudo_element &
+ CSS_PSEUDO_ELEMENT_FIRST_LINE))
+ *match = true;
+ else if (detail->name == state->first_letter &&
+ (state->pseudo_element &
+ CSS_PSEUDO_ELEMENT_FIRST_LETTER))
+ *match = true;
+ else if (detail->name == state->before &&
+ (state->pseudo_element &
+ CSS_PSEUDO_ELEMENT_BEFORE))
+ *match = true;
+ else if (detail->name == state->after &&
+ (state->pseudo_element &
+ CSS_PSEUDO_ELEMENT_AFTER))
+ *match = true;
+ else
+ *match = false;
break;
case CSS_SELECTOR_ATTRIBUTE:
error = state->handler->node_has_attribute(state->pw, node,
diff --git a/test/data/select/tests1.dat b/test/data/select/tests1.dat
index d8a55b0..5b415f3 100644
--- a/test/data/select/tests1.dat
+++ b/test/data/select/tests1.dat
@@ -12,6 +12,15 @@ div#foo { background-color: #bbc; }
.green { color: #0f0; }
#errors
#expected
+background-attachment: scroll
+background-color: transparent
+background-image: none
+background-position: 0% 0%
+background-repeat: repeat
+border-top-color: #00000000
+border-right-color: #00000000
+border-bottom-color: #00000000
+border-left-color: #00000000
color: #ff000000
display: block
#reset
@@ -24,6 +33,15 @@ div { display: block; }
div { display: inline; }
#errors
#expected
+background-attachment: scroll
+background-color: transparent
+background-image: none
+background-position: 0% 0%
+background-repeat: repeat
+border-top-color: #00000000
+border-right-color: #00000000
+border-bottom-color: #00000000
+border-left-color: #00000000
display: block
#reset
@@ -34,6 +52,15 @@ div { background-color: #000; }
div:active { background-color: #bbc; }
#errors
#expected
+background-attachment: scroll
background-color: #bbbbcc00
+background-image: none
+background-position: 0% 0%
+background-repeat: repeat
+border-top-color: #00000000
+border-right-color: #00000000
+border-bottom-color: #00000000
+border-left-color: #00000000
+display: inline
#reset
diff --git a/test/dump.h b/test/dump.h
index c217565..98ec1bb 100644
--- a/test/dump.h
+++ b/test/dump.h
@@ -436,7 +436,7 @@ static void dump_unit(fixed val, uint32_t unit, char **ptr)
*ptr += sprintf(*ptr, "rad");
break;
case UNIT_MS:
- *ptr += printf(*ptr, "ms");
+ *ptr += sprintf(*ptr, "ms");
break;
case UNIT_S:
*ptr += sprintf(*ptr, "s");
diff --git a/test/dump_computed.h b/test/dump_computed.h
index dda07c1..f573e9d 100644
--- a/test/dump_computed.h
+++ b/test/dump_computed.h
@@ -1,6 +1,141 @@
#include <libcss/computed.h>
#include <libcss/properties.h>
+#include "utils/fpmath.h"
+
+static size_t dump_css_fixed(css_fixed f, char *ptr, size_t len)
+{
+#define ABS(x) (uint32_t)((x) < 0 ? -(x) : (x))
+ uint32_t uintpart = FIXTOINT(ABS(f));
+ /* + 500 to ensure round to nearest (division will truncate) */
+ uint32_t fracpart = ((ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10);
+#undef ABS
+ size_t flen = 0;
+ char tmp[20];
+ size_t tlen = 0;
+ char *buf = ptr;
+
+ if (len == 0)
+ return 0;
+
+ if (f < 0) {
+ buf[0] = '-';
+ buf++;
+ len--;
+ }
+
+ do {
+ tmp[tlen] = "0123456789"[uintpart % 10];
+ tlen++;
+
+ uintpart /= 10;
+ } while (tlen < 20 && uintpart != 0);
+
+ while (tlen > 0 && len > 0) {
+ buf[0] = tmp[--tlen];
+ buf++;
+ len--;
+ }
+
+ if (len > 0) {
+ buf[0] = '.';
+ buf++;
+ len--;
+ }
+
+ do {
+ tmp[tlen] = "0123456789"[fracpart % 10];
+ tlen++;
+
+ fracpart /= 10;
+ } while (tlen < 20 && fracpart != 0);
+
+ while (tlen > 0 && len > 0) {
+ buf[0] = tmp[--tlen];
+ buf++;
+ flen++;
+ len--;
+ }
+
+ while (flen < 3 && len > 0) {
+ buf[0] = '0';
+ buf++;
+ flen++;
+ len--;
+ }
+
+ if (len > 0)
+ buf[0] = '\0';
+
+ return buf - ptr;
+}
+static size_t dump_css_number(css_fixed val, char *ptr, size_t len)
+{
+ if (INTTOFIX(FIXTOINT(val)) == val)
+ return snprintf(ptr, len, "%d", FIXTOINT(val));
+ else
+ return dump_css_fixed(val, ptr, len);
+}
+
+static size_t dump_css_unit(css_fixed val, css_unit unit, char *ptr, size_t len)
+{
+ size_t ret = dump_css_number(val, ptr, len);
+
+ switch (unit) {
+ case CSS_UNIT_PX:
+ ret += snprintf(ptr + ret, len - ret, "px");
+ break;
+ case CSS_UNIT_EX:
+ ret += snprintf(ptr + ret, len - ret, "ex");
+ break;
+ case CSS_UNIT_EM:
+ ret += snprintf(ptr + ret, len - ret, "em");
+ break;
+ case CSS_UNIT_IN:
+ ret += snprintf(ptr + ret, len - ret, "in");
+ break;
+ case CSS_UNIT_CM:
+ ret += snprintf(ptr + ret, len - ret, "cm");
+ break;
+ case CSS_UNIT_MM:
+ ret += snprintf(ptr + ret, len - ret, "mm");
+ break;
+ case CSS_UNIT_PT:
+ ret += snprintf(ptr + ret, len - ret, "pt");
+ break;
+ case CSS_UNIT_PC:
+ ret += snprintf(ptr + ret, len - ret, "pc");
+ break;
+ case CSS_UNIT_PCT:
+ ret += snprintf(ptr + ret, len - ret, "%%");
+ break;
+ case CSS_UNIT_DEG:
+ ret += snprintf(ptr + ret, len - ret, "deg");
+ break;
+ case CSS_UNIT_GRAD:
+ ret += snprintf(ptr + ret, len - ret, "grad");
+ break;
+ case CSS_UNIT_RAD:
+ ret += snprintf(ptr + ret, len - ret, "rad");
+ break;
+ case CSS_UNIT_MS:
+ ret += snprintf(ptr + ret, len - ret, "ms");
+ break;
+ case CSS_UNIT_S:
+ ret += snprintf(ptr + ret, len - ret, "s");
+ break;
+ case CSS_UNIT_HZ:
+ ret += snprintf(ptr + ret, len - ret, "Hz");
+ break;
+ case CSS_UNIT_KHZ:
+ ret += snprintf(ptr + ret, len - ret, "kHz");
+ break;
+ }
+
+ return ret;
+}
+
+
static void dump_computed_style(const css_computed_style *style, char *buf,
size_t *len)
{
@@ -8,6 +143,9 @@ static void dump_computed_style(const css_computed_style *style, char *buf,
size_t wrote = 0;
uint8_t val;
css_color color;
+ const css_string *url;
+ css_fixed len1, len2;
+ css_unit unit1, unit2;
val = css_computed_background_attachment(style);
switch (val) {
@@ -39,6 +177,169 @@ static void dump_computed_style(const css_computed_style *style, char *buf,
ptr += wrote;
*len -= wrote;
+ val = css_computed_background_image(style, &url);
+ if (val == CSS_BACKGROUND_IMAGE_IMAGE && url->data != NULL) {
+ wrote = snprintf(ptr, *len, "background-image: url('%.*s')\n",
+ (int) url->len, url->data);
+ } else if (val == CSS_BACKGROUND_IMAGE_NONE) {
+ wrote = snprintf(ptr, *len, "background-image: none\n");
+ } else {
+ wrote = 0;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ val = css_computed_background_position(style, &len1, &unit1,
+ &len2, &unit2);
+ if (val == CSS_BACKGROUND_POSITION_SET) {
+ wrote = snprintf(ptr, *len, "background-position: ");
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = dump_css_unit(len1, unit1, ptr, *len);
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = snprintf(ptr, *len, " ");
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = dump_css_unit(len2, unit2, ptr, *len);
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = snprintf(ptr, *len, "\n");
+ ptr += wrote;
+ *len -= wrote;
+ }
+
+ val = css_computed_background_repeat(style);
+ switch (val) {
+ case CSS_BACKGROUND_REPEAT_REPEAT_X:
+ wrote = snprintf(ptr, *len, "background-repeat: repeat-x\n");
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT_Y:
+ wrote = snprintf(ptr, *len, "background-repeat: repeat-y\n");
+ break;
+ case CSS_BACKGROUND_REPEAT_REPEAT:
+ wrote = snprintf(ptr, *len, "background-repeat: repeat\n");
+ break;
+ case CSS_BACKGROUND_REPEAT_NO_REPEAT:
+ wrote = snprintf(ptr, *len, "background-repeat: no-repeat\n");
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ val = css_computed_border_collapse(style);
+ switch (val) {
+ case CSS_BORDER_COLLAPSE_SEPARATE:
+ wrote = snprintf(ptr, *len, "border-collapse: separate\n");
+ break;
+ case CSS_BORDER_COLLAPSE_COLLAPSE:
+ wrote = snprintf(ptr, *len, "border-collapse: collapse\n");
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ if (style->uncommon != NULL) {
+ val = css_computed_border_spacing(style, &len1, &unit1,
+ &len2, &unit2);
+ if (val == CSS_BORDER_SPACING_SET) {
+ wrote = snprintf(ptr, *len, "border-spacing: ");
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = dump_css_unit(len1, unit1, ptr, *len);
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = snprintf(ptr, *len, " ");
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = dump_css_unit(len2, unit2, ptr, *len);
+ ptr += wrote;
+ *len -= wrote;
+
+ wrote = snprintf(ptr, *len, "\n");
+ ptr += wrote;
+ *len -= wrote;
+ }
+ }
+
+ val = css_computed_border_top_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ wrote = snprintf(ptr, *len, "border-top-color: transparent\n");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ wrote = snprintf(ptr, *len, "border-top-color: #%08x\n", color);
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ val = css_computed_border_right_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ wrote = snprintf(ptr, *len,
+ "border-right-color: transparent\n");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ wrote = snprintf(ptr, *len,
+ "border-right-color: #%08x\n", color);
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ val = css_computed_border_bottom_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ wrote = snprintf(ptr, *len,
+ "border-bottom-color: transparent\n");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ wrote = snprintf(ptr, *len,
+ "border-bottom-color: #%08x\n", color);
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
+ val = css_computed_border_left_color(style, &color);
+ switch (val) {
+ case CSS_BORDER_COLOR_TRANSPARENT:
+ wrote = snprintf(ptr, *len, "border-left-color: transparent\n");
+ break;
+ case CSS_BORDER_COLOR_COLOR:
+ wrote = snprintf(ptr, *len,
+ "border-left-color: #%08x\n", color);
+ break;
+ default:
+ wrote = 0;
+ break;
+ }
+ ptr += wrote;
+ *len -= wrote;
+
val = css_computed_color(style, &color);
if (val == CSS_COLOR_COLOR) {
wrote = snprintf(ptr, *len, "color: #%08x\n", color);
diff --git a/test/select-auto.c b/test/select-auto.c
index 75558c4..19af180 100644
--- a/test/select-auto.c
+++ b/test/select-auto.c
@@ -624,11 +624,11 @@ void run_test(line_ctx *ctx, const char *exp, size_t explen)
UNUSED(exp);
- buf = malloc(2 * explen);
+ buf = malloc(8192);
if (buf == NULL) {
assert(0 && "No memory for result data");
}
- buflen = 2 * explen;
+ buflen = 8192;
assert(css_select_ctx_create(myrealloc, NULL, &select) == CSS_OK);
@@ -647,10 +647,10 @@ void run_test(line_ctx *ctx, const char *exp, size_t explen)
dump_computed_style(computed, buf, &buflen);
- if (2 * explen - buflen != explen || memcmp(buf, exp, explen) != 0) {
+ if (8192 - buflen != explen || memcmp(buf, exp, explen) != 0) {
printf("Expected (%zu):\n%.*s\n", explen, (int) explen, exp);
- printf("Result (%zu):\n%.*s\n", 2 * explen - buflen,
- (int) (2 * explen - buflen), buf);
+ printf("Result (%zu):\n%.*s\n", 8192 - buflen,
+ (int) (8192 - buflen), buf);
assert(0 && "Result doesn't match expected");
}