aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/layout_wrapper.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/layout_wrapper.rs')
-rw-r--r--components/script/layout_wrapper.rs218
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) => {