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

@ -72,6 +72,7 @@ use style::dom::{TElement, TNode};
use style::driver;
use style::error_reporting::RustLogReporter;
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
use style::invalidation::element::restyle_hints::RestyleHint;
use style::media_queries::{Device, MediaList, MediaType};
use style::properties::PropertyId;
use style::selector_parser::SnapshotMap;
@ -360,7 +361,10 @@ impl LayoutThread {
fragment_tree: Default::default(),
// 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: webrender_api_sender,
stylist: Stylist::new(device, QuirksMode::NoQuirks),
rw_data: Arc::new(Mutex::new(LayoutThreadData {
@ -628,15 +632,6 @@ impl LayoutThread {
Some(x) => x,
};
let initial_viewport = data.window_size.initial_viewport;
let device_pixel_ratio = data.window_size.device_pixel_ratio;
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();
@ -649,17 +644,14 @@ impl LayoutThread {
ua_or_user: &ua_or_user_guard,
};
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);
let had_used_viewport_units = self.stylist.device().used_viewport_units();
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());
}
}
self.stylist
.force_stylesheet_origins_dirty(sheet_origins_affected_by_device_change);
self.viewport_size = current_screen_size;
if self.first_reflow.get() {
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
self.stylist
@ -739,7 +731,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,
@ -1158,6 +1150,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 {