mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: When there is no restyle damage, do not re-layout (#37048)
When the computed restyle damage is empty, do not do a layout. Instead, just rebuild the display list. In the future, even that can be omitted, but that requires changes to the compositor. These kind of relayouts commonly happen when the cursor is moving around the page and no style rules cause changes to :hover. Testing: This is covered existing WPT tests and should only have performance impacts. Unfortunately there are currently no performance tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
859a0ffbd5
commit
856ffa6ecb
6 changed files with 47 additions and 9 deletions
|
@ -773,7 +773,7 @@ impl LayoutThread {
|
||||||
|
|
||||||
let root_node = root_element.as_node();
|
let root_node = root_element.as_node();
|
||||||
let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node);
|
let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node);
|
||||||
if damage == RestyleDamage::REPAINT {
|
if damage.is_empty() || damage == RestyleDamage::REPAINT {
|
||||||
layout_context.style_context.stylist.rule_tree().maybe_gc();
|
layout_context.style_context.stylist.rule_tree().maybe_gc();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,9 @@ pub(crate) fn compute_damage_and_repair_style_inner(
|
||||||
parent_restyle_damage: RestyleDamage,
|
parent_restyle_damage: RestyleDamage,
|
||||||
) -> RestyleDamage {
|
) -> RestyleDamage {
|
||||||
let original_damage;
|
let original_damage;
|
||||||
let damage = {
|
let damage;
|
||||||
|
|
||||||
|
{
|
||||||
let mut element_data = node
|
let mut element_data = node
|
||||||
.style_data()
|
.style_data()
|
||||||
.expect("Should not run `compute_damage` before styling.")
|
.expect("Should not run `compute_damage` before styling.")
|
||||||
|
@ -113,14 +115,14 @@ pub(crate) fn compute_damage_and_repair_style_inner(
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
|
|
||||||
original_damage = std::mem::take(&mut element_data.damage);
|
original_damage = std::mem::take(&mut element_data.damage);
|
||||||
|
damage = original_damage | parent_restyle_damage;
|
||||||
|
|
||||||
if let Some(ref style) = element_data.styles.primary {
|
if let Some(ref style) = element_data.styles.primary {
|
||||||
if style.get_box().display == Display::None {
|
if style.get_box().display == Display::None {
|
||||||
return parent_restyle_damage;
|
return damage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
original_damage | parent_restyle_damage
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut propagated_damage = damage;
|
let mut propagated_damage = damage;
|
||||||
for child in iter_child_nodes(node) {
|
for child in iter_child_nodes(node) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ use servo_media::streams::registry::MediaStreamId;
|
||||||
use snapshot::Snapshot;
|
use snapshot::Snapshot;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
|
|
||||||
|
use super::node::NodeDamage;
|
||||||
pub(crate) use crate::canvas_context::*;
|
pub(crate) use crate::canvas_context::*;
|
||||||
use crate::conversions::Convert;
|
use crate::conversions::Convert;
|
||||||
use crate::dom::attr::Attr;
|
use crate::dom::attr::Attr;
|
||||||
|
@ -687,8 +688,11 @@ impl VirtualMethods for HTMLCanvasElement {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.attribute_mutated(attr, mutation, can_gc);
|
.attribute_mutated(attr, mutation, can_gc);
|
||||||
match attr.local_name() {
|
match attr.local_name() {
|
||||||
&local_name!("width") | &local_name!("height") => self.recreate_contexts_after_resize(),
|
&local_name!("width") | &local_name!("height") => {
|
||||||
_ => (),
|
self.recreate_contexts_after_resize();
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -520,6 +520,7 @@ impl HTMLInputElement {
|
||||||
let mut value = textinput.single_line_content().clone();
|
let mut value = textinput.single_line_content().clone();
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
textinput.set_content(value);
|
textinput.set_content(value);
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn does_minmaxlength_apply(&self) -> bool {
|
fn does_minmaxlength_apply(&self) -> bool {
|
||||||
|
@ -2668,6 +2669,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
let mut value = textinput.single_line_content().clone();
|
let mut value = textinput.single_line_content().clone();
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
textinput.set_content(value);
|
textinput.set_content(value);
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
|
||||||
// Steps 7-9
|
// Steps 7-9
|
||||||
if !previously_selectable && self.selection_api_applies() {
|
if !previously_selectable && self.selection_api_applies() {
|
||||||
|
@ -2695,6 +2697,8 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
self.textinput.borrow_mut().set_content(value);
|
self.textinput.borrow_mut().set_content(value);
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
},
|
},
|
||||||
local_name!("name") if self.input_type() == InputType::Radio => {
|
local_name!("name") if self.input_type() == InputType::Radio => {
|
||||||
self.radio_group_updated(
|
self.radio_group_updated(
|
||||||
|
|
|
@ -9,6 +9,9 @@ use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
||||||
use style::color::AbsoluteColor;
|
use style::color::AbsoluteColor;
|
||||||
use style::context::QuirksMode;
|
use style::context::QuirksMode;
|
||||||
|
|
||||||
|
use super::attr::Attr;
|
||||||
|
use super::element::AttributeMutation;
|
||||||
|
use super::node::NodeDamage;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLTableCellElementBinding::HTMLTableCellElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLTableCellElementBinding::HTMLTableCellElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
|
@ -174,6 +177,19 @@ impl VirtualMethods for HTMLTableCellElement {
|
||||||
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
|
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
|
||||||
|
if let Some(super_type) = self.super_type() {
|
||||||
|
super_type.attribute_mutated(attr, mutation, can_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(*attr.local_name(), local_name!("colspan")) {
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
}
|
||||||
|
if matches!(*attr.local_name(), local_name!("rowspan")) {
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
|
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
|
||||||
match *local_name {
|
match *local_name {
|
||||||
local_name!("colspan") => {
|
local_name!("colspan") => {
|
||||||
|
|
|
@ -7,8 +7,10 @@ use html5ever::{LocalName, Prefix, local_name, ns};
|
||||||
use js::rust::HandleObject;
|
use js::rust::HandleObject;
|
||||||
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
||||||
|
|
||||||
|
use super::attr::Attr;
|
||||||
use super::bindings::root::LayoutDom;
|
use super::bindings::root::LayoutDom;
|
||||||
use super::element::Element;
|
use super::element::{AttributeMutation, Element};
|
||||||
|
use super::node::NodeDamage;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLTableColElementBinding::HTMLTableColElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLTableColElementBinding::HTMLTableColElementMethods;
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
@ -93,6 +95,16 @@ impl VirtualMethods for HTMLTableColElement {
|
||||||
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
|
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
|
||||||
|
if let Some(super_type) = self.super_type() {
|
||||||
|
super_type.attribute_mutated(attr, mutation, can_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(*attr.local_name(), local_name!("span")) {
|
||||||
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
|
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
|
||||||
match *local_name {
|
match *local_name {
|
||||||
local_name!("span") => {
|
local_name!("span") => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue