mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40: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 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(),
|
||||||
|
|
|
@ -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) };
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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