aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/document.rs
diff options
context:
space:
mode:
authorAnthony Ramine <nox@nox.paris>2020-04-27 17:54:06 +0200
committerAnthony Ramine <nox@nox.paris>2020-05-19 16:26:36 +0200
commit036f123c4ee61f72fd123cc0c624df9d604cbb93 (patch)
treed83f5dcae9d96f40d3b0174ba91d0ca0046b5f80 /components/script/dom/document.rs
parent518c0660c6eee711252057bd73f75cd35f3d3215 (diff)
downloadservo-036f123c4ee61f72fd123cc0c624df9d604cbb93.tar.gz
servo-036f123c4ee61f72fd123cc0c624df9d604cbb93.zip
Implement concept of dirty root
Diffstat (limited to 'components/script/dom/document.rs')
-rw-r--r--components/script/dom/document.rs119
1 files changed, 117 insertions, 2 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 4577835d24e..efb3277f1cf 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -387,6 +387,8 @@ pub struct Document {
animation_timeline: DomRefCell<AnimationTimeline>,
/// Animations for this Document
animations: DomRefCell<Animations>,
+ /// The nearest inclusive ancestors to all the nodes that require a restyle.
+ dirty_root: MutNullableDom<Element>,
}
#[derive(JSTraceable, MallocSizeOf)]
@@ -446,6 +448,112 @@ enum ElementLookupResult {
#[allow(non_snake_case)]
impl Document {
+ pub fn note_node_with_dirty_descendants(&self, node: &Node) {
+ debug_assert!(*node.owner_doc() == *self);
+ if !node.is_connected() {
+ return;
+ }
+
+ let parent = match node.inclusive_ancestors(ShadowIncluding::Yes).nth(1) {
+ Some(parent) => parent,
+ None => {
+ // There is no parent so this is the Document node, so we
+ // behave as if we were called with the document element.
+ let document_element = match self.GetDocumentElement() {
+ Some(element) => element,
+ None => return,
+ };
+ if let Some(dirty_root) = self.dirty_root.get() {
+ // There was an existing dirty root so we mark its
+ // ancestors as dirty until the document element.
+ for ancestor in dirty_root
+ .upcast::<Node>()
+ .inclusive_ancestors(ShadowIncluding::Yes)
+ {
+ if ancestor.is::<Element>() {
+ ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
+ }
+ }
+ }
+ self.dirty_root.set(Some(&document_element));
+ return;
+ },
+ };
+
+ if parent.is::<Element>() {
+ if !parent.is_styled() {
+ return;
+ }
+
+ if parent.is_display_none() {
+ return;
+ }
+ }
+
+ let element_parent: DomRoot<Element>;
+ let element = match node.downcast::<Element>() {
+ Some(element) => element,
+ None => {
+ // Current node is not an element, it's probably a text node,
+ // we try to get its element parent.
+ match DomRoot::downcast::<Element>(parent) {
+ Some(parent) => {
+ element_parent = parent;
+ &element_parent
+ },
+ None => {
+ // Parent is not an element so it must be a document,
+ // and this is not an element either, so there is
+ // nothing to do.
+ return;
+ },
+ }
+ },
+ };
+
+ let dirty_root = match self.dirty_root.get() {
+ None => {
+ element
+ .upcast::<Node>()
+ .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
+ self.dirty_root.set(Some(element));
+ return;
+ },
+ Some(root) => root,
+ };
+
+ for ancestor in element
+ .upcast::<Node>()
+ .inclusive_ancestors(ShadowIncluding::Yes)
+ {
+ if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) {
+ return;
+ }
+ if ancestor.is::<Element>() {
+ ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
+ }
+ }
+
+ let new_dirty_root = element
+ .upcast::<Node>()
+ .common_ancestor(dirty_root.upcast(), ShadowIncluding::Yes);
+
+ let mut has_dirty_descendants = true;
+ for ancestor in dirty_root
+ .upcast::<Node>()
+ .inclusive_ancestors(ShadowIncluding::Yes)
+ {
+ ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants);
+ has_dirty_descendants &= *ancestor != *new_dirty_root;
+ }
+ self.dirty_root
+ .set(Some(new_dirty_root.downcast::<Element>().unwrap()));
+ }
+
+ pub fn take_dirty_root(&self) -> Option<DomRoot<Element>> {
+ self.dirty_root.take()
+ }
+
#[inline]
pub fn loader(&self) -> Ref<DocumentLoader> {
self.loader.borrow()
@@ -967,8 +1075,14 @@ impl Document {
}
pub fn dirty_all_nodes(&self) {
- let root = self.upcast::<Node>();
- for node in root.traverse_preorder(ShadowIncluding::Yes) {
+ let root = match self.GetDocumentElement() {
+ Some(root) => root,
+ None => return,
+ };
+ for node in root
+ .upcast::<Node>()
+ .traverse_preorder(ShadowIncluding::Yes)
+ {
node.dirty(NodeDamage::OtherNodeDamage)
}
}
@@ -2917,6 +3031,7 @@ impl Document {
DomRefCell::new(AnimationTimeline::new())
},
animations: DomRefCell::new(Animations::new()),
+ dirty_root: Default::default(),
}
}