Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stylo: Traverse anonymous children when styling #12911

Merged
merged 4 commits into from Aug 26, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -115,6 +115,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
type ConcreteElement = ServoLayoutElement<'ln>;
type ConcreteDocument = ServoLayoutDocument<'ln>;
type ConcreteRestyleDamage = RestyleDamage;
type ConcreteChildrenIterator = ServoChildrenIterator<'ln>;

fn to_unsafe(&self) -> UnsafeNode {
unsafe {
@@ -147,6 +148,12 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
self.dump_style_indent(0);
}

fn children(self) -> ServoChildrenIterator<'ln> {
ServoChildrenIterator {
current: self.first_child(),
}
}

fn opaque(&self) -> OpaqueNode {
unsafe { self.get_jsmanaged().opaque() }
}
@@ -163,10 +170,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
self.opaque().0
}

fn children_count(&self) -> u32 {
unsafe { self.node.children_count() }
}

fn as_element(&self) -> Option<ServoLayoutElement<'ln>> {
as_element(self.node)
}
@@ -280,6 +283,19 @@ 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>;

@@ -80,8 +80,61 @@ pub trait LayoutNode: TNode {

fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>;

fn rev_children(self) -> ReverseChildrenIterator<Self> {
ReverseChildrenIterator {
current: self.last_child(),
}
}

fn traverse_preorder(self) -> TreeIterator<Self> {
TreeIterator::new(self)
}
}

pub struct ReverseChildrenIterator<ConcreteNode> where ConcreteNode: TNode {
current: Option<ConcreteNode>,
}

impl<ConcreteNode> Iterator for ReverseChildrenIterator<ConcreteNode>
where ConcreteNode: TNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}

pub struct TreeIterator<ConcreteNode> where ConcreteNode: TNode {
stack: Vec<ConcreteNode>,
}

impl<ConcreteNode> TreeIterator<ConcreteNode> where ConcreteNode: LayoutNode {
fn new(root: ConcreteNode) -> TreeIterator<ConcreteNode> {
let mut stack = vec![];
stack.push(root);
TreeIterator {
stack: stack,
}
}

pub fn next_skipping_children(&mut self) -> Option<ConcreteNode> {
self.stack.pop()
}
}

impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode>
where ConcreteNode: LayoutNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}


/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
@@ -68,6 +68,7 @@ pub trait TNode : Sized + Copy + Clone {
type ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
type ConcreteRestyleDamage: TRestyleDamage;
type ConcreteChildrenIterator: Iterator<Item = Self>;

fn to_unsafe(&self) -> UnsafeNode;
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
@@ -83,22 +84,8 @@ pub trait TNode : Sized + Copy + Clone {

fn dump_style(self);

fn traverse_preorder(self) -> TreeIterator<Self> {
TreeIterator::new(self)
}

/// Returns an iterator over this node's children.
fn children(self) -> ChildrenIterator<Self> {
ChildrenIterator {
current: self.first_child(),
}
}

fn rev_children(self) -> ReverseChildrenIterator<Self> {
ReverseChildrenIterator {
current: self.last_child(),
}
}
fn children(self) -> Self::ConcreteChildrenIterator;

/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
@@ -113,8 +100,6 @@ pub trait TNode : Sized + Copy + Clone {

fn as_document(&self) -> Option<Self::ConcreteDocument>;

fn children_count(&self) -> u32;

fn has_changed(&self) -> bool;

unsafe fn set_changed(&self, value: bool);
@@ -254,59 +239,3 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
}
}
}

pub struct TreeIterator<ConcreteNode> where ConcreteNode: TNode {
stack: Vec<ConcreteNode>,
}

impl<ConcreteNode> TreeIterator<ConcreteNode> where ConcreteNode: TNode {
fn new(root: ConcreteNode) -> TreeIterator<ConcreteNode> {
let mut stack = vec![];
stack.push(root);
TreeIterator {
stack: stack,
}
}

pub fn next_skipping_children(&mut self) -> Option<ConcreteNode> {
self.stack.pop()
}
}

impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode>
where ConcreteNode: TNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
}
}

pub struct ChildrenIterator<ConcreteNode> where ConcreteNode: TNode {
current: Option<ConcreteNode>,
}

impl<ConcreteNode> Iterator for ChildrenIterator<ConcreteNode>
where ConcreteNode: TNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}

pub struct ReverseChildrenIterator<ConcreteNode> where ConcreteNode: TNode {
current: Option<ConcreteNode>,
}

