diff options
Diffstat (limited to 'components/script/layout_wrapper.rs')
-rw-r--r-- | components/script/layout_wrapper.rs | 218 |
1 files changed, 104 insertions, 114 deletions
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 00c7ce1413c..a6d4815090f 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -34,9 +34,9 @@ use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId}; use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::LayoutJS; use dom::characterdata::LayoutCharacterDataHelpers; -use dom::document::{Document, LayoutDocumentHelpers}; +use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle}; use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers}; -use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY}; +use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS}; use dom::node::{LayoutNodeHelpers, Node}; use dom::text::Text; use gfx_traits::ByteIndex; @@ -46,30 +46,31 @@ use parking_lot::RwLock; use range::Range; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; -use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutElement, LayoutNode}; +use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use selectors::matching::ElementFlags; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_atoms::Atom; +use servo_url::ServoUrl; use std::fmt; +use std::fmt::Debug; use std::marker::PhantomData; use std::mem::transmute; use std::sync::Arc; use std::sync::atomic::Ordering; -use style::atomic_refcell::{AtomicRef, AtomicRefCell}; +use style::atomic_refcell::AtomicRefCell; use style::attr::AttrValue; use style::computed_values::display; use style::context::SharedStyleContext; use style::data::ElementData; -use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TDocument, TElement, TNode}; -use style::dom::{TRestyleDamage, UnsafeNode}; +use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TElement, TNode}; +use style::dom::UnsafeNode; use style::element_state::*; use style::properties::{ComputedValues, PropertyDeclarationBlock}; -use style::selector_impl::{NonTSPseudoClass, PseudoElement, RestyleDamage, ServoSelectorImpl, Snapshot}; -use style::selector_matching::ApplicableDeclarationBlock; +use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl}; use style::sink::Push; use style::str::is_whitespace; -use url::Url; +use style::stylist::ApplicableDeclarationBlock; #[derive(Copy, Clone)] pub struct ServoLayoutNode<'a> { @@ -80,6 +81,16 @@ pub struct ServoLayoutNode<'a> { chain: PhantomData<&'a ()>, } +impl<'ln> Debug for ServoLayoutNode<'ln> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(el) = self.as_element() { + el.fmt(f) + } else { + write!(f, "{:?} ({:#x})", self.type_id(), self.opaque().0) + } + } +} + impl<'a> PartialEq for ServoLayoutNode<'a> { #[inline] fn eq(&self, other: &ServoLayoutNode) -> bool { @@ -112,6 +123,10 @@ impl<'ln> ServoLayoutNode<'ln> { self.node.type_id_for_layout() } } + + pub fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> { + self.node.downcast().map(ServoLayoutDocument::from_layout_js) + } } impl<'ln> NodeInfo for ServoLayoutNode<'ln> { @@ -128,7 +143,6 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> { impl<'ln> TNode for ServoLayoutNode<'ln> { type ConcreteElement = ServoLayoutElement<'ln>; - type ConcreteDocument = ServoLayoutDocument<'ln>; type ConcreteChildrenIterator = ServoChildrenIterator<'ln>; fn to_unsafe(&self) -> UnsafeNode { @@ -161,14 +175,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { unsafe { self.get_jsmanaged().opaque() } } - fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<ServoLayoutElement<'ln>> { - if self.opaque() == reflow_root { - None - } else { - self.parent_node().and_then(|x| x.as_element()) - } - } - fn debug_id(self) -> usize { self.opaque().0 } @@ -177,10 +183,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { as_element(self.node) } - fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> { - self.node.downcast().map(ServoLayoutDocument::from_layout_js) - } - fn needs_dirty_on_viewport_size_changed(&self) -> bool { unsafe { self.node.get_flag(DIRTY_ON_VIEWPORT_SIZE_CHANGE) } } @@ -202,30 +204,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) } } - - 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)) - } - } } pub struct ServoChildrenIterator<'a> { @@ -260,14 +238,28 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { self.get_jsmanaged().take_style_and_layout_data() } - fn has_changed(&self) -> bool { - unsafe { self.node.get_flag(HAS_CHANGED) } + 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)) + } } - unsafe fn clear_dirty_bits(&self) { - self.node.set_flag(HAS_CHANGED, false); - self.node.set_flag(IS_DIRTY, false); - self.node.set_flag(HAS_DIRTY_DESCENDANTS, false); + fn next_sibling(&self) -> Option<ServoLayoutNode<'ln>> { + unsafe { + self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) + } } } @@ -298,14 +290,6 @@ impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> { } impl<'ln> ServoLayoutNode<'ln> { - pub fn is_dirty(&self) -> bool { - unsafe { self.node.get_flag(IS_DIRTY) } - } - - pub unsafe fn set_dirty(&self) { - self.node.set_flag(IS_DIRTY, true) - } - fn dump_indent(self, indent: u32) { let mut s = String::new(); for _ in 0..indent { @@ -336,9 +320,8 @@ impl<'ln> ServoLayoutNode<'ln> { } fn debug_str(self) -> String { - format!("{:?}: changed={} dirty={} dirty_descendants={}", - self.script_type_id(), self.has_changed(), - self.as_element().map_or(false, |el| el.deprecated_dirty_bit_is_set()), + format!("{:?}: dirty_descendants={}", + self.script_type_id(), self.as_element().map_or(false, |el| el.has_dirty_descendants())) } @@ -369,34 +352,29 @@ pub struct ServoLayoutDocument<'ld> { chain: PhantomData<&'ld ()>, } -impl<'ld> TDocument for ServoLayoutDocument<'ld> { - type ConcreteNode = ServoLayoutNode<'ld>; - type ConcreteElement = ServoLayoutElement<'ld>; - +impl<'ld> ServoLayoutDocument<'ld> { fn as_node(&self) -> ServoLayoutNode<'ld> { ServoLayoutNode::from_layout_js(self.document.upcast()) } - fn root_node(&self) -> Option<ServoLayoutNode<'ld>> { + pub fn root_node(&self) -> Option<ServoLayoutNode<'ld>> { self.as_node().children().find(ServoLayoutNode::is_element) } - fn drain_modified_elements(&self) -> Vec<(ServoLayoutElement<'ld>, Snapshot)> { - let elements = unsafe { self.document.drain_modified_elements() }; + pub fn drain_pending_restyles(&self) -> Vec<(ServoLayoutElement<'ld>, PendingRestyle)> { + let elements = unsafe { self.document.drain_pending_restyles() }; elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect() } - fn needs_paint_from_layout(&self) { + pub fn needs_paint_from_layout(&self) { unsafe { self.document.needs_paint_from_layout(); } } - fn will_paint(&self) { + pub fn will_paint(&self) { unsafe { self.document.will_paint(); } } -} -impl<'ld> ServoLayoutDocument<'ld> { - fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> { + pub fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, chain: PhantomData, @@ -417,7 +395,7 @@ impl<'le> fmt::Debug for ServoLayoutElement<'le> { if let &Some(ref id) = unsafe { &*self.element.id_attribute() } { try!(write!(f, " id={}", id)); } - write!(f, ">") + write!(f, "> ({:#x})", self.as_node().opaque().0) } } @@ -433,7 +411,6 @@ impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> { impl<'le> TElement for ServoLayoutElement<'le> { type ConcreteNode = ServoLayoutNode<'le>; - type ConcreteDocument = ServoLayoutDocument<'le>; fn as_node(&self) -> ServoLayoutNode<'le> { ServoLayoutNode::from_layout_js(self.element.upcast()) @@ -459,10 +436,6 @@ impl<'le> TElement for ServoLayoutElement<'le> { self.get_attr(namespace, attr).map_or(false, |x| x == val) } - fn set_restyle_damage(self, damage: RestyleDamage) { - self.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage; - } - #[inline] fn existing_style_for_restyle_damage<'a>(&'a self, current_cv: Option<&'a Arc<ComputedValues>>, @@ -471,10 +444,6 @@ impl<'le> TElement for ServoLayoutElement<'le> { current_cv } - fn deprecated_dirty_bit_is_set(&self) -> bool { - unsafe { self.as_node().node.get_flag(IS_DIRTY) } - } - fn has_dirty_descendants(&self) -> bool { unsafe { self.as_node().node.get_flag(HAS_DIRTY_DESCENDANTS) } } @@ -483,6 +452,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { self.as_node().node.set_flag(HAS_DIRTY_DESCENDANTS, true) } + unsafe fn unset_dirty_descendants(&self) { + self.as_node().node.set_flag(HAS_DIRTY_DESCENDANTS, false) + } + fn store_children_to_process(&self, n: isize) { let data = self.get_partial_layout_data().unwrap().borrow(); data.parallel.children_to_process.store(n, Ordering::Relaxed); @@ -495,10 +468,6 @@ impl<'le> TElement for ServoLayoutElement<'le> { old_value - 1 } - fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { - self.get_data().map(|d| d.borrow()) - } - fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { unsafe { self.get_style_and_layout_data().map(|d| { @@ -508,6 +477,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { }) } } + + fn skip_root_and_item_based_display_fixup(&self) -> bool { + false + } } impl<'le> PartialEq for ServoLayoutElement<'le> { @@ -536,6 +509,35 @@ impl<'le> ServoLayoutElement<'le> { self.get_style_and_layout_data().map(|d| &**d.ptr) } } + + pub unsafe fn note_dirty_descendant(&self) { + use ::selectors::Element; + + let mut current = Some(*self); + while let Some(el) = current { + // FIXME(bholley): Ideally we'd have the invariant that any element + // with has_dirty_descendants also has the bit set on all its ancestors. + // However, there are currently some corner-cases where we get that wrong. + // I have in-flight patches to fix all this stuff up, so we just always + // propagate this bit for now. + el.set_dirty_descendants(); + current = el.parent_element(); + } + + debug_assert!(self.dirty_descendants_bit_is_propagated()); + } + + fn dirty_descendants_bit_is_propagated(&self) -> bool { + use ::selectors::Element; + + let mut current = Some(*self); + while let Some(el) = current { + if !el.has_dirty_descendants() { return false; } + current = el.parent_element(); + } + + true + } } fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> { @@ -543,9 +545,9 @@ fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> { } impl<'le> ::selectors::MatchAttrGeneric for ServoLayoutElement<'le> { - type Impl = ServoSelectorImpl; + type Impl = SelectorImpl; - fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool + fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool where F: Fn(&str) -> bool { use ::selectors::Element; let name = if self.is_html_element_in_html_document() { @@ -712,7 +714,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct ServoThreadSafeLayoutNode<'ln> { /// The wrapped node. node: ServoLayoutNode<'ln>, @@ -813,7 +815,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { debug_assert!(self.is_text_node()); let parent = self.node.parent_node().unwrap().as_element().unwrap(); let parent_data = parent.get_data().unwrap().borrow(); - parent_data.current_styles().primary.clone() + parent_data.current_styles().primary.values.clone() } fn debug_id(self) -> usize { @@ -857,24 +859,14 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } fn restyle_damage(self) -> RestyleDamage { - if self.node.has_changed() { - RestyleDamage::rebuild_and_reflow() - } else if self.is_text_node() { - let parent = self.node.parent_node().unwrap().as_element().unwrap(); - let parent_data = parent.get_partial_layout_data().unwrap().borrow(); - parent_data.restyle_damage + let element = if self.is_text_node() { + self.node.parent_node().unwrap().as_element().unwrap() } else { - let el = self.as_element().unwrap().element; - let damage = el.get_partial_layout_data().unwrap().borrow().restyle_damage.clone(); - damage - } - } + self.node.as_element().unwrap() + }; - fn clear_restyle_damage(self) { - if let Some(el) = self.as_element() { - let mut data = el.element.get_partial_layout_data().unwrap().borrow_mut(); - data.restyle_damage = RestyleDamage::empty(); - } + let damage = element.borrow_data().unwrap().damage(); + damage } fn can_be_fragmented(&self) -> bool { @@ -895,7 +887,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { }) } - fn image_url(&self) -> Option<Url> { + fn image_url(&self) -> Option<ServoUrl> { let this = unsafe { self.get_jsmanaged() }; this.image_url() } @@ -1069,8 +1061,6 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> { } } -impl<'le> LayoutElement for ServoLayoutElement<'le> {} - /// This implementation of `::selectors::Element` is used for implementing lazy /// pseudo-elements. /// @@ -1084,9 +1074,9 @@ impl<'le> LayoutElement for ServoLayoutElement<'le> {} /// Note that the element implementation is needed only for selector matching, /// not for inheritance (styles are inherited appropiately). impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> { - type Impl = ServoSelectorImpl; + type Impl = SelectorImpl; - fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool + fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool where F: Fn(&str) -> bool { match attr.namespace { NamespaceConstraint::Specific(ref ns) => { |