mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Store pristine element state rather than a set of changes.
This is the strategy we'll need to take for attributes, and so this change puts us in a position to handle attributes and state the same way. This does mean that we stop taking care to track the situations where our state has reverted to the original state, with no net change. I think that's probably of negligible value though.
This commit is contained in:
parent
d89816bb5f
commit
7dba4447f1
6 changed files with 23 additions and 35 deletions
|
@ -1213,13 +1213,12 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let state_changes = document.drain_element_state_changes();
|
let modified_elements = document.drain_modified_elements();
|
||||||
if !needs_dirtying {
|
if !needs_dirtying {
|
||||||
for &(el, state_change) in state_changes.iter() {
|
for &(el, old_state) in modified_elements.iter() {
|
||||||
debug_assert!(!state_change.is_empty());
|
|
||||||
let hint = rw_data.stylist.restyle_hint_for_state_change(&el,
|
let hint = rw_data.stylist.restyle_hint_for_state_change(&el,
|
||||||
el.get_state(),
|
el.get_state(),
|
||||||
state_change);
|
old_state);
|
||||||
el.note_restyle_hint(hint);
|
el.note_restyle_hint(hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,10 +375,10 @@ impl<'le> LayoutDocument<'le> {
|
||||||
self.as_node().children().find(LayoutNode::is_element)
|
self.as_node().children().find(LayoutNode::is_element)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drain_element_state_changes(&self) -> Vec<(LayoutElement, ElementState)> {
|
pub fn drain_modified_elements(&self) -> Vec<(LayoutElement, ElementState)> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let changes = self.document.drain_element_state_changes();
|
let elements = self.document.drain_modified_elements();
|
||||||
Vec::from_iter(changes.iter().map(|&(el, state)|
|
Vec::from_iter(elements.iter().map(|&(el, state)|
|
||||||
(LayoutElement {
|
(LayoutElement {
|
||||||
element: el,
|
element: el,
|
||||||
chain: PhantomData,
|
chain: PhantomData,
|
||||||
|
|
|
@ -175,8 +175,8 @@ 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>>,
|
||||||
/// The collection of ElementStates that have been changed since the last restyle.
|
/// For each element that has had a state change since the last restyle, track the original state.
|
||||||
element_state_changes: DOMRefCell<HashMap<JS<Element>, ElementState>>,
|
modified_elements: DOMRefCell<HashMap<JS<Element>, ElementState>>,
|
||||||
/// http://w3c.github.io/touch-events/#dfn-active-touch-point
|
/// http://w3c.github.io/touch-events/#dfn-active-touch-point
|
||||||
active_touch_points: DOMRefCell<Vec<JS<Touch>>>,
|
active_touch_points: DOMRefCell<Vec<JS<Touch>>>,
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ impl Document {
|
||||||
|
|
||||||
pub fn needs_reflow(&self) -> bool {
|
pub fn needs_reflow(&self) -> bool {
|
||||||
self.GetDocumentElement().is_some() &&
|
self.GetDocumentElement().is_some() &&
|
||||||
(self.upcast::<Node>().get_has_dirty_descendants() || !self.element_state_changes.borrow().is_empty())
|
(self.upcast::<Node>().get_has_dirty_descendants() || !self.modified_elements.borrow().is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first `base` element in the DOM that has an `href` attribute.
|
/// Returns the first `base` element in the DOM that has an `href` attribute.
|
||||||
|
@ -1230,7 +1230,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_element_state_changes(&self) -> Vec<(LayoutJS<Element>, ElementState)>;
|
unsafe fn drain_modified_elements(&self) -> Vec<(LayoutJS<Element>, ElementState)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -1242,9 +1242,9 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
unsafe fn drain_element_state_changes(&self) -> Vec<(LayoutJS<Element>, ElementState)> {
|
unsafe fn drain_modified_elements(&self) -> Vec<(LayoutJS<Element>, ElementState)> {
|
||||||
let mut changes = (*self.unsafe_get()).element_state_changes.borrow_mut_for_layout();
|
let mut elements = (*self.unsafe_get()).modified_elements.borrow_mut_for_layout();
|
||||||
let drain = changes.drain();
|
let drain = elements.drain();
|
||||||
let layout_drain = drain.map(|(k, v)| (k.to_layout(), v));
|
let layout_drain = drain.map(|(k, v)| (k.to_layout(), v));
|
||||||
Vec::from_iter(layout_drain)
|
Vec::from_iter(layout_drain)
|
||||||
}
|
}
|
||||||
|
@ -1313,7 +1313,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(),
|
||||||
element_state_changes: DOMRefCell::new(HashMap::new()),
|
modified_elements: DOMRefCell::new(HashMap::new()),
|
||||||
active_touch_points: DOMRefCell::new(Vec::new()),
|
active_touch_points: DOMRefCell::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1380,18 +1380,9 @@ impl Document {
|
||||||
self.idmap.borrow().get(&id).map(|ref elements| Root::from_ref(&*(*elements)[0]))
|
self.idmap.borrow().get(&id).map(|ref elements| Root::from_ref(&*(*elements)[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_element_state_change(&self, el: &Element, which: ElementState) {
|
pub fn element_state_will_change(&self, el: &Element) {
|
||||||
let mut map = self.element_state_changes.borrow_mut();
|
let mut map = self.modified_elements.borrow_mut();
|
||||||
let empty;
|
map.entry(JS::from_ref(el)).or_insert(el.get_state());
|
||||||
{
|
|
||||||
let states = map.entry(JS::from_ref(el))
|
|
||||||
.or_insert(ElementState::empty());
|
|
||||||
states.toggle(which);
|
|
||||||
empty = states.is_empty();
|
|
||||||
}
|
|
||||||
if empty {
|
|
||||||
map.remove(&JS::from_ref(el));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1814,14 +1814,13 @@ impl Element {
|
||||||
if state.contains(which) == value {
|
if state.contains(which) == value {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let node = self.upcast::<Node>();
|
||||||
|
node.owner_doc().element_state_will_change(self);
|
||||||
match value {
|
match value {
|
||||||
true => state.insert(which),
|
true => state.insert(which),
|
||||||
false => state.remove(which),
|
false => state.remove(which),
|
||||||
};
|
};
|
||||||
self.state.set(state);
|
self.state.set(state);
|
||||||
|
|
||||||
let node = self.upcast::<Node>();
|
|
||||||
node.owner_doc().record_element_state_change(self, which);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_active_state(&self) -> bool {
|
pub fn get_active_state(&self) -> bool {
|
||||||
|
|
|
@ -195,11 +195,10 @@ impl StateDependencySet {
|
||||||
StateDependencySet { deps: Vec::new() }
|
StateDependencySet { deps: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_hint<E>(&self, el: &E, current_state: ElementState, state_changes: ElementState)
|
pub fn compute_hint<E>(&self, el: &E, current_state: ElementState, old_state: ElementState)
|
||||||
-> RestyleHint where E: Element, E: Clone {
|
-> RestyleHint where E: Element, E: Clone {
|
||||||
let mut hint = RestyleHint::empty();
|
let mut hint = RestyleHint::empty();
|
||||||
let mut old_state = current_state;
|
let state_changes = current_state ^ old_state;
|
||||||
old_state.toggle(state_changes);
|
|
||||||
for dep in &self.deps {
|
for dep in &self.deps {
|
||||||
if state_changes.intersects(dep.state) {
|
if state_changes.intersects(dep.state) {
|
||||||
let old_el: ElementWrapper<E> = ElementWrapper::new_with_override(el.clone(), old_state);
|
let old_el: ElementWrapper<E> = ElementWrapper::new_with_override(el.clone(), old_state);
|
||||||
|
|
|
@ -174,10 +174,10 @@ impl Stylist {
|
||||||
|
|
||||||
pub fn restyle_hint_for_state_change<E>(&self, element: &E,
|
pub fn restyle_hint_for_state_change<E>(&self, element: &E,
|
||||||
current_state: ElementState,
|
current_state: ElementState,
|
||||||
state_change: ElementState)
|
old_state: ElementState)
|
||||||
-> RestyleHint
|
-> RestyleHint
|
||||||
where E: Element + Clone {
|
where E: Element + Clone {
|
||||||
self.state_deps.compute_hint(element, current_state, state_change)
|
self.state_deps.compute_hint(element, current_state, old_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_device(&mut self, device: Device) {
|
pub fn set_device(&mut self, device: Device) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue