aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/traversal.rs19
-rw-r--r--components/layout_thread/lib.rs46
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/document.rs69
-rw-r--r--components/script/dom/element.rs17
-rw-r--r--components/script/dom/node.rs51
-rw-r--r--components/script/layout_wrapper.rs87
-rw-r--r--components/script_layout_interface/lib.rs6
-rw-r--r--components/script_layout_interface/wrapper_traits.rs8
-rw-r--r--components/style/dom.rs24
-rw-r--r--components/style/gecko/wrapper.rs41
-rw-r--r--components/style/servo/restyle_damage.rs5
12 files changed, 192 insertions, 183 deletions
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index b054568d5d5..849e7b2087a 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -10,7 +10,7 @@ use display_list_builder::DisplayListBuildState;
use flow::{self, PreorderFlowTraversal};
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
use gfx::display_list::OpaqueNode;
-use script_layout_interface::wrapper_traits::{LayoutElement, LayoutNode, ThreadSafeLayoutNode};
+use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
use std::mem;
use style::atomic_refcell::AtomicRefCell;
use style::context::{LocalStyleContext, SharedStyleContext, StyleContext};
@@ -32,7 +32,7 @@ pub struct RecalcStyleAndConstructFlows<'lc> {
#[allow(unsafe_code)]
impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
where N: LayoutNode + TNode,
- N::ConcreteElement: LayoutElement
+ N::ConcreteElement: TElement
{
type SharedContext = SharedLayoutContext;
@@ -118,16 +118,13 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
return false;
}
- // If this node has been marked as damaged in some way, we need to
- // traverse it for layout.
- if child.has_changed() {
- return true;
- }
-
match child.as_element() {
- Some(el) => el.styling_mode() != StylingMode::Stop,
- // Aside from the has_changed case above, we want to traverse non-element children
- // in two additional cases:
+ // Elements should be traversed if they need styling or flow construction.
+ Some(el) => el.styling_mode() != StylingMode::Stop ||
+ el.as_node().to_threadsafe().restyle_damage() != RestyleDamage::empty(),
+
+ // Text nodes never need styling. However, there are two cases they may need
+ // flow construction:
// (1) They child doesn't yet have layout data (preorder traversal initializes it).
// (2) The parent element has restyle damage (so the text flow also needs fixup).
None => child.get_raw_data().is_none() ||
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index fbb7d2fb724..8aa51683f1a 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -104,7 +104,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{Receiver, Sender, channel};
use style::animation::Animation;
use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext};
-use style::dom::{TDocument, TElement, TNode};
+use style::dom::{TElement, TNode};
use style::error_reporting::{ParseErrorReporter, StdoutErrorReporter};
use style::logical_geometry::LogicalPoint;
use style::media_queries::{Device, MediaType};
@@ -1063,11 +1063,8 @@ impl LayoutThread {
// NB: The dirty bit is propagated down the tree.
unsafe { node.set_dirty(); }
- let mut current = node.parent_node().and_then(|n| n.as_element());
- while let Some(el) = current {
- if el.has_dirty_descendants() { break; }
- unsafe { el.set_dirty_descendants(); }
- current = el.parent_element();
+ if let Some(p) = node.parent_node().and_then(|n| n.as_element()) {
+ unsafe { p.note_dirty_descendant() };
}
next = iter.next_skipping_children();
@@ -1096,11 +1093,40 @@ impl LayoutThread {
}
}
- let modified_elements = document.drain_modified_elements();
+ let restyles = document.drain_pending_restyles();
if !needs_dirtying {
- for (el, snapshot) in modified_elements {
- let hint = rw_data.stylist.compute_restyle_hint(&el, &snapshot, el.get_state());
- el.note_restyle_hint::<RecalcStyleAndConstructFlows>(hint);
+ for (el, restyle) in restyles {
+ // Propagate the descendant bit up the ancestors. Do this before
+ // the restyle calculation so that we can also do it for new
+ // unstyled nodes, which the descendants bit helps us find.
+ if let Some(parent) = el.parent_element() {
+ unsafe { parent.note_dirty_descendant() };
+ }
+
+ if el.get_data().is_none() {
+ // If we haven't styled this node yet, we don't need to track
+ // a restyle.
+ continue;
+ }
+
+ // Start with the explicit hint, if any.
+ let mut hint = restyle.hint;
+
+ // Expand any snapshots.
+ if let Some(s) = restyle.snapshot {
+ hint |= rw_data.stylist.compute_restyle_hint(&el, &s, el.get_state());
+ }
+
+ // Apply the cumulative hint.
+ if !hint.is_empty() {
+ el.note_restyle_hint::<RecalcStyleAndConstructFlows>(hint);
+ }
+
+ // Apply explicit damage, if any.
+ if !restyle.damage.is_empty() {
+ let mut d = el.mutate_layout_data().unwrap();
+ d.base.restyle_damage |= restyle.damage;
+ }
}
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index b38d5d4ec91..661ecadde9d 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -41,6 +41,7 @@ use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::str::{DOMString, USVString};
use dom::bindings::utils::WindowProxyHandler;
+use dom::document::PendingRestyle;
use encoding::types::EncodingRef;
use euclid::{Matrix2D, Matrix4D, Point2D};
use euclid::length::Length as EuclidLength;
@@ -348,6 +349,7 @@ no_jsmanaged_fields!(Mime);
no_jsmanaged_fields!(AttrIdentifier);
no_jsmanaged_fields!(AttrValue);
no_jsmanaged_fields!(Snapshot);
+no_jsmanaged_fields!(PendingRestyle);
no_jsmanaged_fields!(HttpsState);
no_jsmanaged_fields!(Request);
no_jsmanaged_fields!(RequestInit);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 7326a207c31..d13d94f8099 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -122,7 +122,8 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use style::attr::AttrValue;
use style::context::ReflowGoal;
-use style::selector_impl::Snapshot;
+use style::restyle_hints::RestyleHint;
+use style::selector_impl::{RestyleDamage, Snapshot};
use style::str::{split_html_space_chars, str_join};
use style::stylesheets::Stylesheet;
use time;
@@ -155,6 +156,29 @@ pub struct StylesheetInDocument {
pub stylesheet: Arc<Stylesheet>,
}
+#[derive(Debug, HeapSizeOf)]
+pub struct PendingRestyle {
+ /// If this element had a state or attribute change since the last restyle, track
+ /// the original condition of the element.
+ pub snapshot: Option<Snapshot>,
+
+ /// Any explicit restyles hints that have been accumulated for this element.
+ pub hint: RestyleHint,
+
+ /// Any explicit restyles damage that have been accumulated for this element.
+ pub damage: RestyleDamage,
+}
+
+impl PendingRestyle {
+ pub fn new() -> Self {
+ PendingRestyle {
+ snapshot: None,
+ hint: RestyleHint::empty(),
+ damage: RestyleDamage::empty(),
+ }
+ }
+}
+
// https://dom.spec.whatwg.org/#document
#[dom_struct]
pub struct Document {
@@ -232,9 +256,9 @@ pub struct Document {
/// This field is set to the document itself for inert documents.
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
appropriate_template_contents_owner_document: MutNullableHeap<JS<Document>>,
- /// For each element that has had a state or attribute change since the last restyle,
- /// track the original condition of the element.
- modified_elements: DOMRefCell<HashMap<JS<Element>, Snapshot>>,
+ /// Information on elements needing restyle to ship over to the layout thread when the
+ /// time comes.
+ pending_restyles: DOMRefCell<HashMap<JS<Element>, PendingRestyle>>,
/// This flag will be true if layout suppressed a reflow attempt that was
/// needed in order for the page to be painted.
needs_paint: Cell<bool>,
@@ -408,7 +432,7 @@ impl Document {
Some(root) => {
root.upcast::<Node>().is_dirty() ||
root.upcast::<Node>().has_dirty_descendants() ||
- !self.modified_elements.borrow().is_empty() ||
+ !self.pending_restyles.borrow().is_empty() ||
self.needs_paint()
}
None => false,
@@ -451,7 +475,7 @@ impl Document {
}
pub fn content_and_heritage_changed(&self, node: &Node, damage: NodeDamage) {
- node.force_dirty_ancestors(damage);
+ node.dirty(damage);
}
/// Reflows and disarms the timer if the reflow timer has expired.
@@ -1706,7 +1730,7 @@ pub enum DocumentSource {
#[allow(unsafe_code)]
pub trait LayoutDocumentHelpers {
unsafe fn is_html_document_for_layout(&self) -> bool;
- unsafe fn drain_modified_elements(&self) -> Vec<(LayoutJS<Element>, Snapshot)>;
+ unsafe fn drain_pending_restyles(&self) -> Vec<(LayoutJS<Element>, PendingRestyle)>;
unsafe fn needs_paint_from_layout(&self);
unsafe fn will_paint(&self);
}
@@ -1720,8 +1744,8 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
#[inline]
#[allow(unrooted_must_root)]
- unsafe fn drain_modified_elements(&self) -> Vec<(LayoutJS<Element>, Snapshot)> {
- let mut elements = (*self.unsafe_get()).modified_elements.borrow_mut_for_layout();
+ unsafe fn drain_pending_restyles(&self) -> Vec<(LayoutJS<Element>, PendingRestyle)> {
+ let mut elements = (*self.unsafe_get()).pending_restyles.borrow_mut_for_layout();
let result = elements.drain().map(|(k, v)| (k.to_layout(), v)).collect();
result
}
@@ -1829,7 +1853,7 @@ impl Document {
reflow_timeout: Cell::new(None),
base_element: Default::default(),
appropriate_template_contents_owner_document: Default::default(),
- modified_elements: DOMRefCell::new(HashMap::new()),
+ pending_restyles: DOMRefCell::new(HashMap::new()),
needs_paint: Cell::new(false),
active_touch_points: DOMRefCell::new(Vec::new()),
dom_loading: Cell::new(Default::default()),
@@ -1967,23 +1991,28 @@ impl Document {
self.id_map.borrow().get(&id).map(|ref elements| Root::from_ref(&*(*elements)[0]))
}
+ pub fn ensure_pending_restyle(&self, el: &Element) -> RefMut<PendingRestyle> {
+ let map = self.pending_restyles.borrow_mut();
+ RefMut::map(map, |m| m.entry(JS::from_ref(el)).or_insert_with(PendingRestyle::new))
+ }
+
+ pub fn ensure_snapshot(&self, el: &Element) -> RefMut<Snapshot> {
+ let mut entry = self.ensure_pending_restyle(el);
+ if entry.snapshot.is_none() {
+ entry.snapshot = Some(Snapshot::new(el.html_element_in_html_document()));
+ }
+ RefMut::map(entry, |e| e.snapshot.as_mut().unwrap())
+ }
+
pub fn element_state_will_change(&self, el: &Element) {
- let mut map = self.modified_elements.borrow_mut();
- let snapshot = map.entry(JS::from_ref(el))
- .or_insert_with(|| {
- Snapshot::new(el.html_element_in_html_document())
- });
+ let mut snapshot = self.ensure_snapshot(el);
if snapshot.state.is_none() {
snapshot.state = Some(el.state());
}
}
pub fn element_attr_will_change(&self, el: &Element) {
- let mut map = self.modified_elements.borrow_mut();
- let mut snapshot = map.entry(JS::from_ref(el))
- .or_insert_with(|| {
- Snapshot::new(el.html_element_in_html_document())
- });
+ let mut snapshot = self.ensure_snapshot(el);
if snapshot.attrs.is_none() {
let attrs = el.attrs()
.iter()
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index ac65c01e24c..b348220c0fb 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -84,13 +84,15 @@ use std::fmt;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
+use style::dom::TRestyleDamage;
use style::element_state::*;
use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
use style::parser::ParserContextExtraData;
use style::properties::{DeclaredValue, Importance};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
use style::properties::longhands::{background_image, border_spacing, font_family, font_size, overflow_x};
-use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl};
+use style::restyle_hints::RESTYLE_SELF;
+use style::selector_impl::{NonTSPseudoClass, RestyleDamage, ServoSelectorImpl};
use style::selector_matching::ApplicableDeclarationBlock;
use style::sink::Push;
use style::values::CSSFloat;
@@ -201,6 +203,19 @@ impl Element {
ElementBinding::Wrap)
}
+ pub fn restyle(&self, damage: NodeDamage) {
+ let doc = self.node.owner_doc();
+ let mut restyle = doc.ensure_pending_restyle(self);
+
+ // FIXME(bholley): I think we should probably only do this for
+ // NodeStyleDamaged, but I'm preserving existing behavior.
+ restyle.hint |= RESTYLE_SELF;
+
+ if damage == NodeDamage::OtherNodeDamage {
+ restyle.damage = RestyleDamage::rebuild_and_reflow();
+ }
+ }
+
// https://drafts.csswg.org/cssom-view/#css-layout-box
// Elements that have a computed value of the display property
// that is table-column or table-column-group
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index f6389b57efe..ea00f62f43d 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -149,8 +149,6 @@ bitflags! {
pub flags NodeFlags: u8 {
#[doc = "Specifies whether this node is in a document."]
const IS_IN_DOC = 0x01,
- #[doc = "Specifies whether this node _must_ be reflowed regardless of style differences."]
- const HAS_CHANGED = 0x02,
#[doc = "Specifies whether this node needs style recalc on next reflow."]
const IS_DIRTY = 0x04,
#[doc = "Specifies whether this node has descendants (inclusive of itself) which \
@@ -175,7 +173,7 @@ bitflags! {
impl NodeFlags {
pub fn new() -> NodeFlags {
- HAS_CHANGED | IS_DIRTY | HAS_DIRTY_DESCENDANTS
+ IS_DIRTY
}
}
@@ -251,6 +249,8 @@ impl Node {
let parent_in_doc = self.is_in_doc();
for node in new_child.traverse_preorder() {
node.set_flag(IS_IN_DOC, parent_in_doc);
+ // Out-of-document elements never have the descendants flag set.
+ debug_assert!(!node.get_flag(HAS_DIRTY_DESCENDANTS));
vtable_for(&&*node).bind_to_tree(parent_in_doc);
}
let document = new_child.owner_doc();
@@ -289,7 +289,8 @@ impl Node {
self.children_count.set(self.children_count.get() - 1);
for node in child.traverse_preorder() {
- node.set_flag(IS_IN_DOC, false);
+ // Out-of-document elements never have the descendants flag set.
+ node.set_flag(IS_IN_DOC | HAS_DIRTY_DESCENDANTS, false);
vtable_for(&&*node).unbind_from_tree(&context);
node.style_and_layout_data.get().map(|d| node.dispose(d));
}
@@ -428,14 +429,6 @@ impl Node {
self.flags.set(flags);
}
- pub fn has_changed(&self) -> bool {
- self.get_flag(HAS_CHANGED)
- }
-
- pub fn set_has_changed(&self, state: bool) {
- self.set_flag(HAS_CHANGED, state)
- }
-
pub fn is_dirty(&self) -> bool {
self.get_flag(IS_DIRTY)
}
@@ -452,10 +445,6 @@ impl Node {
self.set_flag(HAS_DIRTY_DESCENDANTS, state)
}
- pub fn force_dirty_ancestors(&self, damage: NodeDamage) {
- self.dirty_impl(damage, true)
- }
-
pub fn rev_version(&self) {
// The new version counter is 1 plus the max of the node's current version counter,
// its descendants version, and the document's version. Normally, this will just be
@@ -470,30 +459,18 @@ impl Node {
}
pub fn dirty(&self, damage: NodeDamage) {
- self.dirty_impl(damage, false)
- }
-
- pub fn dirty_impl(&self, damage: NodeDamage, force_ancestors: bool) {
- // 0. Set version counter
self.rev_version();
-
- // 1. Dirty self.
- match damage {
- NodeDamage::NodeStyleDamaged => {}
- NodeDamage::OtherNodeDamage => self.set_has_changed(true),
+ if !self.is_in_doc() {
+ return;
}
- if self.is_dirty() && !force_ancestors {
- return
- }
-
- self.set_flag(IS_DIRTY, true);
-
- // 4. Dirty ancestors.
- for ancestor in self.ancestors() {
- if !force_ancestors && ancestor.has_dirty_descendants() { break }
- ancestor.set_has_dirty_descendants(true);
- }
+ match self.type_id() {
+ NodeTypeId::CharacterData(CharacterDataTypeId::Text) =>
+ self.parent_node.get().unwrap().downcast::<Element>().unwrap().restyle(damage),
+ NodeTypeId::Element(_) =>
+ self.downcast::<Element>().unwrap().restyle(damage),
+ _ => {},
+ };
}
/// The maximum version number of this node's descendants, including itself
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index 00c7ce1413c..5dd5e5082ce 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, IS_DIRTY};
use dom::node::{LayoutNodeHelpers, Node};
use dom::text::Text;
use gfx_traits::ByteIndex;
@@ -46,7 +46,7 @@ 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};
@@ -61,11 +61,11 @@ 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_impl::{NonTSPseudoClass, PseudoElement, RestyleDamage, ServoSelectorImpl};
use style::selector_matching::ApplicableDeclarationBlock;
use style::sink::Push;
use style::str::is_whitespace;
@@ -112,6 +112,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 +132,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 {
@@ -177,10 +180,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) }
}
@@ -260,12 +259,7 @@ 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) }
- }
-
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);
}
@@ -336,8 +330,8 @@ impl<'ln> ServoLayoutNode<'ln> {
}
fn debug_str(self) -> String {
- format!("{:?}: changed={} dirty={} dirty_descendants={}",
- self.script_type_id(), self.has_changed(),
+ format!("{:?}: dirty={} dirty_descendants={}",
+ self.script_type_id(),
self.as_element().map_or(false, |el| el.deprecated_dirty_bit_is_set()),
self.as_element().map_or(false, |el| el.has_dirty_descendants()))
}
@@ -369,34 +363,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,
@@ -433,7 +422,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())
@@ -460,7 +448,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
fn set_restyle_damage(self, damage: RestyleDamage) {
- self.get_partial_layout_data().unwrap().borrow_mut().restyle_damage = damage;
+ self.get_partial_layout_data().unwrap().borrow_mut().restyle_damage |= damage;
}
#[inline]
@@ -536,6 +524,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>> {
@@ -857,9 +874,7 @@ 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() {
+ 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
@@ -1069,8 +1084,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.
///
diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs
index 284f6f33498..ff86579631c 100644
--- a/components/script_layout_interface/lib.rs
+++ b/components/script_layout_interface/lib.rs
@@ -51,6 +51,7 @@ use libc::c_void;
use std::sync::atomic::AtomicIsize;
use style::atomic_refcell::AtomicRefCell;
use style::data::ElementData;
+use style::dom::TRestyleDamage;
use style::selector_impl::RestyleDamage;
pub struct PartialPersistentLayoutData {
@@ -71,7 +72,10 @@ impl PartialPersistentLayoutData {
pub fn new() -> Self {
PartialPersistentLayoutData {
style_data: ElementData::new(),
- restyle_damage: RestyleDamage::empty(),
+ // FIXME(bholley): This is needed for now to make sure we do frame
+ // construction after initial styling. This will go away shortly when
+ // we move restyle damage into the style system.
+ restyle_damage: RestyleDamage::rebuild_and_reflow(),
parallel: DomParallelInfo::new(),
}
}
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index 9123c0c1f45..283e8def80a 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -18,7 +18,7 @@ use style::atomic_refcell::AtomicRefCell;
use style::computed_values::display;
use style::context::SharedStyleContext;
use style::data::ElementData;
-use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TElement, TNode};
+use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
use style::dom::OpaqueNode;
use style::properties::ServoComputedValues;
use style::selector_impl::{PseudoElement, PseudoElementCascadeType, RestyleDamage, ServoSelectorImpl};
@@ -86,8 +86,6 @@ pub trait LayoutNode: GetLayoutData + TNode {
unsafe fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData);
unsafe fn take_style_and_layout_data(&self) -> OpaqueStyleAndLayoutData;
- fn has_changed(&self) -> bool;
-
unsafe fn clear_dirty_bits(&self);
fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> {
@@ -274,9 +272,6 @@ pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
}
-pub trait LayoutElement: Clone + Copy + Sized + Debug + GetLayoutData + TElement {
-}
-
pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
::selectors::Element<Impl=ServoSelectorImpl> +
GetLayoutData +
@@ -435,5 +430,4 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
.get(&other.style_pseudo_element()).unwrap().0.clone(),
}
}
-
}
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 388a7310ab0..7b15e820edf 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -14,7 +14,7 @@ use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock};
use properties::longhands::display::computed_value as display;
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
-use selector_impl::{ElementExt, PseudoElement, RestyleDamage, Snapshot};
+use selector_impl::{ElementExt, PseudoElement, RestyleDamage};
use selector_matching::ApplicableDeclarationBlock;
use sink::Push;
use std::fmt::Debug;
@@ -105,8 +105,7 @@ impl<T, I> Iterator for LayoutIterator<T> where T: Iterator<Item=I>, I: NodeInfo
}
pub trait TNode : Sized + Copy + Clone + NodeInfo {
- type ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
- type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
+ type ConcreteElement: TElement<ConcreteNode = Self>;
type ConcreteChildrenIterator: Iterator<Item = Self>;
fn to_unsafe(&self) -> UnsafeNode;
@@ -130,8 +129,6 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
fn as_element(&self) -> Option<Self::ConcreteElement>;
- fn as_document(&self) -> Option<Self::ConcreteDocument>;
-
fn needs_dirty_on_viewport_size_changed(&self) -> bool;
unsafe fn set_dirty_on_viewport_size_changed(&self);
@@ -151,28 +148,13 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo {
fn next_sibling(&self) -> Option<Self>;
}
-pub trait TDocument : Sized + Copy + Clone {
- type ConcreteNode: TNode<ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
- type ConcreteElement: TElement<ConcreteNode = Self::ConcreteNode, ConcreteDocument = Self>;
-
- fn as_node(&self) -> Self::ConcreteNode;
-
- fn root_node(&self) -> Option<Self::ConcreteNode>;
-
- fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, Snapshot)>;
-
- fn needs_paint_from_layout(&self);
- fn will_paint(&self);
-}
-
pub trait PresentationalHintsSynthetizer {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: Push<ApplicableDeclarationBlock>;
}
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
- type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
- type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
+ type ConcreteNode: TNode<ConcreteElement = Self>;
fn as_node(&self) -> Self::ConcreteNode;
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index cc40f22ae97..4f36b722626 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -7,22 +7,20 @@
use atomic_refcell::{AtomicRef, AtomicRefCell};
use data::ElementData;
-use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, UnsafeNode};
+use dom::{LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::restyle_damage::GeckoRestyleDamage;
use gecko::selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PseudoElement};
-use gecko::snapshot::GeckoElementSnapshot;
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
-use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
-use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
+use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement};
use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
-use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
+use gecko_bindings::bindings::{RawGeckoElement, RawGeckoNode};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::bindings::Gecko_SetNodeFlags;
@@ -78,7 +76,6 @@ impl<'ln> NodeInfo for GeckoNode<'ln> {
}
impl<'ln> TNode for GeckoNode<'ln> {
- type ConcreteDocument = GeckoDocument<'ln>;
type ConcreteElement = GeckoElement<'ln>;
type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;
@@ -137,10 +134,6 @@ impl<'ln> TNode for GeckoNode<'ln> {
}
}
- fn as_document(&self) -> Option<GeckoDocument<'ln>> {
- unimplemented!()
- }
-
fn can_be_fragmented(&self) -> bool {
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
// Maybe this isn’t useful for Gecko?
@@ -219,33 +212,6 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
}
#[derive(Clone, Copy)]
-pub struct GeckoDocument<'ld>(pub &'ld RawGeckoDocument);
-
-impl<'ld> TDocument for GeckoDocument<'ld> {
- type ConcreteNode = GeckoNode<'ld>;
- type ConcreteElement = GeckoElement<'ld>;
-
- fn as_node(&self) -> GeckoNode<'ld> {
- unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
- }
-
- fn root_node(&self) -> Option<GeckoNode<'ld>> {
- unsafe {
- Gecko_GetDocumentElement(self.0).map(|el| GeckoElement(el).as_node())
- }
- }
-
- fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, GeckoElementSnapshot)> {
- unimplemented!()
- /*
- let elements = unsafe { self.0.drain_modified_elements() };
- elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()*/
- }
- fn will_paint(&self) { unimplemented!() }
- fn needs_paint_from_layout(&self) { unimplemented!() }
-}
-
-#[derive(Clone, Copy)]
pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
impl<'le> fmt::Debug for GeckoElement<'le> {
@@ -322,7 +288,6 @@ lazy_static! {
impl<'le> TElement for GeckoElement<'le> {
type ConcreteNode = GeckoNode<'le>;
- type ConcreteDocument = GeckoDocument<'le>;
fn as_node(&self) -> Self::ConcreteNode {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
diff --git a/components/style/servo/restyle_damage.rs b/components/style/servo/restyle_damage.rs
index 616c3506173..6cabb7eb485 100644
--- a/components/style/servo/restyle_damage.rs
+++ b/components/style/servo/restyle_damage.rs
@@ -4,6 +4,7 @@
use computed_values::display;
use dom::TRestyleDamage;
+use heapsize::HeapSizeOf;
use properties::ServoComputedValues;
use std::fmt;
use std::sync::Arc;
@@ -48,6 +49,10 @@ bitflags! {
}
}
+impl HeapSizeOf for ServoRestyleDamage {
+ fn heap_size_of_children(&self) -> usize { 0 }
+}
+
impl TRestyleDamage for ServoRestyleDamage {
/// For Servo the style source is always the computed values.
type PreExistingComputedValues = Arc<ServoComputedValues>;