style/servo/
restyle_damage.rs1use bitflags::Flags;
9
10use crate::computed_values::isolation::T as Isolation;
11use crate::computed_values::mix_blend_mode::T as MixBlendMode;
12use crate::computed_values::transform_style::T as TransformStyle;
13use crate::dom::TElement;
14use crate::matching::{StyleChange, StyleDifference};
15use crate::properties::{
16 restyle_damage_rebuild_box, restyle_damage_rebuild_stacking_context,
17 restyle_damage_recalculate_overflow, restyle_damage_repaint, style_structs, ComputedValues,
18};
19use crate::values::computed::basic_shape::ClipPath;
20use crate::values::computed::Perspective;
21use crate::values::generics::transform::{GenericRotate, GenericScale, GenericTranslate};
22use std::fmt;
23
24bitflags! {
25 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
30 pub struct ServoRestyleDamage: u16 {
31 const REPAINT = 0b0001;
35
36 const REBUILD_STACKING_CONTEXT = 0b0011;
40
41 const RECALCULATE_OVERFLOW = 0b0111;
45
46 const RELAYOUT = 0b1111;
50 }
51}
52
53malloc_size_of::malloc_size_of_is_0!(ServoRestyleDamage);
54
55impl ServoRestyleDamage {
56 pub fn compute_style_difference<E: TElement>(
59 old: &ComputedValues,
60 new: &ComputedValues,
61 ) -> StyleDifference {
62 if std::ptr::eq(old, new) {
63 return StyleDifference {
64 damage: ServoRestyleDamage::empty(),
65 change: StyleChange::Unchanged,
66 };
67 }
68
69 let mut damage = compute_damage(old, new);
70 if damage.contains(ServoRestyleDamage::RELAYOUT) {
71 damage |= E::compute_layout_damage(old, new);
72 }
73
74 let mut any_style_changed = !damage.is_empty();
75 let mut reset_only = !any_style_changed;
79
80 let old_custom_props = old.custom_properties();
81 let new_custom_props = new.custom_properties();
82 let mut custom_properties_changed = false;
83 if old_custom_props.inherited != new_custom_props.inherited {
84 any_style_changed = true;
85 custom_properties_changed = true;
86 reset_only = false;
87 } else if old_custom_props.non_inherited != new_custom_props.non_inherited {
88 any_style_changed = true;
89 custom_properties_changed = true;
90 };
91 if custom_properties_changed {
92 damage.insert(ServoRestyleDamage::REPAINT);
94 }
95
96 let change = if any_style_changed {
97 StyleChange::Changed {
98 reset_only,
99 custom_properties_changed,
100 }
101 } else {
102 StyleChange::Unchanged
103 };
104
105 StyleDifference { damage, change }
106 }
107
108 pub fn reconstruct() -> ServoRestyleDamage {
110 ServoRestyleDamage::from_bits_retain(<ServoRestyleDamage as Flags>::Bits::MAX)
113 }
114}
115
116impl Default for ServoRestyleDamage {
117 fn default() -> Self {
118 Self::empty()
119 }
120}
121
122impl fmt::Display for ServoRestyleDamage {
123 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
124 let mut first_elem = true;
125
126 let to_iter = [
127 (ServoRestyleDamage::REPAINT, "Repaint"),
128 (
129 ServoRestyleDamage::REBUILD_STACKING_CONTEXT,
130 "Rebuild stacking context",
131 ),
132 (
133 ServoRestyleDamage::RECALCULATE_OVERFLOW,
134 "Recalculate overflow",
135 ),
136 (ServoRestyleDamage::RELAYOUT, "Relayout"),
137 ];
138
139 for &(damage, damage_str) in &to_iter {
140 if self.contains(damage) {
141 if !first_elem {
142 write!(f, " | ")?;
143 }
144 write!(f, "{}", damage_str)?;
145 first_elem = false;
146 }
147 }
148
149 if first_elem {
150 write!(f, "NoDamage")?;
151 }
152
153 Ok(())
154 }
155}
156
157fn augmented_restyle_damage_rebuild_box(old: &ComputedValues, new: &ComputedValues) -> bool {
158 let old_box = old.get_box();
159 let new_box = new.get_box();
160 restyle_damage_rebuild_box(old, new)
161 || old_box.original_display != new_box.original_display
162 || old_box.has_transform_or_perspective() != new_box.has_transform_or_perspective()
163 || old.get_effects().filter.0.is_empty() != new.get_effects().filter.0.is_empty()
164}
165
166fn augmented_restyle_damage_rebuild_stacking_context(
167 old: &ComputedValues,
168 new: &ComputedValues,
169) -> bool {
170 restyle_damage_rebuild_stacking_context(old, new)
171 || old.guarantees_stacking_context() != new.guarantees_stacking_context()
172}
173
174fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> ServoRestyleDamage {
175 if augmented_restyle_damage_rebuild_box(old, new) {
178 ServoRestyleDamage::RELAYOUT
179 } else if restyle_damage_recalculate_overflow(old, new) {
180 ServoRestyleDamage::RECALCULATE_OVERFLOW
181 } else if augmented_restyle_damage_rebuild_stacking_context(old, new) {
182 ServoRestyleDamage::REBUILD_STACKING_CONTEXT
183 } else if restyle_damage_repaint(old, new) {
184 ServoRestyleDamage::REPAINT
185 } else {
186 ServoRestyleDamage::empty()
187 }
188}
189
190impl ComputedValues {
191 pub fn guarantees_stacking_context(&self) -> bool {
198 self.get_effects().opacity != 1.0
199 || self.get_effects().mix_blend_mode != MixBlendMode::Normal
200 || self.get_svg().clip_path != ClipPath::None
201 || self.get_box().isolation == Isolation::Isolate
202 }
203}
204
205impl style_structs::Box {
206 pub fn has_transform_or_perspective(&self) -> bool {
208 !self.transform.0.is_empty()
209 || self.scale != GenericScale::None
210 || self.rotate != GenericRotate::None
211 || self.translate != GenericTranslate::None
212 || self.perspective != Perspective::None
213 || self.transform_style == TransformStyle::Preserve3d
214 }
215}