Fix: Mark ancestors dirty in mutation methods for proper style traversal #333
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes a bug where DOM mutations via
set_attribute,set_node_text, andclear_attributewould not result in visual updates during continuous operations (like slider dragging), even though the correct damage/hint flags were being set.The Problem
The Stylo style traversal uses the
dirty_descendantsflag on ancestor nodes to determine which subtrees need restyling. When a node needs restyling, the traversal algorithm walks down from the root but only descends into subtrees where an ancestor hasdirty_descendants = true.The mutation methods (
set_attribute,set_node_text,clear_attribute) were correctly setting:RestyleHint::restyle_subtree()on the nodeALL_DAMAGEon the nodeHowever, they were not calling
mark_ancestors_dirty(), which sets thedirty_descendantsflag on all ancestor nodes up to the root.Without this flag, the style traversal would skip the modified nodes entirely, leaving their damage unprocessed until something else (like a hover state change) triggered a proper traversal of that subtree.
Why hover() works correctly
The
hover()andunhover()methods onNodecallset_restyle_hint(), which internally callsmark_ancestors_dirty():This is why hover state changes would "fix" the visual state - they would trigger a proper traversal that would also pick up pending damage from earlier mutations.
The Fix
Added
mark_ancestors_dirty()calls to:set_node_text()- afterinsert_damage()set_attribute()- after setting hint/damage on node and parentclear_attribute()- after setting hint/damageTesting
Tested with a slider widget that updates inline styles during drag. Before this fix, the slider bar/thumb would not move visually during drag (only on mouse release or when cursor moved over a different element). After this fix, the slider updates in real-time during drag.
Impact
This is a correctness fix with minimal performance impact. The
mark_ancestors_dirty()function is O(tree depth) and early-exits when it finds an ancestor that already has the flag set, so repeated mutations to the same subtree have minimal overhead.