mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
layout: Ensure a element's style is up to date when processing queries.
This commit is contained in:
parent
17772d1618
commit
6b60383f24
4 changed files with 109 additions and 11 deletions
|
@ -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<N: LayoutNode>(
|
||||
requested_node: N, pseudo: &Option<PseudoElement>,
|
||||
property: &Atom, layout_root: &mut FlowRef) -> Option<String> {
|
||||
pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||
style_context: &'a C,
|
||||
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 = match *pseudo {
|
||||
Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
|
||||
|
|
|
@ -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) };
|
||||
|
|
|
@ -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.
|
||||
#[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),
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[hidden-container-001.htm]
|
||||
type: testharness
|
||||
[transition within display:none / values]
|
||||
expected: FAIL
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue