layout: Ensure a element's style is up to date when processing queries.

This commit is contained in:
Emilio Cobos Álvarez 2016-08-07 14:54:05 -07:00
parent 17772d1618
commit 6b60383f24
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 109 additions and 11 deletions

View file

@ -30,6 +30,7 @@ use std::ops::Deref;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use string_cache::Atom; use string_cache::Atom;
use style::computed_values; use style::computed_values;
use style::context::StyleContext;
use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection}; use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection};
use style::properties::longhands::{display, position}; use style::properties::longhands::{display, position};
use style::properties::style_structs; use style::properties::style_structs;
@ -37,7 +38,7 @@ use style::selector_impl::PseudoElement;
use style::selector_matching::Stylist; use style::selector_matching::Stylist;
use style::values::LocalToCss; use style::values::LocalToCss;
use style_traits::cursor::Cursor; use style_traits::cursor::Cursor;
use wrapper::ThreadSafeLayoutNodeHelpers; use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers};
/// Mutable data belonging to the LayoutThread. /// 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. /// Return the resolved value of property for a given (pseudo)element.
/// https://drafts.csswg.org/cssom/#resolved-value /// https://drafts.csswg.org/cssom/#resolved-value
pub fn process_resolved_style_request<N: LayoutNode>( pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
requested_node: N, pseudo: &Option<PseudoElement>, style_context: &'a C,
property: &Atom, layout_root: &mut FlowRef) -> Option<String> { pseudo: &Option<PseudoElement>,
property: &Atom,
layout_root: &mut FlowRef) -> Option<String>
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 = requested_node.to_threadsafe();
let layout_node = match *pseudo { let layout_node = match *pseudo {
Some(PseudoElement::Before) => layout_node.get_before_pseudo(), Some(PseudoElement::Before) => layout_node.get_before_pseudo(),

View file

@ -1228,8 +1228,13 @@ impl LayoutThread {
}, },
ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => {
let node = unsafe { ServoLayoutNode::new(&node) }; let node = unsafe { ServoLayoutNode::new(&node) };
let layout_context = LayoutContext::new(&shared_layout_context);
rw_data.resolved_style_response = 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) => { ReflowQueryType::OffsetParentQuery(node) => {
let node = unsafe { ServoLayoutNode::new(&node) }; let node = unsafe { ServoLayoutNode::new(&node) };

View file

@ -193,6 +193,79 @@ pub trait DomTraversalContext<N: TNode> {
} }
} }
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. /// Calculates the style for a single node.
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -200,7 +273,8 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C,
root: OpaqueNode, root: OpaqueNode,
node: N) -> RestyleResult node: N) -> RestyleResult
where N: TNode, where N: TNode,
C: StyleContext<'a> { C: StyleContext<'a>
{
// Get the parent node. // Get the parent node.
let parent_opt = match node.parent_node() { let parent_opt = match node.parent_node() {
Some(parent) if parent.is_element() => Some(parent), Some(parent) if parent.is_element() => Some(parent),

View file

@ -1,5 +0,0 @@
[hidden-container-001.htm]
type: testharness
[transition within display:none / values]
expected: FAIL