aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2016-11-14 13:29:41 -0800
committerBobby Holley <bobbyholley@gmail.com>2016-11-15 10:51:14 -0800
commit0547a6b313072cde5870a61b97be10ee62ce65ad (patch)
treef3d268457497f488e32909ce9b68f1314cd93683 /components
parentdda29283862481786805993b9dee7f8b37ad36b4 (diff)
downloadservo-0547a6b313072cde5870a61b97be10ee62ce65ad.tar.gz
servo-0547a6b313072cde5870a61b97be10ee62ce65ad.zip
Expand the role of modified_elements to include explicit restyle hints and damage.
This will take the place of setting IS_DIRTY and HAS_CHANGED.
Diffstat (limited to 'components')
-rw-r--r--components/layout_thread/lib.rs38
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/document.rs67
-rw-r--r--components/script/layout_wrapper.rs8
-rw-r--r--components/style/servo/restyle_damage.rs5
5 files changed, 93 insertions, 27 deletions
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 09061a0932f..a1a8825791f 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -1117,11 +1117,41 @@ 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 {
+ if el.get_data().is_none() {
+ // If we haven't styled this node yet, we can ignore the 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;
+ }
+
+ // Propagate the descendant bit up the ancestors.
+ if !hint.is_empty() || !restyle.damage.is_empty() {
+ let curr = el;
+ while let Some(curr) = curr.parent_element() {
+ if curr.has_dirty_descendants() { break }
+ unsafe { curr.set_dirty_descendants(); }
+ }
+ }
}
}
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 5b1f4cfe404..829b1d98192 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -125,7 +125,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;
@@ -158,6 +159,29 @@ struct StylesheetInDocument {
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 {
@@ -234,9 +258,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>,
@@ -410,7 +434,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,
@@ -1708,7 +1732,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);
}
@@ -1722,8 +1746,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
}
@@ -1830,7 +1854,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()),
@@ -1966,23 +1990,28 @@ impl Document {
self.id_map.borrow().get(&id).map(|ref elements| Root::from_ref(&*(*elements)[0]))
}
+ 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))
+ }
+
+ 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/layout_wrapper.rs b/components/script/layout_wrapper.rs
index fb31965d45d..3d61a810111 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -34,7 +34,7 @@ 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::{LayoutNodeHelpers, Node};
@@ -65,7 +65,7 @@ use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthe
use style::dom::{TRestyleDamage, 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;
@@ -377,8 +377,8 @@ impl<'ld> ServoLayoutDocument<'ld> {
self.as_node().children().find(ServoLayoutNode::is_element)
}
- pub 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()
}
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>;