diff --git a/components/layout/query.rs b/components/layout/query.rs index aed02a9392e..5b7d2ad6625 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -30,6 +30,7 @@ use std::ops::Deref; use std::sync::{Arc, Mutex}; use string_cache::Atom; use style::computed_values; +use style::context::StyleContext; use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection}; use style::properties::longhands::{display, position}; use style::properties::style_structs; @@ -37,7 +38,7 @@ use style::selector_impl::PseudoElement; use style::selector_matching::Stylist; use style::values::LocalToCss; use style_traits::cursor::Cursor; -use wrapper::ThreadSafeLayoutNodeHelpers; +use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers}; /// Mutable data belonging to the LayoutThread. /// @@ -616,9 +617,32 @@ pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layou /// Return the resolved value of property for a given (pseudo)element. /// https://drafts.csswg.org/cssom/#resolved-value -pub fn process_resolved_style_request( - requested_node: N, pseudo: &Option, - property: &Atom, layout_root: &mut FlowRef) -> Option { +pub fn process_resolved_style_request<'a, N, C>(requested_node: N, + style_context: &'a C, + pseudo: &Option, + property: &Atom, + layout_root: &mut FlowRef) -> Option + where N: LayoutNode, + C: StyleContext<'a> +{ + use style::traversal::ensure_node_styled; + + // This node might have display: none, or it's style might be not up to + // date, so we might need to do style recalc. + // + // XXX: Is a bit shame we have to do this instead of in style :/ + let mut cur = Some(requested_node); + while let Some(current) = cur { + if current.borrow_data().is_some() { + break; + } + + current.initialize_data(); + cur = current.parent_node(); + } + + ensure_node_styled(requested_node, style_context); + let layout_node = requested_node.to_threadsafe(); let layout_node = match *pseudo { Some(PseudoElement::Before) => layout_node.get_before_pseudo(), diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 958a2acc71e..344549691f6 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1228,8 +1228,13 @@ impl LayoutThread { }, ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { let node = unsafe { ServoLayoutNode::new(&node) }; + let layout_context = LayoutContext::new(&shared_layout_context); rw_data.resolved_style_response = - process_resolved_style_request(node, pseudo, property, &mut root_flow); + process_resolved_style_request(node, + &layout_context, + pseudo, + property, + &mut root_flow); }, ReflowQueryType::OffsetParentQuery(node) => { let node = unsafe { ServoLayoutNode::new(&node) }; diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 6c13af1566d..9bab63b2692 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -193,6 +193,79 @@ pub trait DomTraversalContext { } } +pub fn ensure_node_styled<'a, N, C>(node: N, + context: &'a C) + where N: TNode, + C: StyleContext<'a> +{ + let mut display_none = false; + ensure_node_styled_internal(node, context, &mut display_none); +} + +#[allow(unsafe_code)] +fn ensure_node_styled_internal<'a, N, C>(node: N, + context: &'a C, + parents_had_display_none: &mut bool) + where N: TNode, + C: StyleContext<'a> +{ + use properties::longhands::display::computed_value as display; + + // Ensure we have style data available. This must be done externally because + // there's no way to initialize the style data from the style system + // (because in Servo it's coupled with the layout data too). + // + // Ideally we'd have an initialize_data() or something similar but just for + // style data. + debug_assert!(node.borrow_data().is_some(), + "Need to initialize the data before calling ensure_node_styled"); + + // We need to go to the root and ensure their style is up to date. + // + // This means potentially a bit of wasted work (usually not much). We could + // add a flag at the node at which point we stopped the traversal to know + // where should we stop, but let's not add that complication unless needed. + let parent = match node.parent_node() { + Some(parent) if parent.is_element() => Some(parent), + _ => None, + }; + + if let Some(parent) = parent { + ensure_node_styled_internal(parent, context, parents_had_display_none); + } + + // Common case: our style is already resolved and none of our ancestors had + // display: none. + // + // We only need to mark whether we have display none, and forget about it, + // our style is up to date. + if let Some(ref style) = node.borrow_data().unwrap().style { + if !*parents_had_display_none { + *parents_had_display_none = style.get_box().clone_display() == display::T::none; + return; + } + } + + // Otherwise, our style might be out of date. Time to do selector matching + // if appropriate and cascade the node. + // + // Note that we could add the bloom filter's complexity here, but that's + // probably not necessary since we're likely to be matching only a few + // nodes, at best. + let mut applicable_declarations = ApplicableDeclarations::new(); + if let Some(element) = node.as_element() { + let stylist = &context.shared_context().stylist; + + element.match_element(&**stylist, + None, + &mut applicable_declarations); + } + + unsafe { + node.cascade_node(context, parent, &applicable_declarations); + } +} + /// Calculates the style for a single node. #[inline] #[allow(unsafe_code)] @@ -200,7 +273,8 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, root: OpaqueNode, node: N) -> RestyleResult where N: TNode, - C: StyleContext<'a> { + C: StyleContext<'a> +{ // Get the parent node. let parent_opt = match node.parent_node() { Some(parent) if parent.is_element() => Some(parent), diff --git a/tests/wpt/metadata-css/css-transitions-1_dev/html/hidden-container-001.htm.ini b/tests/wpt/metadata-css/css-transitions-1_dev/html/hidden-container-001.htm.ini deleted file mode 100644 index 27e2c118109..00000000000 --- a/tests/wpt/metadata-css/css-transitions-1_dev/html/hidden-container-001.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[hidden-container-001.htm] - type: testharness - [transition within display:none / values] - expected: FAIL -