mirror of
https://github.com/servo/servo.git
synced 2025-07-30 18:50:36 +01:00
Auto merge of #8299 - pcwalton:dont-reflow-on-hover, r=mbrubeck
Fix several bugs causing the page to reflow on every mouse move event After all these changes are applied, Hacker News and GitHub only repaint and reflow nodes that actually have hover styles applied when the mouse moves over them. r? @mbrubeck cc @bholley <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8299) <!-- Reviewable:end -->
This commit is contained in:
commit
36c5dd4c8c
5 changed files with 56 additions and 40 deletions
|
@ -989,9 +989,10 @@ impl BlockFlow {
|
|||
let mut block_size = cur_b - block_start_offset;
|
||||
let is_root = self.is_root();
|
||||
if is_root {
|
||||
let screen_size = LogicalSize::from_physical(self.fragment.style.writing_mode,
|
||||
layout_context.shared.screen_size);
|
||||
block_size = max(screen_size.block, block_size)
|
||||
let viewport_size =
|
||||
LogicalSize::from_physical(self.fragment.style.writing_mode,
|
||||
layout_context.shared.viewport_size);
|
||||
block_size = max(viewport_size.block, block_size)
|
||||
}
|
||||
|
||||
if is_root || self.formatting_context_type() != FormattingContextType::None ||
|
||||
|
@ -1156,9 +1157,9 @@ impl BlockFlow {
|
|||
|
||||
pub fn explicit_block_containing_size(&self, layout_context: &LayoutContext) -> Option<Au> {
|
||||
if self.is_root() || self.is_fixed() {
|
||||
let screen_size = LogicalSize::from_physical(self.fragment.style.writing_mode,
|
||||
layout_context.shared.screen_size);
|
||||
Some(screen_size.block)
|
||||
let viewport_size = LogicalSize::from_physical(self.fragment.style.writing_mode,
|
||||
layout_context.shared.viewport_size);
|
||||
Some(viewport_size.block)
|
||||
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) &&
|
||||
self.base.block_container_explicit_block_size.is_none() {
|
||||
self.base.absolute_cb.explicit_block_containing_size(layout_context)
|
||||
|
@ -1223,7 +1224,7 @@ impl BlockFlow {
|
|||
fn calculate_absolute_block_size_and_margins(&mut self, layout_context: &LayoutContext) {
|
||||
let opaque_self = OpaqueFlow::from_flow(self);
|
||||
let containing_block_block_size =
|
||||
self.containing_block_size(&layout_context.shared.screen_size, opaque_self).block;
|
||||
self.containing_block_size(&layout_context.shared.viewport_size, opaque_self).block;
|
||||
|
||||
// This is the stored content block-size value from assign-block-size
|
||||
let content_block_size = self.fragment.border_box.size.block;
|
||||
|
@ -1381,7 +1382,7 @@ impl BlockFlow {
|
|||
|
||||
// Calculate containing block inline size.
|
||||
let containing_block_size = if flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
self.containing_block_size(&layout_context.shared.screen_size, opaque_self).inline
|
||||
self.containing_block_size(&layout_context.shared.viewport_size, opaque_self).inline
|
||||
} else {
|
||||
content_inline_size
|
||||
};
|
||||
|
@ -1714,7 +1715,7 @@ impl Flow for BlockFlow {
|
|||
debug!("Setting root position");
|
||||
self.base.position.start = LogicalPoint::zero(self.base.writing_mode);
|
||||
self.base.block_container_inline_size = LogicalSize::from_physical(
|
||||
self.base.writing_mode, layout_context.shared.screen_size).inline;
|
||||
self.base.writing_mode, layout_context.shared.viewport_size).inline;
|
||||
self.base.block_container_writing_mode = self.base.writing_mode;
|
||||
|
||||
// The root element is never impacted by floats.
|
||||
|
@ -1979,12 +1980,12 @@ impl Flow for BlockFlow {
|
|||
let visible_rect =
|
||||
match layout_context.shared.visible_rects.get(&self.layer_id()) {
|
||||
Some(visible_rect) => *visible_rect,
|
||||
None => Rect::new(Point2D::zero(), layout_context.shared.screen_size),
|
||||
None => Rect::new(Point2D::zero(), layout_context.shared.viewport_size),
|
||||
};
|
||||
|
||||
let screen_size = layout_context.shared.screen_size;
|
||||
visible_rect.inflate(screen_size.width * DISPLAY_PORT_SIZE_FACTOR,
|
||||
screen_size.height * DISPLAY_PORT_SIZE_FACTOR)
|
||||
let viewport_size = layout_context.shared.viewport_size;
|
||||
visible_rect.inflate(viewport_size.width * DISPLAY_PORT_SIZE_FACTOR,
|
||||
viewport_size.height * DISPLAY_PORT_SIZE_FACTOR)
|
||||
} else if is_stacking_context {
|
||||
self.base
|
||||
.stacking_relative_position_of_display_port
|
||||
|
@ -2705,7 +2706,7 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
|
|||
layout_context: &LayoutContext)
|
||||
-> Au {
|
||||
let opaque_block = OpaqueFlow::from_flow(block);
|
||||
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline
|
||||
block.containing_block_size(&layout_context.shared.viewport_size, opaque_block).inline
|
||||
}
|
||||
|
||||
fn set_inline_position_of_flow_if_necessary(&self,
|
||||
|
@ -2817,7 +2818,7 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
|||
-> MaybeAuto {
|
||||
let opaque_block = OpaqueFlow::from_flow(block);
|
||||
let containing_block_inline_size =
|
||||
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline;
|
||||
block.containing_block_size(&layout_context.shared.viewport_size, opaque_block).inline;
|
||||
let fragment = block.fragment();
|
||||
fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size);
|
||||
// For replaced absolute flow, the rest of the constraint solving will
|
||||
|
@ -2831,7 +2832,7 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
|||
layout_context: &LayoutContext)
|
||||
-> Au {
|
||||
let opaque_block = OpaqueFlow::from_flow(block);
|
||||
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline
|
||||
block.containing_block_size(&layout_context.shared.viewport_size, opaque_block).inline
|
||||
}
|
||||
|
||||
fn set_inline_position_of_flow_if_necessary(&self,
|
||||
|
|
|
@ -82,8 +82,8 @@ pub struct SharedLayoutContext {
|
|||
/// A channel for the image cache to send responses to.
|
||||
pub image_cache_sender: ImageCacheChan,
|
||||
|
||||
/// The current screen size.
|
||||
pub screen_size: Size2D<Au>,
|
||||
/// The current viewport size.
|
||||
pub viewport_size: Size2D<Au>,
|
||||
|
||||
/// Screen sized changed?
|
||||
pub screen_size_changed: bool,
|
||||
|
|
|
@ -463,7 +463,7 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
|||
None => None,
|
||||
Some(ref style) => Some(&**style),
|
||||
};
|
||||
let (the_style, is_cacheable) = cascade(layout_context.screen_size,
|
||||
let (the_style, is_cacheable) = cascade(layout_context.viewport_size,
|
||||
applicable_declarations,
|
||||
shareable,
|
||||
Some(&***parent_style),
|
||||
|
@ -472,7 +472,7 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
|||
this_style = the_style
|
||||
}
|
||||
None => {
|
||||
let (the_style, is_cacheable) = cascade(layout_context.screen_size,
|
||||
let (the_style, is_cacheable) = cascade(layout_context.viewport_size,
|
||||
applicable_declarations,
|
||||
shareable,
|
||||
None,
|
||||
|
|
|
@ -940,11 +940,12 @@ pub struct BaseFlow {
|
|||
impl fmt::Debug for BaseFlow {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
"@ {:?}, CC {}, ADC {}, Ovr {:?}",
|
||||
"@ {:?}, CC {}, ADC {}, Ovr {:?}, Dmg {:?}",
|
||||
self.position,
|
||||
self.parallel.children_count.load(Ordering::SeqCst),
|
||||
self.abs_descendants.len(),
|
||||
self.overflow)
|
||||
self.overflow,
|
||||
self.restyle_damage)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,9 +109,13 @@ pub struct LayoutTaskData {
|
|||
/// The channel on which messages can be sent to the constellation.
|
||||
pub constellation_chan: ConstellationChan,
|
||||
|
||||
/// The size of the viewport.
|
||||
/// The size of the screen.
|
||||
pub screen_size: Size2D<Au>,
|
||||
|
||||
/// The size of the viewport. This may be different from the size of the screen due to viewport
|
||||
/// constraints.
|
||||
pub viewport_size: Size2D<Au>,
|
||||
|
||||
/// The root stacking context.
|
||||
pub stacking_context: Option<Arc<StackingContext>>,
|
||||
|
||||
|
@ -408,6 +412,7 @@ impl LayoutTask {
|
|||
image_cache_task: image_cache_task,
|
||||
constellation_chan: constellation_chan,
|
||||
screen_size: screen_size,
|
||||
viewport_size: screen_size,
|
||||
stacking_context: None,
|
||||
stylist: stylist,
|
||||
parallel_traversal: parallel_traversal,
|
||||
|
@ -445,7 +450,7 @@ impl LayoutTask {
|
|||
SharedLayoutContext {
|
||||
image_cache_task: rw_data.image_cache_task.clone(),
|
||||
image_cache_sender: self.image_cache_sender.clone(),
|
||||
screen_size: rw_data.screen_size.clone(),
|
||||
viewport_size: rw_data.viewport_size.clone(),
|
||||
screen_size_changed: screen_size_changed,
|
||||
constellation_chan: rw_data.constellation_chan.clone(),
|
||||
layout_chan: self.chan.clone(),
|
||||
|
@ -1033,7 +1038,7 @@ impl LayoutTask {
|
|||
|| {
|
||||
flow::mut_base(flow_ref::deref_mut(layout_root)).stacking_relative_position =
|
||||
LogicalPoint::zero(writing_mode).to_physical(writing_mode,
|
||||
rw_data.screen_size);
|
||||
rw_data.viewport_size);
|
||||
|
||||
flow::mut_base(flow_ref::deref_mut(layout_root)).clip =
|
||||
ClippingRegion::from_rect(&data.page_clip_rect);
|
||||
|
@ -1138,24 +1143,31 @@ impl LayoutTask {
|
|||
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||
|
||||
let initial_viewport = data.window_size.initial_viewport;
|
||||
let old_screen_size = rw_data.screen_size;
|
||||
let old_viewport_size = rw_data.viewport_size;
|
||||
let current_screen_size = Size2D::new(Au::from_f32_px(initial_viewport.width.get()),
|
||||
Au::from_f32_px(initial_viewport.height.get()));
|
||||
rw_data.screen_size = current_screen_size;
|
||||
|
||||
// Handle conditions where the entire flow tree is invalid.
|
||||
let screen_size_changed = current_screen_size != old_screen_size;
|
||||
if screen_size_changed {
|
||||
// Calculate the actual viewport as per DEVICE-ADAPT § 6
|
||||
let device = Device::new(MediaType::Screen, initial_viewport);
|
||||
rw_data.stylist.set_device(device);
|
||||
// Calculate the actual viewport as per DEVICE-ADAPT § 6
|
||||
let device = Device::new(MediaType::Screen, initial_viewport);
|
||||
rw_data.stylist.set_device(device);
|
||||
|
||||
if let Some(constraints) = rw_data.stylist.constrain_viewport() {
|
||||
let constraints = rw_data.stylist.constrain_viewport();
|
||||
rw_data.viewport_size = match constraints {
|
||||
Some(ref constraints) => {
|
||||
debug!("Viewport constraints: {:?}", constraints);
|
||||
|
||||
// other rules are evaluated against the actual viewport
|
||||
rw_data.screen_size = Size2D::new(Au::from_f32_px(constraints.size.width.get()),
|
||||
Au::from_f32_px(constraints.size.height.get()));
|
||||
Size2D::new(Au::from_f32_px(constraints.size.width.get()),
|
||||
Au::from_f32_px(constraints.size.height.get()))
|
||||
}
|
||||
None => current_screen_size,
|
||||
};
|
||||
|
||||
// Handle conditions where the entire flow tree is invalid.
|
||||
let viewport_size_changed = rw_data.viewport_size != old_viewport_size;
|
||||
if viewport_size_changed {
|
||||
if let Some(constraints) = constraints {
|
||||
let device = Device::new(MediaType::Screen, constraints.size);
|
||||
rw_data.stylist.set_device(device);
|
||||
|
||||
|
@ -1168,7 +1180,7 @@ impl LayoutTask {
|
|||
|
||||
// If the entire flow tree is invalid, then it will be reflowed anyhow.
|
||||
let needs_dirtying = rw_data.stylist.update();
|
||||
let needs_reflow = screen_size_changed && !needs_dirtying;
|
||||
let needs_reflow = viewport_size_changed && !needs_dirtying;
|
||||
unsafe {
|
||||
if needs_dirtying {
|
||||
LayoutTask::dirty_all_nodes(node);
|
||||
|
@ -1184,14 +1196,16 @@ impl LayoutTask {
|
|||
if !needs_dirtying {
|
||||
for &(el, state_change) in state_changes.iter() {
|
||||
debug_assert!(!state_change.is_empty());
|
||||
let hint = rw_data.stylist.restyle_hint_for_state_change(&el, el.get_state(), state_change);
|
||||
let hint = rw_data.stylist.restyle_hint_for_state_change(&el,
|
||||
el.get_state(),
|
||||
state_change);
|
||||
el.note_restyle_hint(hint);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a layout context for use throughout the following passes.
|
||||
let mut shared_layout_context = self.build_shared_layout_context(&*rw_data,
|
||||
screen_size_changed,
|
||||
viewport_size_changed,
|
||||
&self.url,
|
||||
data.reflow_info.goal);
|
||||
|
||||
|
@ -1262,8 +1276,8 @@ impl LayoutTask {
|
|||
let mut must_regenerate_display_lists = false;
|
||||
let mut old_visible_rects = HashMap::with_hash_state(Default::default());
|
||||
let inflation_amount =
|
||||
Size2D::new(rw_data.screen_size.width * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR,
|
||||
rw_data.screen_size.height * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR);
|
||||
Size2D::new(rw_data.viewport_size.width * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR,
|
||||
rw_data.viewport_size.height * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR);
|
||||
for &(ref layer_id, ref new_visible_rect) in &new_visible_rects {
|
||||
match rw_data.visible_rects.get(layer_id) {
|
||||
None => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue