1use crate::bloom::StyleBloom;
10use crate::context::SharedStyleContext;
11use crate::dom::{TElement, TShadowRoot};
12use crate::properties::ComputedValues;
13use crate::sharing::{StyleSharingCandidate, StyleSharingTarget};
14use crate::values::specified::TreeCountingFunction;
15use selectors::matching::SelectorCaches;
16
17pub fn parents_allow_sharing<E>(
20 target: &mut StyleSharingTarget<E>,
21 candidate: &mut StyleSharingCandidate<E>,
22) -> bool
23where
24 E: TElement,
25{
26 if target.parent_style_identity() != candidate.parent_style_identity() {
29 return false;
30 }
31
32 let parent = target.inheritance_parent().unwrap();
34 let candidate_parent = candidate.element.inheritance_parent().unwrap();
35 if parent == candidate_parent {
36 return true;
37 }
38
39 let parent_data = parent.borrow_data().unwrap();
50 let candidate_parent_data = candidate_parent.borrow_data().unwrap();
51 if !parent_data.safe_for_cousin_sharing() || !candidate_parent_data.safe_for_cousin_sharing() {
52 return false;
53 }
54
55 true
56}
57
58pub fn have_same_style_attribute<E>(
62 target: &mut StyleSharingTarget<E>,
63 candidate: &mut StyleSharingCandidate<E>,
64 shared_context: &SharedStyleContext,
65) -> bool
66where
67 E: TElement,
68{
69 match (target.style_attribute(), candidate.style_attribute()) {
70 (None, None) => true,
71 (Some(_), None) | (None, Some(_)) => false,
72 (Some(a), Some(b)) => {
73 if std::ptr::eq(&*a, &*b) {
74 return true;
75 }
76 let guard = shared_context.guards.author;
77 *a.read_with(guard) == *b.read_with(guard)
78 },
79 }
80}
81
82pub fn have_same_presentational_hints<E>(
84 target: &mut StyleSharingTarget<E>,
85 candidate: &mut StyleSharingCandidate<E>,
86) -> bool
87where
88 E: TElement,
89{
90 target.pres_hints() == candidate.pres_hints()
91}
92
93pub fn have_same_class<E>(
97 target: &mut StyleSharingTarget<E>,
98 candidate: &mut StyleSharingCandidate<E>,
99) -> bool
100where
101 E: TElement,
102{
103 target.class_list() == candidate.class_list()
104}
105
106pub fn have_same_parts<E>(
110 target: &mut StyleSharingTarget<E>,
111 candidate: &mut StyleSharingCandidate<E>,
112) -> bool
113where
114 E: TElement,
115{
116 target.part_list() == candidate.part_list()
117}
118
119#[inline]
126pub fn revalidate<E>(
127 target: &mut StyleSharingTarget<E>,
128 candidate: &mut StyleSharingCandidate<E>,
129 shared_context: &SharedStyleContext,
130 bloom: &StyleBloom<E>,
131 selector_caches: &mut SelectorCaches,
132) -> bool
133where
134 E: TElement,
135{
136 let stylist = &shared_context.stylist;
137
138 let for_element = target.revalidation_match_results(stylist, bloom, selector_caches);
139
140 let for_candidate = candidate.revalidation_match_results(stylist, bloom, selector_caches);
141
142 for_element == for_candidate
143}
144
145#[inline]
148pub fn have_same_referenced_attrs<E>(
149 target: &StyleSharingTarget<E>,
150 candidate: &StyleSharingCandidate<E>,
151) -> bool
152where
153 E: TElement,
154{
155 let borrowed_data = candidate.element.borrow_data().unwrap();
157 let styles = &borrowed_data.styles;
158
159 let check_style = |style: &ComputedValues| {
160 let Some(ref attrs) = style.attribute_references else {
161 return true;
162 };
163 attrs.iter().all(|(name, namespaces)| {
164 namespaces.iter().all(|namespace| {
165 TElement::get_attr(&**target, name, namespace)
166 == TElement::get_attr(&**candidate, name, namespace)
167 })
168 })
169 };
170
171 if !check_style(styles.primary()) {
172 return false;
173 }
174
175 for pseudo_styles in styles.pseudos.as_array() {
176 let Some(ref styles) = pseudo_styles else {
177 continue;
178 };
179 if !check_style(styles) {
180 return false;
181 }
182 }
183 true
184}
185
186pub fn have_shareable_tree_counting_functions<E>(
188 target: &StyleSharingTarget<E>,
189 candidate: &StyleSharingCandidate<E>,
190) -> bool
191where
192 E: TElement,
193{
194 let borrowed_data = candidate.element.borrow_data().unwrap();
195 let styles = &borrowed_data.styles;
196
197 if styles.uses_tree_counting_function(TreeCountingFunction::SiblingIndex) {
198 return false;
200 }
201
202 if styles.uses_tree_counting_function(TreeCountingFunction::SiblingCount)
203 && target.parent_element() != candidate.parent_element()
204 {
205 return false;
206 }
207
208 true
209}
210
211#[inline]
214pub fn revalidate_scope<E>(
215 target: &mut StyleSharingTarget<E>,
216 candidate: &mut StyleSharingCandidate<E>,
217 shared_context: &SharedStyleContext,
218 selector_caches: &mut SelectorCaches,
219) -> bool
220where
221 E: TElement,
222{
223 let stylist = &shared_context.stylist;
224 let for_element = target.scope_revalidation_results(stylist, selector_caches);
225 let for_candidate = candidate.scope_revalidation_results(stylist, selector_caches);
226
227 for_element == for_candidate
228}
229
230#[inline]
232pub fn may_match_different_id_rules<E>(
233 shared_context: &SharedStyleContext,
234 element: E,
235 candidate: E,
236) -> bool
237where
238 E: TElement,
239{
240 let element_id = element.id();
241 let candidate_id = candidate.id();
242
243 if element_id == candidate_id {
244 return false;
245 }
246
247 let stylist = &shared_context.stylist;
248
249 let may_have_rules_for_element = match element_id {
250 Some(id) => stylist.may_have_rules_for_id(id, element),
251 None => false,
252 };
253
254 if may_have_rules_for_element {
255 return true;
256 }
257
258 match candidate_id {
259 Some(id) => stylist.may_have_rules_for_id(id, candidate),
260 None => false,
261 }
262}
263
264#[inline]
266pub fn shadow_root_style_data_equals<S>(l: Option<S>, r: Option<S>) -> bool
267where
268 S: TShadowRoot,
269{
270 if l == r {
271 return true;
272 }
273 let (Some(l), Some(r)) = (l, r) else {
274 return false;
275 };
276 match (l.style_data(), r.style_data()) {
277 (Some(l), Some(r)) => std::ptr::eq(l, r),
278 (None, None) => true,
279 _ => false,
280 }
281}