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 let mut damage = if std::ptr::eq(old, new) {
63 ServoRestyleDamage::empty()
64 } else {
65 compute_damage(old, new)
66 };
67 let custom_properties_changed = !old.custom_properties_equal(new);
68
69 if damage.contains(ServoRestyleDamage::RELAYOUT) {
70 damage |= E::compute_layout_damage(old, new);
71 }
72
73 let change = if damage.is_empty() && !custom_properties_changed {
77 StyleChange::Unchanged
78 } else {
79 StyleChange::Changed {
80 reset_only: false,
81 custom_properties_changed,
82 }
83 };
84
85 StyleDifference { damage, change }
86 }
87
88 pub fn reconstruct() -> ServoRestyleDamage {
90 ServoRestyleDamage::from_bits_retain(<ServoRestyleDamage as Flags>::Bits::MAX)
93 }
94}
95
96impl Default for ServoRestyleDamage {
97 fn default() -> Self {
98 Self::empty()
99 }
100}
101
102impl fmt::Display for ServoRestyleDamage {
103 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
104 let mut first_elem = true;
105
106 let to_iter = [
107 (ServoRestyleDamage::REPAINT, "Repaint"),
108 (
109 ServoRestyleDamage::REBUILD_STACKING_CONTEXT,
110 "Rebuild stacking context",
111 ),
112 (
113 ServoRestyleDamage::RECALCULATE_OVERFLOW,
114 "Recalculate overflow",
115 ),
116 (ServoRestyleDamage::RELAYOUT, "Relayout"),
117 ];
118
119 for &(damage, damage_str) in &to_iter {
120 if self.contains(damage) {
121 if !first_elem {
122 write!(f, " | ")?;
123 }
124 write!(f, "{}", damage_str)?;
125 first_elem = false;
126 }
127 }
128
129 if first_elem {
130 write!(f, "NoDamage")?;
131 }
132
133 Ok(())
134 }
135}
136
137fn augmented_restyle_damage_rebuild_box(old: &ComputedValues, new: &ComputedValues) -> bool {
138 let old_box = old.get_box();
139 let new_box = new.get_box();
140 restyle_damage_rebuild_box(old, new)
141 || old_box.original_display != new_box.original_display
142 || old_box.has_transform_or_perspective() != new_box.has_transform_or_perspective()
143 || old.get_effects().filter.0.is_empty() != new.get_effects().filter.0.is_empty()
144}
145
146fn augmented_restyle_damage_rebuild_stacking_context(
147 old: &ComputedValues,
148 new: &ComputedValues,
149) -> bool {
150 restyle_damage_rebuild_stacking_context(old, new)
151 || old.guarantees_stacking_context() != new.guarantees_stacking_context()
152}
153fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> ServoRestyleDamage {
154 let mut damage = ServoRestyleDamage::empty();
155
156 if augmented_restyle_damage_rebuild_box(old, new) {
159 damage.insert(ServoRestyleDamage::RELAYOUT)
160 } else if restyle_damage_recalculate_overflow(old, new) {
161 damage.insert(ServoRestyleDamage::RECALCULATE_OVERFLOW)
162 } else if augmented_restyle_damage_rebuild_stacking_context(old, new) {
163 damage.insert(ServoRestyleDamage::REBUILD_STACKING_CONTEXT);
164 } else if restyle_damage_repaint(old, new) {
165 damage.insert(ServoRestyleDamage::REPAINT);
166 }
167 else if !old.custom_properties_equal(new) {
169 damage.insert(ServoRestyleDamage::REPAINT);
170 }
171
172 damage
173}
174
175impl ComputedValues {
176 pub fn guarantees_stacking_context(&self) -> bool {
183 self.get_effects().opacity != 1.0
184 || self.get_effects().mix_blend_mode != MixBlendMode::Normal
185 || self.get_svg().clip_path != ClipPath::None
186 || self.get_box().isolation == Isolation::Isolate
187 }
188}
189
190impl style_structs::Box {
191 pub fn has_transform_or_perspective(&self) -> bool {
193 !self.transform.0.is_empty()
194 || self.scale != GenericScale::None
195 || self.rotate != GenericRotate::None
196 || self.translate != GenericTranslate::None
197 || self.perspective != Perspective::None
198 || self.transform_style == TransformStyle::Preserve3d
199 }
200}