style: Refactor children handling.

Moving traversal_children away from TNode I can make TNode trivial enough, in
order to share a QuerySelector implementation between Servo and Gecko.
This commit is contained in:
Emilio Cobos Álvarez 2017-10-16 14:25:25 +02:00
parent 7c2265360f
commit a11d268468
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
9 changed files with 149 additions and 158 deletions

View file

@ -68,7 +68,7 @@ use style::attr::AttrValue;
use style::computed_values::display;
use style::context::SharedStyleContext;
use style::data::ElementData;
use style::dom::{LayoutIterator, NodeInfo, OpaqueNode};
use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode};
use style::dom::{PresentationalHintsSynthesizer, TElement, TNode};
use style::element_state::*;
use style::font_metrics::ServoMetricsProvider;
@ -159,7 +159,6 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
impl<'ln> TNode for ServoLayoutNode<'ln> {
type ConcreteElement = ServoLayoutElement<'ln>;
type ConcreteChildrenIterator = ServoChildrenIterator<'ln>;
fn parent_node(&self) -> Option<Self> {
unsafe {
@ -167,20 +166,34 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
}
}
fn children(&self) -> LayoutIterator<ServoChildrenIterator<'ln>> {
LayoutIterator(ServoChildrenIterator {
current: self.first_child(),
})
fn first_child(&self) -> Option<Self> {
unsafe {
self.node.first_child_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn last_child(&self) -> Option<Self> {
unsafe {
self.node.last_child_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn prev_sibling(&self) -> Option<Self> {
unsafe {
self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn next_sibling(&self) -> Option<Self> {
unsafe {
self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn traversal_parent(&self) -> Option<ServoLayoutElement<'ln>> {
self.parent_element()
}
fn traversal_children(&self) -> LayoutIterator<ServoChildrenIterator<'ln>> {
self.children()
}
fn opaque(&self) -> OpaqueNode {
unsafe { self.get_jsmanaged().opaque() }
}
@ -206,19 +219,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
}
}
pub struct ServoChildrenIterator<'a> {
current: Option<ServoLayoutNode<'a>>,
}
impl<'a> Iterator for ServoChildrenIterator<'a> {
type Item = ServoLayoutNode<'a>;
fn next(&mut self) -> Option<ServoLayoutNode<'a>> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
@ -248,30 +248,6 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
unsafe fn take_style_and_layout_data(&self) -> OpaqueStyleAndLayoutData {
self.get_jsmanaged().take_style_and_layout_data()
}
fn first_child(&self) -> Option<ServoLayoutNode<'ln>> {
unsafe {
self.node.first_child_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn last_child(&self) -> Option<ServoLayoutNode<'ln>> {
unsafe {
self.node.last_child_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn prev_sibling(&self) -> Option<ServoLayoutNode<'ln>> {
unsafe {
self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
fn next_sibling(&self) -> Option<ServoLayoutNode<'ln>> {
unsafe {
self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
}
}
}
impl<'ln> GetLayoutData for ServoLayoutNode<'ln> {
@ -320,8 +296,8 @@ impl<'ld> ServoLayoutDocument<'ld> {
ServoLayoutNode::from_layout_js(self.document.upcast())
}
pub fn root_node(&self) -> Option<ServoLayoutNode<'ld>> {
self.as_node().children().find(ServoLayoutNode::is_element)
pub fn root_element(&self) -> Option<ServoLayoutElement<'ld>> {
self.as_node().dom_children().flat_map(|n| n.as_element()).next()
}
pub fn drain_pending_restyles(&self) -> Vec<(ServoLayoutElement<'ld>, PendingRestyle)> {
@ -380,6 +356,7 @@ impl<'le> PresentationalHintsSynthesizer for ServoLayoutElement<'le> {
impl<'le> TElement for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>;
type TraversalChildrenIterator = DomChildren<Self::ConcreteNode>;
type FontMetricsProvider = ServoMetricsProvider;
@ -387,6 +364,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast())
}
fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator> {
LayoutIterator(self.as_node().dom_children())
}
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
unsafe {
(*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc())
@ -629,7 +610,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
fn first_child_element(&self) -> Option<ServoLayoutElement<'le>> {
self.as_node().children().filter_map(|n| n.as_element()).next()
self.as_node().dom_children().filter_map(|n| n.as_element()).next()
}
fn last_child_element(&self) -> Option<ServoLayoutElement<'le>> {
@ -690,7 +671,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
fn is_empty(&self) -> bool {
self.as_node().children().all(|node| match node.script_type_id() {
self.as_node().dom_children().all(|node| match node.script_type_id() {
NodeTypeId::Element(..) => false,
NodeTypeId::CharacterData(CharacterDataTypeId::Text) => unsafe {
node.node.downcast().unwrap().data_for_layout().is_empty()
@ -850,20 +831,14 @@ impl<'ln> ServoThreadSafeLayoutNode<'ln> {
}
}
// NB: The implementation here is a bit tricky because elements implementing
// pseudos are supposed to return false for is_element().
impl<'ln> NodeInfo for ServoThreadSafeLayoutNode<'ln> {
fn is_element(&self) -> bool {
self.pseudo == PseudoElementType::Normal && self.node.is_element()
self.node.is_element()
}
fn is_text_node(&self) -> bool {
self.node.is_text_node()
}
fn needs_layout(&self) -> bool {
self.node.is_text_node() || self.node.is_element()
}
}
impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {

View file

@ -1067,7 +1067,7 @@ impl LayoutThread {
let mut rw_data = possibly_locked_rw_data.lock();
let element: ServoLayoutElement = match document.root_node() {
let element = match document.root_element() {
None => {
// Since we cannot compute anything, give spec-required placeholders.
debug!("layout: No root node: bailing");
@ -1112,7 +1112,7 @@ impl LayoutThread {
}
return;
},
Some(x) => x.as_element().unwrap(),
Some(x) => x,
};
debug!("layout: processing reflow request for: {:?} ({}) (query={:?})",