style: Allow calling GetBaseComputedStylesForElement for an unstyled element.

Before this refactoring, getComputedStyle could have side effects, and left the
style data in the element, so we could never arrive there without data.

There are a few crashtests that caught this, but this was already broken if you
called animate() on an element deep in a display: none subtree.

MozReview-Commit-ID: 1AvOvhAyOP3
This commit is contained in:
Emilio Cobos Álvarez 2017-07-10 13:33:21 +02:00
parent c6d5dbbb01
commit d15acc219e
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
2 changed files with 33 additions and 39 deletions

View file

@ -840,37 +840,6 @@ pub trait MatchMethods : TElement {
// StyleChange::Changed conservatively. // StyleChange::Changed conservatively.
StyleDifference::new(damage, StyleChange::Changed) StyleDifference::new(damage, StyleChange::Changed)
} }
/// Returns computed values without animation and transition rules.
fn get_base_style(
&self,
context: &mut StyleContext<Self>,
style: &Arc<ComputedValues>,
) -> Arc<ComputedValues> {
use style_resolver::StyleResolverForElement;
let rule_node = style.rules.as_ref().unwrap();
let without_animation_rules =
context.shared.stylist.rule_tree().remove_animation_rules(rule_node);
if without_animation_rules == *rule_node {
// Note that unwrapping here is fine, because the style is only
// incomplete during the styling process.
return style.clone();
}
// This currently ignores visited styles, which seems acceptable,
// as existing browsers don't appear to animate visited styles.
let inputs =
CascadeInputs {
rules: Some(without_animation_rules),
visited_rules: None,
};
let style =
StyleResolverForElement::new(*self, context, RuleInclusion::All)
.cascade_style_and_visited_with_default_parents(inputs);
style
}
} }
impl<E: TElement> MatchMethods for E {} impl<E: TElement> MatchMethods for E {}

View file

@ -654,19 +654,35 @@ pub extern "C" fn Servo_AnimationValue_Uncompute(value: RawServoAnimationValueBo
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawServoStyleSetBorrowed, pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawServoStyleSetBorrowed,
element: RawGeckoElementBorrowed, element: RawGeckoElementBorrowed,
computed_values: ServoComputedValuesBorrowed,
snapshots: *const ServoElementSnapshotTable, snapshots: *const ServoElementSnapshotTable,
pseudo_type: CSSPseudoElementType) pseudo_type: CSSPseudoElementType)
-> ServoComputedValuesStrong -> ServoComputedValuesStrong
{ {
use style::matching::MatchMethods; use style::style_resolver::StyleResolverForElement;
debug_assert!(!snapshots.is_null()); debug_assert!(!snapshots.is_null());
let computed_values = ComputedValues::as_arc(&computed_values);
let rules = match computed_values.rules {
None => return computed_values.clone().into_strong(),
Some(ref rules) => rules,
};
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let global_style_data = &*GLOBAL_STYLE_DATA; let without_animations =
let guard = global_style_data.shared_lock.read(); doc_data.stylist.rule_tree().remove_animation_rules(rules);
if without_animations == *rules {
return computed_values.clone().into_strong();
}
let element = GeckoElement(element); let element = GeckoElement(element);
let element_data = element.borrow_data().unwrap();
let element_data = match element.borrow_data() {
Some(data) => data,
None => return computed_values.clone().into_strong(),
};
let styles = &element_data.styles; let styles = &element_data.styles;
if let Some(pseudo) = PseudoElement::from_pseudo_type(pseudo_type) { if let Some(pseudo) = PseudoElement::from_pseudo_type(pseudo_type) {
@ -678,6 +694,8 @@ pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawSe
.clone().into_strong(); .clone().into_strong();
} }
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let shared = create_shared_context(&global_style_data, let shared = create_shared_context(&global_style_data,
&guard, &guard,
&doc_data, &doc_data,
@ -689,10 +707,17 @@ pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawSe
thread_local: &mut tlc, thread_local: &mut tlc,
}; };
element.get_base_style( // This currently ignores visited styles, which seems acceptable, as
&mut context, // existing browsers don't appear to animate visited styles.
styles.primary(), let inputs =
).into_strong() CascadeInputs {
rules: Some(without_animations),
visited_rules: None,
};
StyleResolverForElement::new(element, &mut context, RuleInclusion::All)
.cascade_style_and_visited_with_default_parents(inputs)
.into_strong()
} }
#[no_mangle] #[no_mangle]