impl<ConcreteNode> Iterator for ReverseChildrenIterator<ConcreteNode>
where ConcreteNode: TNode {
type Item = ConcreteNode;
fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}
@@ -168,6 +168,7 @@ pub enum RawServoStyleSheet { }
pub enum RawServoStyleSet { }
pub enum nsHTMLCSSStyleSheet { }
pub enum ServoDeclarationBlock { }
pub enum StyleChildrenIterator { }
pub type ThreadSafePrincipalHolder = nsMainThreadPtrHolder<nsIPrincipal>;
pub type ThreadSafeURIHolder = nsMainThreadPtrHolder<nsIURI>;
extern "C" {
@@ -190,6 +191,11 @@ extern "C" {
-> *mut RawGeckoElement;
pub fn Gecko_GetDocumentElement(document: *mut RawGeckoDocument)
-> *mut RawGeckoElement;
pub fn Gecko_MaybeCreateStyleChildrenIterator(node: *mut RawGeckoNode)
-> *mut StyleChildrenIterator;
pub fn Gecko_DropStyleChildrenIterator(it: *mut StyleChildrenIterator);
pub fn Gecko_GetNextStyleChild(it: *mut StyleChildrenIterator)
-> *mut RawGeckoNode;
pub fn Gecko_ElementState(element: *mut RawGeckoElement) -> u8;
pub fn Gecko_IsHTMLElementInHTMLDocument(element: *mut RawGeckoElement)
-> bool;
@@ -5,16 +5,16 @@
#![allow(unsafe_code)]

use gecko_bindings::bindings;
use gecko_bindings::bindings::Gecko_ChildrenCount;
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetNodeData;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::bindings::ServoNodeData;
use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference};
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement};
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement};
use gecko_bindings::bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement};
use gecko_bindings::bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_GetNodeFlags, Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::{Gecko_GetParentElement, Gecko_GetParentNode};
use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement};
@@ -134,6 +134,7 @@ impl<'ln> TNode for GeckoNode<'ln> {
type ConcreteDocument = GeckoDocument<'ln>;
type ConcreteElement = GeckoElement<'ln>;
type ConcreteRestyleDamage = GeckoRestyleDamage;
type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;

fn to_unsafe(&self) -> UnsafeNode {
(self.node as usize, 0)
@@ -163,6 +164,15 @@ impl<'ln> TNode for GeckoNode<'ln> {
unimplemented!()
}

fn children(self) -> GeckoChildrenIterator<'ln> {
let maybe_iter = unsafe { Gecko_MaybeCreateStyleChildrenIterator(self.node) };
if !maybe_iter.is_null() {
GeckoChildrenIterator::GeckoIterator(maybe_iter)
} else {
GeckoChildrenIterator::Current(self.first_child())
}
}

fn opaque(&self) -> OpaqueNode {
let ptr: uintptr_t = self.node as uintptr_t;
OpaqueNode(ptr)
@@ -180,12 +190,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
unimplemented!()
}

fn children_count(&self) -> u32 {
unsafe {
Gecko_ChildrenCount(self.node)
}
}

fn as_element(&self) -> Option<GeckoElement<'ln>> {
if self.is_element() {
unsafe { Some(GeckoElement::from_raw(self.node as *mut RawGeckoElement)) }
@@ -341,6 +345,40 @@ impl<'ln> TNode for GeckoNode<'ln> {
unsafe fn set_dirty_on_viewport_size_changed(&self) {}
}

// We generally iterate children by traversing the siblings of the first child
// like Servo does. However, for nodes with anonymous children, we use a custom
// (heavier-weight) Gecko-implemented iterator.
pub enum GeckoChildrenIterator<'a> {
Current(Option<GeckoNode<'a>>),
GeckoIterator(*mut bindings::StyleChildrenIterator),
}

impl<'a> Drop for GeckoChildrenIterator<'a> {
fn drop(&mut self) {
if let GeckoChildrenIterator::GeckoIterator(it) = *self {
unsafe {
Gecko_DropStyleChildrenIterator(it);
}
}
}
}

impl<'a> Iterator for GeckoChildrenIterator<'a> {
type Item = GeckoNode<'a>;
fn next(&mut self) -> Option<GeckoNode<'a>> {
match *self {
GeckoChildrenIterator::Current(curr) => {
let next = curr.and_then(|node| node.next_sibling());
*self = GeckoChildrenIterator::Current(next);
curr
},
GeckoChildrenIterator::GeckoIterator(it) => unsafe {
Gecko_GetNextStyleChild(it).as_ref().map(|n| GeckoNode::from_ref(n))

This comment has been minimized.

@emilio

emilio Aug 18, 2016

Member

You can eta-reduce this closure ;-)

This comment has been minimized.

@bholley

bholley Aug 26, 2016

Author Contributor

I can't:

Compiling geckoservo v0.0.1 (file:///files/mozilla/stylo/bb/servo/ports/geckolib)
wrapper.rs:376:54: 376:57 error: the trait bound unsafe fn(&gecko_bindings::bindings::nsINode) -> wrapper::GeckoNode<'_> {wrapper::GeckoNode<'_>::from_ref}: std::ops::FnOnce<(&gecko_bindings::bindings::nsINode,)> is not satisfied [E0277]
wrapper.rs:376 Gecko_GetNextStyleChild(it).as_ref().map(GeckoNode::from_ref)
^~~
wrapper.rs:376:54: 376:57 help: run rustc --explain E0277 to see a detailed explanation
error: aborting due to previous error
error: Could not compile geckoservo.

To learn more, run the command again with --verbose.

}
}
}
}

#[derive(Clone, Copy)]
pub struct GeckoDocument<'ld> {
document: *mut RawGeckoDocument,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.