mirror of
https://github.com/servo/servo
synced 2026-05-09 08:32:31 +02:00
Replace the old dirty root box tree layout approach with one that works
based on independent formatting contexts. Instead of just allowing a
single dirty root to be the source of box tree reconstruction, allow box
tree reconstruction to happen anywhere in the tree that can isolate box
tree damage from ancestors. This essentially combines damage propagation
and box tree construction into a single step.
There is currently one downside to this approach compared to the dirty
root approach which is that we currently cannot detect and start box
tree layout when the dirty has a compatible `display` and `position`
value. This can mean the scope of box tree layout extends further up the
tree. We will address this in a followup -- but have not noticed any
major performance implications (currently fragment tree layout is much
more expensive than box tree layout).
Benefits:
1. Damage propagation now only happens under the dirty root.
2. Future changes can limit the scope of damage up the tree and perhaps
preserve the inline content size cache between box tree rebuilds.
Testing: This should not change behavior in a testable way (we currently
do
not have robust performance tests), so WPT test results should not
change.
---------
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
66 lines
2.4 KiB
Rust
66 lines
2.4 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use bitflags::bitflags;
|
|
use style::selector_parser::RestyleDamage;
|
|
|
|
bitflags! {
|
|
/// Individual layout actions that may be necessary after restyling. This is an extension
|
|
/// of `RestyleDamage` from stylo, which only uses the 4 lower bits.
|
|
#[derive(Clone, Copy, Default, Eq, PartialEq)]
|
|
pub struct LayoutDamage: u16 {
|
|
/// Clear the cached inline content sizes and recompute them during the next layout.
|
|
const RECOMPUTE_INLINE_CONTENT_SIZES = 0b1000_0000_0000 << 4;
|
|
/// Rebuild this box and all of its ancestors. Do not rebuild any children. This
|
|
/// is used when a box's content (such as text content) changes or a descendant
|
|
/// has box damage ([`Self::BOX_DAMAGE`]).
|
|
const DESCENDANT_HAS_BOX_DAMAGE = 0b0111_1111_1111 << 4;
|
|
/// Rebuild this box, all of its ancestors and all of its descendants. This is the
|
|
/// most a box can be damaged.
|
|
const BOX_DAMAGE = 0b1111_1111_1111 << 4;
|
|
}
|
|
}
|
|
|
|
impl LayoutDamage {
|
|
pub fn descendant_has_box_damage() -> RestyleDamage {
|
|
RestyleDamage::from_bits_retain(LayoutDamage::DESCENDANT_HAS_BOX_DAMAGE.bits())
|
|
}
|
|
|
|
pub fn box_damage() -> RestyleDamage {
|
|
RestyleDamage::from_bits_retain(LayoutDamage::BOX_DAMAGE.bits())
|
|
}
|
|
|
|
pub fn needs_new_box(&self) -> bool {
|
|
self.contains(Self::DESCENDANT_HAS_BOX_DAMAGE)
|
|
}
|
|
|
|
pub fn recompute_inline_content_sizes() -> RestyleDamage {
|
|
RestyleDamage::from_bits_retain(LayoutDamage::RECOMPUTE_INLINE_CONTENT_SIZES.bits())
|
|
}
|
|
}
|
|
|
|
impl From<RestyleDamage> for LayoutDamage {
|
|
fn from(restyle_damage: RestyleDamage) -> Self {
|
|
LayoutDamage::from_bits_retain(restyle_damage.bits())
|
|
}
|
|
}
|
|
|
|
impl From<LayoutDamage> for RestyleDamage {
|
|
fn from(layout_damage: LayoutDamage) -> Self {
|
|
RestyleDamage::from_bits_retain(layout_damage.bits())
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for LayoutDamage {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
if self.contains(Self::BOX_DAMAGE) {
|
|
f.write_str("REBUILD_BOX")
|
|
} else if self.contains(Self::DESCENDANT_HAS_BOX_DAMAGE) {
|
|
f.write_str("RECOLLECT_BOX_TREE_CHILDREN")
|
|
} else {
|
|
f.write_str("EMPTY")
|
|
}
|
|
}
|
|
}
|