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(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_element_dependent_functions<E>(
189 target: &StyleSharingTarget<E>,
190 candidate: &StyleSharingCandidate<E>,
191) -> bool
192where
193 E: TElement,
194{
195 let borrowed_data = candidate.element.borrow_data().unwrap();
196 let styles = &borrowed_data.styles;
197
198 if styles.uses_tree_counting_function(TreeCountingFunction::SiblingIndex) {
199 return false;
201 }
202
203 if styles.uses_tree_counting_function(TreeCountingFunction::SiblingCount)
204 && target.parent_element() != candidate.parent_element()
205 {
206 return false;
207 }
208
209 if styles.uses_element_scoped_random() {
210 return false;
212 }
213
214 true
215}
216
217#[inline]
220pub fn revalidate_scope<E>(
221 target: &mut StyleSharingTarget<E>,
222 candidate: &mut StyleSharingCandidate<E>,
223 shared_context: &SharedStyleContext,
224 selector_caches: &mut SelectorCaches,
225) -> bool
226where
227 E: TElement,
228{
229 let stylist = &shared_context.stylist;
230 let for_element = target.scope_revalidation_results(stylist, selector_caches);
231 let for_candidate = candidate.scope_revalidation_results(stylist, selector_caches);
232
233 for_element == for_candidate
234}
235
236#[inline]
238pub fn may_match_different_id_rules<E>(
239 shared_context: &SharedStyleContext,
240 element: E,
241 candidate: E,
242) -> bool
243where
244 E: TElement,
245{
246 let element_id = element.id();
247 let candidate_id = candidate.id();
248
249 if element_id == candidate_id {
250 return false;
251 }
252
253 let stylist = &shared_context.stylist;
254
255 let may_have_rules_for_element = match element_id {
256 Some(id) => stylist.may_have_rules_for_id(id, element),
257 None => false,
258 };
259
260 if may_have_rules_for_element {
261 return true;
262 }
263
264 match candidate_id {
265 Some(id) => stylist.may_have_rules_for_id(id, candidate),
266 None => false,
267 }
268}
269
270#[inline]
272pub fn shadow_root_style_data_equals<S>(l: Option<S>, r: Option<S>) -> bool
273where
274 S: TShadowRoot,
275{
276 if l == r {
277 return true;
278 }
279 let (Some(l), Some(r)) = (l, r) else {
280 return false;
281 };
282 match (l.style_data(), r.style_data()) {
283 (Some(l), Some(r)) => std::ptr::eq(l, r),
284 (None, None) => true,
285 _ => false,
286 }
287}