mirror of
https://github.com/servo/servo.git
synced 2025-08-14 01:45:33 +01:00
style: Add a special, explicit path for lazy style resolution and use it for GetComputedStyle.
MozReview-Commit-ID: KAM9mVoxCHE
This commit is contained in:
parent
7e3c9e2197
commit
ab71b29959
7 changed files with 176 additions and 119 deletions
|
@ -224,7 +224,6 @@ mod bindings {
|
|||
"RawGecko.*",
|
||||
"mozilla::ServoElementSnapshot.*",
|
||||
"mozilla::ConsumeStyleBehavior",
|
||||
"mozilla::LazyComputeBehavior",
|
||||
"mozilla::css::SheetParsingMode",
|
||||
"mozilla::TraversalRootBehavior",
|
||||
"mozilla::DisplayItemClip", // Needed because bindgen generates
|
||||
|
@ -251,7 +250,6 @@ mod bindings {
|
|||
"GridNamedArea",
|
||||
"Image",
|
||||
"ImageURL",
|
||||
"LazyComputeBehavior",
|
||||
"nsAttrName",
|
||||
"nsAttrValue",
|
||||
"nsBorderColors",
|
||||
|
@ -451,7 +449,6 @@ mod bindings {
|
|||
"ThreadSafeURIHolder",
|
||||
"ThreadSafePrincipalHolder",
|
||||
"ConsumeStyleBehavior",
|
||||
"LazyComputeBehavior",
|
||||
"TraversalRootBehavior",
|
||||
"FontFamilyList",
|
||||
"FontFamilyType",
|
||||
|
|
|
@ -260,14 +260,6 @@ impl<'le> GeckoElement<'le> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_pseudo_style(&self, pseudo: &PseudoElement) -> Option<Arc<ComputedValues>> {
|
||||
// FIXME(bholley): Gecko sometimes resolves pseudos after an element has
|
||||
// already been marked for restyle. We should consider fixing this, and
|
||||
// then assert has_current_styles here.
|
||||
self.borrow_data().and_then(|data| data.styles().pseudos
|
||||
.get(pseudo).map(|c| c.values.clone()))
|
||||
}
|
||||
|
||||
// Only safe to call with exclusive access to the element.
|
||||
pub unsafe fn ensure_data(&self) -> &AtomicRefCell<ElementData> {
|
||||
match self.get_data() {
|
||||
|
|
|
@ -9,7 +9,6 @@ use gecko_bindings::structs::RawGeckoNode;
|
|||
use gecko_bindings::structs::ThreadSafeURIHolder;
|
||||
use gecko_bindings::structs::ThreadSafePrincipalHolder;
|
||||
use gecko_bindings::structs::ConsumeStyleBehavior;
|
||||
use gecko_bindings::structs::LazyComputeBehavior;
|
||||
use gecko_bindings::structs::TraversalRootBehavior;
|
||||
use gecko_bindings::structs::FontFamilyList;
|
||||
use gecko_bindings::structs::FontFamilyType;
|
||||
|
@ -1209,9 +1208,7 @@ extern "C" {
|
|||
}
|
||||
extern "C" {
|
||||
pub fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
|
||||
set: RawServoStyleSetBorrowed,
|
||||
consume: ConsumeStyleBehavior,
|
||||
compute: LazyComputeBehavior)
|
||||
consume: ConsumeStyleBehavior)
|
||||
-> ServoComputedValuesStrong;
|
||||
}
|
||||
extern "C" {
|
||||
|
@ -1220,6 +1217,13 @@ extern "C" {
|
|||
set: RawServoStyleSetBorrowed)
|
||||
-> ServoComputedValuesStrong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
||||
pseudo_tag: *mut nsIAtom,
|
||||
consume: ConsumeStyleBehavior,
|
||||
set: RawServoStyleSetBorrowed)
|
||||
-> ServoComputedValuesStrong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
||||
set: RawServoStyleSetBorrowed,
|
||||
|
|
|
@ -709,13 +709,13 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn cascade_node(&self,
|
||||
context: &StyleContext<Self>,
|
||||
mut data: &mut AtomicRefMut<ElementData>,
|
||||
parent: Option<Self>,
|
||||
primary_rule_node: StrongRuleNode,
|
||||
pseudo_rule_nodes: PseudoRuleNodes,
|
||||
primary_is_shareable: bool)
|
||||
fn cascade_node(&self,
|
||||
context: &StyleContext<Self>,
|
||||
mut data: &mut AtomicRefMut<ElementData>,
|
||||
parent: Option<Self>,
|
||||
primary_rule_node: StrongRuleNode,
|
||||
pseudo_rule_nodes: PseudoRuleNodes,
|
||||
primary_is_shareable: bool)
|
||||
{
|
||||
// Get our parent's style.
|
||||
let parent_data = parent.as_ref().map(|x| x.borrow_data().unwrap());
|
||||
|
@ -770,10 +770,12 @@ pub trait MatchMethods : TElement {
|
|||
pseudo_rule_nodes,
|
||||
&mut possibly_expired_animations);
|
||||
|
||||
self.as_node().set_can_be_fragmented(parent.map_or(false, |p| {
|
||||
p.as_node().can_be_fragmented() ||
|
||||
parent_style.unwrap().is_multicol()
|
||||
}));
|
||||
unsafe {
|
||||
self.as_node().set_can_be_fragmented(parent.map_or(false, |p| {
|
||||
p.as_node().can_be_fragmented() ||
|
||||
parent_style.unwrap().is_multicol()
|
||||
}));
|
||||
}
|
||||
|
||||
damage
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||
use context::{SharedStyleContext, StyleContext};
|
||||
use data::{ElementData, StoredRestyleHint};
|
||||
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
||||
use dom::{TElement, TNode};
|
||||
use matching::{MatchMethods, StyleSharingResult};
|
||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_SELF};
|
||||
|
@ -265,40 +265,77 @@ pub fn relations_are_shareable(relations: &StyleRelations) -> bool {
|
|||
AFFECTED_BY_PRESENTATIONAL_HINTS)
|
||||
}
|
||||
|
||||
/// Handles lazy resolution of style in display:none subtrees. See the comment
|
||||
/// at the callsite in query.rs.
|
||||
pub fn style_element_in_display_none_subtree<E, F>(context: &StyleContext<E>,
|
||||
element: E, init_data: &F) -> E
|
||||
/// Helper for the function below.
|
||||
fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_data: &F)
|
||||
-> Option<E>
|
||||
where E: TElement,
|
||||
F: Fn(E),
|
||||
{
|
||||
// Check the base case.
|
||||
if element.get_data().is_some() {
|
||||
// See the comment on `cascade_node` for why we allow this on Gecko.
|
||||
debug_assert!(cfg!(feature = "gecko") || element.borrow_data().unwrap().has_current_styles());
|
||||
debug_assert!(element.borrow_data().unwrap().styles().is_display_none());
|
||||
return element;
|
||||
}
|
||||
|
||||
// Ensure the parent is styled.
|
||||
let parent = element.parent_element().unwrap();
|
||||
let display_none_root = style_element_in_display_none_subtree(context, parent, init_data);
|
||||
|
||||
// Initialize our data.
|
||||
init_data(element);
|
||||
|
||||
// Resolve our style.
|
||||
ensure_data(element);
|
||||
let mut data = element.mutate_data().unwrap();
|
||||
let match_results = element.match_element(context, None);
|
||||
unsafe {
|
||||
let mut display_none_root = None;
|
||||
|
||||
// If the Element isn't styled, we need to compute its style.
|
||||
if data.get_styles().is_none() {
|
||||
// Compute the parent style if necessary.
|
||||
if let Some(parent) = element.parent_element() {
|
||||
display_none_root = resolve_style_internal(context, parent, ensure_data);
|
||||
}
|
||||
|
||||
// Compute our style.
|
||||
let match_results = element.match_element(context, None);
|
||||
let shareable = match_results.primary_is_shareable();
|
||||
element.cascade_node(context, &mut data, Some(parent),
|
||||
element.cascade_node(context, &mut data, element.parent_element(),
|
||||
match_results.primary,
|
||||
match_results.per_pseudo,
|
||||
shareable);
|
||||
|
||||
// Conservatively mark us as having dirty descendants, since there might
|
||||
// be other unstyled siblings we miss when walking straight up the parent
|
||||
// chain.
|
||||
unsafe { element.set_dirty_descendants() };
|
||||
}
|
||||
|
||||
display_none_root
|
||||
// If we're display:none and none of our ancestors are, we're the root
|
||||
// of a display:none subtree.
|
||||
if display_none_root.is_none() && data.styles().is_display_none() {
|
||||
display_none_root = Some(element);
|
||||
}
|
||||
|
||||
return display_none_root
|
||||
}
|
||||
|
||||
/// Manually resolve style by sequentially walking up the parent chain to the
|
||||
/// first styled Element, ignoring pending restyles. The resolved style is
|
||||
/// made available via a callback, and can be dropped by the time this function
|
||||
/// returns in the display:none subtree case.
|
||||
pub fn resolve_style<E, F, G, H>(context: &StyleContext<E>, element: E,
|
||||
ensure_data: &F, clear_data: &G, callback: H)
|
||||
where E: TElement,
|
||||
F: Fn(E),
|
||||
G: Fn(E),
|
||||
H: FnOnce(&ElementStyles)
|
||||
{
|
||||
// Resolve styles up the tree.
|
||||
let display_none_root = resolve_style_internal(context, element, ensure_data);
|
||||
|
||||
// Make them available for the scope of the callback. The callee may use the
|
||||
// argument, or perform any other processing that requires the styles to exist
|
||||
// on the Element.
|
||||
callback(element.borrow_data().unwrap().styles());
|
||||
|
||||
// Clear any styles in display:none subtrees to leave the tree in a valid state.
|
||||
if let Some(root) = display_none_root {
|
||||
let mut curr = element;
|
||||
loop {
|
||||
unsafe { curr.unset_dirty_descendants(); }
|
||||
if curr == root {
|
||||
break;
|
||||
}
|
||||
clear_data(curr);
|
||||
curr = curr.parent_element().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the style for a single node.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue