Implement GeckoChildrenIterator to traverse anonymous children.

This commit is contained in:
Bobby Holley 2016-08-10 17:52:19 -07:00
parent 1799b0a5df
commit 122df8ca60
2 changed files with 39 additions and 8 deletions

View file

@ -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;

View file

@ -10,10 +10,11 @@ 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};
@ -164,8 +165,11 @@ impl<'ln> TNode for GeckoNode<'ln> {
} }
fn children(self) -> GeckoChildrenIterator<'ln> { fn children(self) -> GeckoChildrenIterator<'ln> {
GeckoChildrenIterator { let maybe_iter = unsafe { Gecko_MaybeCreateStyleChildrenIterator(self.node) };
current: self.first_child(), if !maybe_iter.is_null() {
GeckoChildrenIterator::GeckoIterator(maybe_iter)
} else {
GeckoChildrenIterator::Current(self.first_child())
} }
} }
@ -341,16 +345,37 @@ impl<'ln> TNode for GeckoNode<'ln> {
unsafe fn set_dirty_on_viewport_size_changed(&self) {} unsafe fn set_dirty_on_viewport_size_changed(&self) {}
} }
pub struct GeckoChildrenIterator<'a> { // We generally iterate children by traversing the siblings of the first child
current: Option<GeckoNode<'a>>, // 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> { impl<'a> Iterator for GeckoChildrenIterator<'a> {
type Item = GeckoNode<'a>; type Item = GeckoNode<'a>;
fn next(&mut self) -> Option<GeckoNode<'a>> { fn next(&mut self) -> Option<GeckoNode<'a>> {
let node = self.current; match *self {
self.current = node.and_then(|node| node.next_sibling()); GeckoChildrenIterator::Current(curr) => {
node 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))
}
}
} }
} }