diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2016-11-14 13:29:41 -0800 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2016-11-15 10:51:14 -0800 |
commit | 0547a6b313072cde5870a61b97be10ee62ce65ad (patch) | |
tree | f3d268457497f488e32909ce9b68f1314cd93683 /components | |
parent | dda29283862481786805993b9dee7f8b37ad36b4 (diff) | |
download | servo-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.rs | 38 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/document.rs | 67 | ||||
-rw-r--r-- | components/script/layout_wrapper.rs | 8 | ||||
-rw-r--r-- | components/style/servo/restyle_damage.rs | 5 |
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>; |