layout: More conservatively replace Stylist's Device (#31857)

Instead of replacing Stylist's device on every reflow, only replace it
when the viewport changes. In addition, preserve the root font size from
the previous reflow fixing an issue where `rem` units were not properly
computed between reflows.

This fixes a bug where fonts that are sized using `rem` units change
size on reload.
This commit is contained in:
Martin Robinson 2024-03-26 16:00:50 +01:00 committed by GitHub
parent b71de92569
commit bf3798bbde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 95 additions and 61 deletions

View file

@ -379,7 +379,10 @@ impl LayoutThread {
root_flow: RefCell::new(None),
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
epoch: Cell::new(Epoch(1)),
viewport_size: Size2D::new(Au(0), Au(0)),
viewport_size: Size2D::new(
Au::from_f32_px(window_size.initial_viewport.width),
Au::from_f32_px(window_size.initial_viewport.height),
),
webrender_api,
stylist: Stylist::new(device, QuirksMode::NoQuirks),
rw_data: Arc::new(Mutex::new(LayoutThreadData {
@ -936,16 +939,6 @@ impl LayoutThread {
);
trace!("{:?}", ShowSubtree(root_element.as_node()));
let initial_viewport = data.window_size.initial_viewport;
let device_pixel_ratio = data.window_size.device_pixel_ratio;
let old_viewport_size = self.viewport_size;
let current_screen_size = Size2D::new(
Au::from_f32_px(initial_viewport.width),
Au::from_f32_px(initial_viewport.height),
);
let origin = data.origin.clone();
// Calculate the actual viewport as per DEVICE-ADAPT § 6
// If the entire flow tree is invalid, then it will be reflowed anyhow.
let document_shared_lock = document.style_shared_lock();
@ -959,19 +952,7 @@ impl LayoutThread {
};
let had_used_viewport_units = self.stylist.device().used_viewport_units();
let device = Device::new(
MediaType::screen(),
self.stylist.quirks_mode(),
initial_viewport,
device_pixel_ratio,
);
let sheet_origins_affected_by_device_change = self.stylist.set_device(device, &guards);
self.stylist
.force_stylesheet_origins_dirty(sheet_origins_affected_by_device_change);
self.viewport_size = current_screen_size;
let viewport_size_changed = self.viewport_size != old_viewport_size;
let viewport_size_changed = self.handle_viewport_change(data.window_size, &guards);
if viewport_size_changed && had_used_viewport_units {
if let Some(mut data) = root_element.mutate_data() {
data.hint.insert(RestyleHint::recascade_subtree());
@ -1063,7 +1044,7 @@ impl LayoutThread {
let mut layout_context = self.build_layout_context(
guards.clone(),
&map,
origin,
data.origin.clone(),
data.animation_timeline_value,
&data.animations,
data.stylesheets_changed,
@ -1518,6 +1499,42 @@ impl LayoutThread {
},
})
}
/// Update layout given a new viewport. Returns true if the viewport changed or false if it didn't.
fn handle_viewport_change(
&mut self,
window_size_data: WindowSizeData,
guards: &StylesheetGuards,
) -> bool {
// If the viewport size and device pixel ratio has not changed, do not make any changes.
let au_viewport_size = Size2D::new(
Au::from_f32_px(window_size_data.initial_viewport.width),
Au::from_f32_px(window_size_data.initial_viewport.height),
);
if self.stylist.device().au_viewport_size() == au_viewport_size &&
self.stylist.device().device_pixel_ratio() == window_size_data.device_pixel_ratio
{
return false;
}
let device = Device::new(
MediaType::screen(),
self.stylist.quirks_mode(),
window_size_data.initial_viewport,
window_size_data.device_pixel_ratio,
);
// Preserve any previously computed root font size.
device.set_root_font_size(self.stylist.device().root_font_size());
let sheet_origins_affected_by_device_change = self.stylist.set_device(device, guards);
self.stylist
.force_stylesheet_origins_dirty(sheet_origins_affected_by_device_change);
self.viewport_size = au_viewport_size;
true
}
}
impl ProfilerMetadataFactory for LayoutThread {