mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Auto merge of #12911 - bholley:traverse_anonymous_children, r=emilio
stylo: Traverse anonymous children when styling The corresponding Gecko changes are at https://bugzilla.mozilla.org/show_bug.cgi?id=1292662 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12911) <!-- Reviewable:end -->
This commit is contained in:
commit
8e39313321
5 changed files with 127 additions and 85 deletions
|
@ -115,6 +115,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
type ConcreteElement = ServoLayoutElement<'ln>;
|
type ConcreteElement = ServoLayoutElement<'ln>;
|
||||||
type ConcreteDocument = ServoLayoutDocument<'ln>;
|
type ConcreteDocument = ServoLayoutDocument<'ln>;
|
||||||
type ConcreteRestyleDamage = RestyleDamage;
|
type ConcreteRestyleDamage = RestyleDamage;
|
||||||
|
type ConcreteChildrenIterator = ServoChildrenIterator<'ln>;
|
||||||
|
|
||||||
fn to_unsafe(&self) -> UnsafeNode {
|
fn to_unsafe(&self) -> UnsafeNode {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -147,6 +148,12 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
self.dump_style_indent(0);
|
self.dump_style_indent(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn children(self) -> ServoChildrenIterator<'ln> {
|
||||||
|
ServoChildrenIterator {
|
||||||
|
current: self.first_child(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn opaque(&self) -> OpaqueNode {
|
fn opaque(&self) -> OpaqueNode {
|
||||||
unsafe { self.get_jsmanaged().opaque() }
|
unsafe { self.get_jsmanaged().opaque() }
|
||||||
}
|
}
|
||||||
|
@ -163,10 +170,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
self.opaque().0
|
self.opaque().0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_count(&self) -> u32 {
|
|
||||||
unsafe { self.node.children_count() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_element(&self) -> Option<ServoLayoutElement<'ln>> {
|
fn as_element(&self) -> Option<ServoLayoutElement<'ln>> {
|
||||||
as_element(self.node)
|
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> {
|
impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
|
||||||
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
|
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,61 @@ pub trait LayoutNode: TNode {
|
||||||
|
|
||||||
fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
|
fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
|
||||||
fn get_style_and_layout_data(&self) -> Option<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
|
/// 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.
|
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
|
||||||
pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
|
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 ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
|
||||||
type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
|
type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
|
||||||
type ConcreteRestyleDamage: TRestyleDamage;
|
type ConcreteRestyleDamage: TRestyleDamage;
|
||||||
|
type ConcreteChildrenIterator: Iterator<Item = Self>;
|
||||||
|
|
||||||
fn to_unsafe(&self) -> UnsafeNode;
|
fn to_unsafe(&self) -> UnsafeNode;
|
||||||
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
|
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
|
||||||
|
@ -83,22 +84,8 @@ pub trait TNode : Sized + Copy + Clone {
|
||||||
|
|
||||||
fn dump_style(self);
|
fn dump_style(self);
|
||||||
|
|
||||||
fn traverse_preorder(self) -> TreeIterator<Self> {
|
|
||||||
TreeIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over this node's children.
|
/// Returns an iterator over this node's children.
|
||||||
fn children(self) -> ChildrenIterator<Self> {
|
fn children(self) -> Self::ConcreteChildrenIterator;
|
||||||
ChildrenIterator {
|
|
||||||
current: self.first_child(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rev_children(self) -> ReverseChildrenIterator<Self> {
|
|
||||||
ReverseChildrenIterator {
|
|
||||||
current: self.last_child(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts self into an `OpaqueNode`.
|
/// Converts self into an `OpaqueNode`.
|
||||||
fn opaque(&self) -> OpaqueNode;
|
fn opaque(&self) -> OpaqueNode;
|
||||||
|
@ -113,8 +100,6 @@ pub trait TNode : Sized + Copy + Clone {
|
||||||
|
|
||||||
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
||||||
|
|
||||||
fn children_count(&self) -> u32;
|
|
||||||
|
|
||||||
fn has_changed(&self) -> bool;
|
fn has_changed(&self) -> bool;
|
||||||
|
|
||||||
unsafe fn set_changed(&self, value: 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 RawServoStyleSet { }
|
||||||
pub enum nsHTMLCSSStyleSheet { }
|
pub enum nsHTMLCSSStyleSheet { }
|
||||||
pub enum ServoDeclarationBlock { }
|
pub enum ServoDeclarationBlock { }
|
||||||
|
pub enum StyleChildrenIterator { }
|
||||||
pub type ThreadSafePrincipalHolder = nsMainThreadPtrHolder<nsIPrincipal>;
|
pub type ThreadSafePrincipalHolder = nsMainThreadPtrHolder<nsIPrincipal>;
|
||||||
pub type ThreadSafeURIHolder = nsMainThreadPtrHolder<nsIURI>;
|
pub type ThreadSafeURIHolder = nsMainThreadPtrHolder<nsIURI>;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -190,6 +191,11 @@ extern "C" {
|
||||||
-> *mut RawGeckoElement;
|
-> *mut RawGeckoElement;
|
||||||
pub fn Gecko_GetDocumentElement(document: *mut RawGeckoDocument)
|
pub fn Gecko_GetDocumentElement(document: *mut RawGeckoDocument)
|
||||||
-> *mut RawGeckoElement;
|
-> *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_ElementState(element: *mut RawGeckoElement) -> u8;
|
||||||
pub fn Gecko_IsHTMLElementInHTMLDocument(element: *mut RawGeckoElement)
|
pub fn Gecko_IsHTMLElementInHTMLDocument(element: *mut RawGeckoElement)
|
||||||
-> bool;
|
-> bool;
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use gecko_bindings::bindings;
|
use gecko_bindings::bindings;
|
||||||
use gecko_bindings::bindings::Gecko_ChildrenCount;
|
|
||||||
use gecko_bindings::bindings::Gecko_ClassOrClassList;
|
use gecko_bindings::bindings::Gecko_ClassOrClassList;
|
||||||
use gecko_bindings::bindings::Gecko_GetNodeData;
|
use gecko_bindings::bindings::Gecko_GetNodeData;
|
||||||
use gecko_bindings::bindings::Gecko_GetStyleContext;
|
use gecko_bindings::bindings::Gecko_GetStyleContext;
|
||||||
use gecko_bindings::bindings::ServoNodeData;
|
use gecko_bindings::bindings::ServoNodeData;
|
||||||
use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference};
|
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_ElementState, Gecko_GetDocumentElement};
|
||||||
use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement};
|
use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement};
|
||||||
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement};
|
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_GetNodeFlags, Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
|
||||||
use gecko_bindings::bindings::{Gecko_GetParentElement, Gecko_GetParentNode};
|
use gecko_bindings::bindings::{Gecko_GetParentElement, Gecko_GetParentNode};
|
||||||
use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement};
|
use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement};
|
||||||
|
@ -134,6 +134,7 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
type ConcreteDocument = GeckoDocument<'ln>;
|
type ConcreteDocument = GeckoDocument<'ln>;
|
||||||
type ConcreteElement = GeckoElement<'ln>;
|
type ConcreteElement = GeckoElement<'ln>;
|
||||||
type ConcreteRestyleDamage = GeckoRestyleDamage;
|
type ConcreteRestyleDamage = GeckoRestyleDamage;
|
||||||
|
type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;
|
||||||
|
|
||||||
fn to_unsafe(&self) -> UnsafeNode {
|
fn to_unsafe(&self) -> UnsafeNode {
|
||||||
(self.node as usize, 0)
|
(self.node as usize, 0)
|
||||||
|
@ -163,6 +164,15 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
unimplemented!()
|
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 {
|
fn opaque(&self) -> OpaqueNode {
|
||||||
let ptr: uintptr_t = self.node as uintptr_t;
|
let ptr: uintptr_t = self.node as uintptr_t;
|
||||||
OpaqueNode(ptr)
|
OpaqueNode(ptr)
|
||||||
|
@ -180,12 +190,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_count(&self) -> u32 {
|
|
||||||
unsafe {
|
|
||||||
Gecko_ChildrenCount(self.node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_element(&self) -> Option<GeckoElement<'ln>> {
|
fn as_element(&self) -> Option<GeckoElement<'ln>> {
|
||||||
if self.is_element() {
|
if self.is_element() {
|
||||||
unsafe { Some(GeckoElement::from_raw(self.node as *mut RawGeckoElement)) }
|
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) {}
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct GeckoDocument<'ld> {
|
pub struct GeckoDocument<'ld> {
|
||||||
document: *mut RawGeckoDocument,
|
document: *mut RawGeckoDocument,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue