Skip to content

Conversation

@nicoburns
Copy link
Collaborator

@nicoburns nicoburns commented Aug 7, 2025

Fixes #226

This implements three optimisations:

  1. If the old and new &ComputedValues are ptr::eq then diffing the styles is entirely skipped. This occurs when an element is restyled but none of the styles actually change.
  2. When computing damage X (e.g. "repaint"), for each "style struct" (e.g. position, background, inherited_text) that contains a longhand property that affects X, compare the structs using ptr::eq before diffing individual properties. If the structs are ptr::eq then no damage is generated from that struct.
  3. If ALL of the longhand properties in a style struct affect a given a property then we can also skip diffing individual properties in the case that the struct is not ptr::eq. In that case damage is generated and we can return early with that result. This optimisation was removed because it may be possible (we are unsure) for style properties to be the same even if the pointers differ. And in that case this would like pessimise performance.

Servo PR: servo/servo#39772

Generated code with this PR is:
pub(crate) fn restyle_damage_repaint (old: &ComputedValues, new: &ComputedValues) -> bool {
        
        let old_background = old.get_background();
        let new_background = new.get_background();
        if !std::ptr::eq(old_background, new_background) {
            if 
                old_background.background_color != new_background.background_color ||
                old_background.background_image != new_background.background_image ||
                old_background.background_position_x != new_background.background_position_x ||
                old_background.background_position_y != new_background.background_position_y ||
                old_background.background_repeat != new_background.background_repeat ||
                old_background.background_attachment != new_background.background_attachment ||
                old_background.background_clip != new_background.background_clip ||
                old_background.background_origin != new_background.background_origin ||
                old_background.background_size != new_background.background_size ||
            false {
                return true;
            }
        }
        
        let old_border = old.get_border();
        let new_border = new.get_border();
        if !std::ptr::eq(old_border, new_border) {
            if 
                old_border.border_image_source != new_border.border_image_source ||
                old_border.border_image_outset != new_border.border_image_outset ||
                old_border.border_image_repeat != new_border.border_image_repeat ||
                old_border.border_image_width != new_border.border_image_width ||
                old_border.border_image_slice != new_border.border_image_slice ||
            false {
                return true;
            }
        }
        
        let old_box = old.get_box();
        let new_box = new.get_box();
        if !std::ptr::eq(old_box, new_box) {
            if 
                old_box.isolation != new_box.isolation ||
                old_box.backface_visibility != new_box.backface_visibility ||
            false {
                return true;
            }
        }
        
        
        
        let old_effects = old.get_effects();
        let new_effects = new.get_effects();
        if !std::ptr::eq(old_effects, new_effects) {
            if 
                old_effects.opacity != new_effects.opacity ||
                old_effects.filter != new_effects.filter ||
                old_effects.mix_blend_mode != new_effects.mix_blend_mode ||
            false {
                return true;
            }
        }
        
        
        
        
        let old_inherited_text = old.get_inherited_text();
        let new_inherited_text = new.get_inherited_text();
        if !std::ptr::eq(old_inherited_text, new_inherited_text) {
            if 
                old_inherited_text.color != new_inherited_text.color ||
            false {
                return true;
            }
        }
        
        let old_inherited_ui = old.get_inherited_ui();
        let new_inherited_ui = new.get_inherited_ui();
        if !std::ptr::eq(old_inherited_ui, new_inherited_ui) {
            if 
                old_inherited_ui.cursor != new_inherited_ui.cursor ||
                old_inherited_ui.pointer_events != new_inherited_ui.pointer_events ||
            false {
                return true;
            }
        }
        
        
        
        let old_outline = old.get_outline();
        let new_outline = new.get_outline();
        if !std::ptr::eq(old_outline, new_outline) {
            if 
                old_outline.outline_color != new_outline.outline_color ||
                old_outline.outline_style != new_outline.outline_style ||
                old_outline.outline_width != new_outline.outline_width ||
                old_outline.outline_offset != new_outline.outline_offset ||
            false {
                return true;
            }
        }
        
        
        
        let old_svg = old.get_svg();
        let new_svg = new.get_svg();
        if !std::ptr::eq(old_svg, new_svg) {
            if 
                old_svg.clip_path != new_svg.clip_path ||
            false {
                return true;
            }
        }
        
        
        
    false
}
pub(crate) fn restyle_damage_recalculate_overflow (old: &ComputedValues, new: &ComputedValues) -> bool {
        
        
        
        let old_box = old.get_box();
        let new_box = new.get_box();
        if !std::ptr::eq(old_box, new_box) {
            if 
                old_box.transform != new_box.transform ||
                old_box.rotate != new_box.rotate ||
                old_box.scale != new_box.scale ||
                old_box.translate != new_box.translate ||
                old_box.perspective != new_box.perspective ||
                old_box.perspective_origin != new_box.perspective_origin ||
                old_box.transform_style != new_box.transform_style ||
                old_box.transform_origin != new_box.transform_origin ||
            false {
                return true;
            }
        }
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    false
}
pub(crate) fn restyle_damage_rebuild_stacking_context (old: &ComputedValues, new: &ComputedValues) -> bool {
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        let old_position = old.get_position();
        let new_position = new.get_position();
        if !std::ptr::eq(old_position, new_position) {
            if 
                old_position.z_index != new_position.z_index ||
            false {
                return true;
            }
        }
        
        
        
        
    false
}
pub(crate) fn restyle_damage_rebuild_box (old: &ComputedValues, new: &ComputedValues) -> bool {
        
        
        let old_border = old.get_border();
        let new_border = new.get_border();
        if !std::ptr::eq(old_border, new_border) {
            if 
                old_border.border_top_color != new_border.border_top_color ||
                old_border.border_top_style != new_border.border_top_style ||
                old_border.border_top_width != new_border.border_top_width ||
                old_border.border_right_color != new_border.border_right_color ||
                old_border.border_right_style != new_border.border_right_style ||
                old_border.border_right_width != new_border.border_right_width ||
                old_border.border_bottom_color != new_border.border_bottom_color ||
                old_border.border_bottom_style != new_border.border_bottom_style ||
                old_border.border_bottom_width != new_border.border_bottom_width ||
                old_border.border_left_color != new_border.border_left_color ||
                old_border.border_left_style != new_border.border_left_style ||
                old_border.border_left_width != new_border.border_left_width ||
                old_border.border_top_left_radius != new_border.border_top_left_radius ||
                old_border.border_top_right_radius != new_border.border_top_right_radius ||
                old_border.border_bottom_right_radius != new_border.border_bottom_right_radius ||
                old_border.border_bottom_left_radius != new_border.border_bottom_left_radius ||
            false {
                return true;
            }
        }
        
        let old_box = old.get_box();
        let new_box = new.get_box();
        if !std::ptr::eq(old_box, new_box) {
            if 
                old_box.display != new_box.display ||
                old_box._servo_top_layer != new_box._servo_top_layer ||
                old_box.position != new_box.position ||
                old_box.float != new_box.float ||
                old_box.clear != new_box.clear ||
                old_box.vertical_align != new_box.vertical_align ||
                old_box.baseline_source != new_box.baseline_source ||
                old_box._servo_overflow_clip_box != new_box._servo_overflow_clip_box ||
                old_box.overflow_y != new_box.overflow_y ||
                old_box.overflow_x != new_box.overflow_x ||
                old_box.offset_path != new_box.offset_path ||
                old_box.contain != new_box.contain ||
                old_box.container_type != new_box.container_type ||
                old_box.container_name != new_box.container_name ||
                old_box.will_change != new_box.will_change ||
                old_box.zoom != new_box.zoom ||
            false {
                return true;
            }
        }
        
        let old_column = old.get_column();
        let new_column = new.get_column();
        if !std::ptr::eq(old_column, new_column) {
            if 
                old_column.column_width != new_column.column_width ||
                old_column.column_count != new_column.column_count ||
                old_column.column_span != new_column.column_span ||
            false {
                return true;
            }
        }
        
        let old_counters = old.get_counters();
        let new_counters = new.get_counters();
        if !std::ptr::eq(old_counters, new_counters) {
            if 
                old_counters.content != new_counters.content ||
                old_counters.counter_increment != new_counters.counter_increment ||
                old_counters.counter_reset != new_counters.counter_reset ||
            false {
                return true;
            }
        }
        
        let old_effects = old.get_effects();
        let new_effects = new.get_effects();
        if !std::ptr::eq(old_effects, new_effects) {
            if 
                old_effects.box_shadow != new_effects.box_shadow ||
                old_effects.clip != new_effects.clip ||
                old_effects.backdrop_filter != new_effects.backdrop_filter ||
            false {
                return true;
            }
        }
        
        let old_font = old.get_font();
        let new_font = new.get_font();
        if !std::ptr::eq(old_font, new_font) {
            if 
                old_font.font_family != new_font.font_family ||
                old_font.font_style != new_font.font_style ||
                old_font.font_variant_caps != new_font.font_variant_caps ||
                old_font.font_weight != new_font.font_weight ||
                old_font.font_size != new_font.font_size ||
                old_font.font_synthesis_weight != new_font.font_synthesis_weight ||
                old_font.font_stretch != new_font.font_stretch ||
                old_font.font_variation_settings != new_font.font_variation_settings ||
                old_font.font_language_override != new_font.font_language_override ||
                old_font._x_lang != new_font._x_lang ||
                old_font.line_height != new_font.line_height ||
            false {
                return true;
            }
        }
        
        let old_inherited_box = old.get_inherited_box();
        let new_inherited_box = new.get_inherited_box();
        if !std::ptr::eq(old_inherited_box, new_inherited_box) {
            if 
                old_inherited_box.visibility != new_inherited_box.visibility ||
                old_inherited_box.writing_mode != new_inherited_box.writing_mode ||
                old_inherited_box.direction != new_inherited_box.direction ||
                old_inherited_box.image_rendering != new_inherited_box.image_rendering ||
            false {
                return true;
            }
        }
        
        let old_inherited_table = old.get_inherited_table();
        let new_inherited_table = new.get_inherited_table();
        if !std::ptr::eq(old_inherited_table, new_inherited_table) {
            if 
                old_inherited_table.border_collapse != new_inherited_table.border_collapse ||
                old_inherited_table.empty_cells != new_inherited_table.empty_cells ||
                old_inherited_table.caption_side != new_inherited_table.caption_side ||
                old_inherited_table.border_spacing != new_inherited_table.border_spacing ||
            false {
                return true;
            }
        }
        
        let old_inherited_text = old.get_inherited_text();
        let new_inherited_text = new.get_inherited_text();
        if !std::ptr::eq(old_inherited_text, new_inherited_text) {
            if 
                old_inherited_text.text_transform != new_inherited_text.text_transform ||
                old_inherited_text.text_indent != new_inherited_text.text_indent ||
                old_inherited_text.overflow_wrap != new_inherited_text.overflow_wrap ||
                old_inherited_text.word_break != new_inherited_text.word_break ||
                old_inherited_text.text_justify != new_inherited_text.text_justify ||
                old_inherited_text.text_align_last != new_inherited_text.text_align_last ||
                old_inherited_text.text_align != new_inherited_text.text_align ||
                old_inherited_text.letter_spacing != new_inherited_text.letter_spacing ||
                old_inherited_text.word_spacing != new_inherited_text.word_spacing ||
                old_inherited_text.white_space_collapse != new_inherited_text.white_space_collapse ||
                old_inherited_text.text_shadow != new_inherited_text.text_shadow ||
                old_inherited_text.text_rendering != new_inherited_text.text_rendering ||
                old_inherited_text.text_wrap_mode != new_inherited_text.text_wrap_mode ||
            false {
                return true;
            }
        }
        
        let old_inherited_ui = old.get_inherited_ui();
        let new_inherited_ui = new.get_inherited_ui();
        if !std::ptr::eq(old_inherited_ui, new_inherited_ui) {
            if 
                old_inherited_ui.color_scheme != new_inherited_ui.color_scheme ||
            false {
                return true;
            }
        }
        
        let old_list = old.get_list();
        let new_list = new.get_list();
        if !std::ptr::eq(old_list, new_list) {
            if 
                old_list.list_style_position != new_list.list_style_position ||
                old_list.list_style_type != new_list.list_style_type ||
                old_list.list_style_image != new_list.list_style_image ||
                old_list.quotes != new_list.quotes ||
            false {
                return true;
            }
        }
        
        let old_margin = old.get_margin();
        let new_margin = new.get_margin();
        if !std::ptr::eq(old_margin, new_margin) {
            if 
                old_margin.margin_top != new_margin.margin_top ||
                old_margin.margin_right != new_margin.margin_right ||
                old_margin.margin_bottom != new_margin.margin_bottom ||
                old_margin.margin_left != new_margin.margin_left ||
                old_margin.overflow_clip_margin != new_margin.overflow_clip_margin ||
            false {
                return true;
            }
        }
        
        
        let old_padding = old.get_padding();
        let new_padding = new.get_padding();
        if !std::ptr::eq(old_padding, new_padding) {
            if 
                old_padding.padding_top != new_padding.padding_top ||
                old_padding.padding_right != new_padding.padding_right ||
                old_padding.padding_bottom != new_padding.padding_bottom ||
                old_padding.padding_left != new_padding.padding_left ||
            false {
                return true;
            }
        }
        
        let old_position = old.get_position();
        let new_position = new.get_position();
        if !std::ptr::eq(old_position, new_position) {
            if 
                old_position.top != new_position.top ||
                old_position.right != new_position.right ||
                old_position.bottom != new_position.bottom ||
                old_position.left != new_position.left ||
                old_position.flex_direction != new_position.flex_direction ||
                old_position.flex_wrap != new_position.flex_wrap ||
                old_position.justify_content != new_position.justify_content ||
                old_position.align_content != new_position.align_content ||
                old_position.align_items != new_position.align_items ||
                old_position.justify_items != new_position.justify_items ||
                old_position.flex_grow != new_position.flex_grow ||
                old_position.flex_shrink != new_position.flex_shrink ||
                old_position.align_self != new_position.align_self ||
                old_position.justify_self != new_position.justify_self ||
                old_position.order != new_position.order ||
                old_position.flex_basis != new_position.flex_basis ||
                old_position.height != new_position.height ||
                old_position.min_height != new_position.min_height ||
                old_position.max_height != new_position.max_height ||
                old_position.width != new_position.width ||
                old_position.min_width != new_position.min_width ||
                old_position.max_width != new_position.max_width ||
                old_position.box_sizing != new_position.box_sizing ||
                old_position.object_fit != new_position.object_fit ||
                old_position.object_position != new_position.object_position ||
                old_position.grid_row_start != new_position.grid_row_start ||
                old_position.grid_row_end != new_position.grid_row_end ||
                old_position.grid_auto_rows != new_position.grid_auto_rows ||
                old_position.grid_template_rows != new_position.grid_template_rows ||
                old_position.grid_column_start != new_position.grid_column_start ||
                old_position.grid_column_end != new_position.grid_column_end ||
                old_position.grid_auto_columns != new_position.grid_auto_columns ||
                old_position.grid_template_columns != new_position.grid_template_columns ||
                old_position.grid_auto_flow != new_position.grid_auto_flow ||
                old_position.grid_template_areas != new_position.grid_template_areas ||
                old_position.column_gap != new_position.column_gap ||
                old_position.row_gap != new_position.row_gap ||
                old_position.aspect_ratio != new_position.aspect_ratio ||
            false {
                return true;
            }
        }
        
        let old_svg = old.get_svg();
        let new_svg = new.get_svg();
        if !std::ptr::eq(old_svg, new_svg) {
            if 
                old_svg.mask_image != new_svg.mask_image ||
            false {
                return true;
            }
        }
        
        let old_table = old.get_table();
        let new_table = new.get_table();
        if !std::ptr::eq(old_table, new_table) {
            if 
                old_table.table_layout != new_table.table_layout ||
            false {
                return true;
            }
        }
        
        let old_text = old.get_text();
        let new_text = new.get_text();
        if !std::ptr::eq(old_text, new_text) {
            if 
                old_text.text_overflow != new_text.text_overflow ||
                old_text.unicode_bidi != new_text.unicode_bidi ||
                old_text.text_decoration_line != new_text.text_decoration_line ||
                old_text.text_decoration_style != new_text.text_decoration_style ||
                old_text.text_decoration_color != new_text.text_decoration_color ||
            false {
                return true;
            }
        }
        
        let old_ui = old.get_ui();
        let new_ui = new.get_ui();
        if !std::ptr::eq(old_ui, new_ui) {
            if 
                old_ui.transition_duration != new_ui.transition_duration ||
                old_ui.transition_timing_function != new_ui.transition_timing_function ||
                old_ui.transition_property != new_ui.transition_property ||
                old_ui.transition_delay != new_ui.transition_delay ||
                old_ui.transition_behavior != new_ui.transition_behavior ||
                old_ui.animation_name != new_ui.animation_name ||
                old_ui.animation_duration != new_ui.animation_duration ||
                old_ui.animation_timing_function != new_ui.animation_timing_function ||
                old_ui.animation_iteration_count != new_ui.animation_iteration_count ||
                old_ui.animation_direction != new_ui.animation_direction ||
                old_ui.animation_play_state != new_ui.animation_play_state ||
                old_ui.animation_fill_mode != new_ui.animation_fill_mode ||
                old_ui.animation_composition != new_ui.animation_composition ||
                old_ui.animation_delay != new_ui.animation_delay ||
                old_ui.animation_timeline != new_ui.animation_timeline ||
                old_ui.view_transition_name != new_ui.view_transition_name ||
                old_ui.view_transition_class != new_ui.view_transition_class ||
            false {
                return true;
            }
        }
    false
}

Signed-off-by: Nico Burns <nico@nicoburns.com>
@nicoburns nicoburns force-pushed the ptr-all-styles-equal branch from 4d1bb60 to d1172e5 Compare October 10, 2025 14:14
@nicoburns nicoburns marked this pull request as ready for review October 10, 2025 15:31
Signed-off-by: Nico Burns <nico@nicoburns.com>
@nicoburns nicoburns requested a review from Loirooriol October 14, 2025 11:50
Copy link
Collaborator

@Loirooriol Loirooriol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you should update the description since the 3rd optimization was removed and the generated code is different

@nicoburns nicoburns added this pull request to the merge queue Oct 14, 2025
Merged via the queue into servo:main with commit 2dda313 Oct 14, 2025
5 checks passed
@nicoburns nicoburns deleted the ptr-all-styles-equal branch October 14, 2025 12:56
github-merge-queue bot pushed a commit to servo/servo that referenced this pull request Oct 14, 2025
Optimises Stylo damage computation. Actual changes are in Stylo.

Stylo PR: servo/stylo#227

Testing: WPT tests

Signed-off-by: Nico Burns <nico@nicoburns.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimize style comparison when computing restyle damage

2 participants