mirror of
https://github.com/servo/servo.git
synced 2025-06-14 11:24:33 +00:00
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.
This commit is contained in:
parent
dda2928386
commit
0547a6b313
5 changed files with 93 additions and 27 deletions
|
@ -1117,11 +1117,41 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let modified_elements = document.drain_modified_elements();
|
let restyles = document.drain_pending_restyles();
|
||||||
if !needs_dirtying {
|
if !needs_dirtying {
|
||||||
for (el, snapshot) in modified_elements {
|
for (el, restyle) in restyles {
|
||||||
let hint = rw_data.stylist.compute_restyle_hint(&el, &snapshot, el.get_state());
|
if el.get_data().is_none() {
|
||||||
el.note_restyle_hint::<RecalcStyleAndConstructFlows>(hint);
|
// 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(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ use dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||||
use dom::bindings::reflector::{Reflectable, Reflector};
|
use dom::bindings::reflector::{Reflectable, Reflector};
|
||||||
use dom::bindings::str::{DOMString, USVString};
|
use dom::bindings::str::{DOMString, USVString};
|
||||||
use dom::bindings::utils::WindowProxyHandler;
|
use dom::bindings::utils::WindowProxyHandler;
|
||||||
|
use dom::document::PendingRestyle;
|
||||||
use encoding::types::EncodingRef;
|
use encoding::types::EncodingRef;
|
||||||
use euclid::{Matrix2D, Matrix4D, Point2D};
|
use euclid::{Matrix2D, Matrix4D, Point2D};
|
||||||
use euclid::length::Length as EuclidLength;
|
use euclid::length::Length as EuclidLength;
|
||||||
|
@ -348,6 +349,7 @@ no_jsmanaged_fields!(Mime);
|
||||||
no_jsmanaged_fields!(AttrIdentifier);
|
no_jsmanaged_fields!(AttrIdentifier);
|
||||||
no_jsmanaged_fields!(AttrValue);
|
no_jsmanaged_fields!(AttrValue);
|
||||||
no_jsmanaged_fields!(Snapshot);
|
no_jsmanaged_fields!(Snapshot);
|
||||||
|
no_jsmanaged_fields!(PendingRestyle);
|
||||||
no_jsmanaged_fields!(HttpsState);
|
no_jsmanaged_fields!(HttpsState);
|
||||||
no_jsmanaged_fields!(Request);
|
no_jsmanaged_fields!(Request);
|
||||||
no_jsmanaged_fields!(RequestInit);
|
no_jsmanaged_fields!(RequestInit);
|
||||||
|
|
|
@ -125,7 +125,8 @@ use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::context::ReflowGoal;
|
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::str::{split_html_space_chars, str_join};
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
use time;
|
use time;
|
||||||
|
@ -158,6 +159,29 @@ struct StylesheetInDocument {
|
||||||
stylesheet: Arc<Stylesheet>,
|
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
|
// https://dom.spec.whatwg.org/#document
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct Document {
|
pub struct Document {
|
||||||
|
@ -234,9 +258,9 @@ pub struct Document {
|
||||||
/// This field is set to the document itself for inert documents.
|
/// This field is set to the document itself for inert documents.
|
||||||
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
|
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
|
||||||
appropriate_template_contents_owner_document: MutNullableHeap<JS<Document>>,
|
appropriate_template_contents_owner_document: MutNullableHeap<JS<Document>>,
|
||||||
/// For each element that has had a state or attribute change since the last restyle,
|
/// Information on elements needing restyle to ship over to the layout thread when the
|
||||||
/// track the original condition of the element.
|
/// time comes.
|
||||||
modified_elements: DOMRefCell<HashMap<JS<Element>, Snapshot>>,
|
pending_restyles: DOMRefCell<HashMap<JS<Element>, PendingRestyle>>,
|
||||||
/// This flag will be true if layout suppressed a reflow attempt that was
|
/// This flag will be true if layout suppressed a reflow attempt that was
|
||||||
/// needed in order for the page to be painted.
|
/// needed in order for the page to be painted.
|
||||||
needs_paint: Cell<bool>,
|
needs_paint: Cell<bool>,
|
||||||
|
@ -410,7 +434,7 @@ impl Document {
|
||||||
Some(root) => {
|
Some(root) => {
|
||||||
root.upcast::<Node>().is_dirty() ||
|
root.upcast::<Node>().is_dirty() ||
|
||||||
root.upcast::<Node>().has_dirty_descendants() ||
|
root.upcast::<Node>().has_dirty_descendants() ||
|
||||||
!self.modified_elements.borrow().is_empty() ||
|
!self.pending_restyles.borrow().is_empty() ||
|
||||||
self.needs_paint()
|
self.needs_paint()
|
||||||
}
|
}
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -1708,7 +1732,7 @@ pub enum DocumentSource {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub trait LayoutDocumentHelpers {
|
pub trait LayoutDocumentHelpers {
|
||||||
unsafe fn is_html_document_for_layout(&self) -> bool;
|
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 needs_paint_from_layout(&self);
|
||||||
unsafe fn will_paint(&self);
|
unsafe fn will_paint(&self);
|
||||||
}
|
}
|
||||||
|
@ -1722,8 +1746,8 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
unsafe fn drain_modified_elements(&self) -> Vec<(LayoutJS<Element>, Snapshot)> {
|
unsafe fn drain_pending_restyles(&self) -> Vec<(LayoutJS<Element>, PendingRestyle)> {
|
||||||
let mut elements = (*self.unsafe_get()).modified_elements.borrow_mut_for_layout();
|
let mut elements = (*self.unsafe_get()).pending_restyles.borrow_mut_for_layout();
|
||||||
let result = elements.drain().map(|(k, v)| (k.to_layout(), v)).collect();
|
let result = elements.drain().map(|(k, v)| (k.to_layout(), v)).collect();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -1830,7 +1854,7 @@ impl Document {
|
||||||
reflow_timeout: Cell::new(None),
|
reflow_timeout: Cell::new(None),
|
||||||
base_element: Default::default(),
|
base_element: Default::default(),
|
||||||
appropriate_template_contents_owner_document: 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),
|
needs_paint: Cell::new(false),
|
||||||
active_touch_points: DOMRefCell::new(Vec::new()),
|
active_touch_points: DOMRefCell::new(Vec::new()),
|
||||||
dom_loading: Cell::new(Default::default()),
|
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]))
|
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) {
|
pub fn element_state_will_change(&self, el: &Element) {
|
||||||
let mut map = self.modified_elements.borrow_mut();
|
let mut snapshot = self.ensure_snapshot(el);
|
||||||
let snapshot = map.entry(JS::from_ref(el))
|
|
||||||
.or_insert_with(|| {
|
|
||||||
Snapshot::new(el.html_element_in_html_document())
|
|
||||||
});
|
|
||||||
if snapshot.state.is_none() {
|
if snapshot.state.is_none() {
|
||||||
snapshot.state = Some(el.state());
|
snapshot.state = Some(el.state());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element_attr_will_change(&self, el: &Element) {
|
pub fn element_attr_will_change(&self, el: &Element) {
|
||||||
let mut map = self.modified_elements.borrow_mut();
|
let mut snapshot = self.ensure_snapshot(el);
|
||||||
let mut snapshot = map.entry(JS::from_ref(el))
|
|
||||||
.or_insert_with(|| {
|
|
||||||
Snapshot::new(el.html_element_in_html_document())
|
|
||||||
});
|
|
||||||
if snapshot.attrs.is_none() {
|
if snapshot.attrs.is_none() {
|
||||||
let attrs = el.attrs()
|
let attrs = el.attrs()
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -34,7 +34,7 @@ use dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId};
|
||||||
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
use dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId};
|
||||||
use dom::bindings::js::LayoutJS;
|
use dom::bindings::js::LayoutJS;
|
||||||
use dom::characterdata::LayoutCharacterDataHelpers;
|
use dom::characterdata::LayoutCharacterDataHelpers;
|
||||||
use dom::document::{Document, LayoutDocumentHelpers};
|
use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
|
||||||
use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
|
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_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
|
||||||
use dom::node::{LayoutNodeHelpers, Node};
|
use dom::node::{LayoutNodeHelpers, Node};
|
||||||
|
@ -65,7 +65,7 @@ use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthe
|
||||||
use style::dom::{TRestyleDamage, UnsafeNode};
|
use style::dom::{TRestyleDamage, UnsafeNode};
|
||||||
use style::element_state::*;
|
use style::element_state::*;
|
||||||
use style::properties::{ComputedValues, PropertyDeclarationBlock};
|
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::selector_matching::ApplicableDeclarationBlock;
|
||||||
use style::sink::Push;
|
use style::sink::Push;
|
||||||
use style::str::is_whitespace;
|
use style::str::is_whitespace;
|
||||||
|
@ -377,8 +377,8 @@ impl<'ld> ServoLayoutDocument<'ld> {
|
||||||
self.as_node().children().find(ServoLayoutNode::is_element)
|
self.as_node().children().find(ServoLayoutNode::is_element)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drain_modified_elements(&self) -> Vec<(ServoLayoutElement<'ld>, Snapshot)> {
|
pub fn drain_pending_restyles(&self) -> Vec<(ServoLayoutElement<'ld>, PendingRestyle)> {
|
||||||
let elements = unsafe { self.document.drain_modified_elements() };
|
let elements = unsafe { self.document.drain_pending_restyles() };
|
||||||
elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()
|
elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use computed_values::display;
|
use computed_values::display;
|
||||||
use dom::TRestyleDamage;
|
use dom::TRestyleDamage;
|
||||||
|
use heapsize::HeapSizeOf;
|
||||||
use properties::ServoComputedValues;
|
use properties::ServoComputedValues;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
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 {
|
impl TRestyleDamage for ServoRestyleDamage {
|
||||||
/// For Servo the style source is always the computed values.
|
/// For Servo the style source is always the computed values.
|
||||||
type PreExistingComputedValues = Arc<ServoComputedValues>;
|
type PreExistingComputedValues = Arc<ServoComputedValues>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue