diff --git a/components/layout/block.rs b/components/layout/block.rs index 1c7925feb0e..dc623d9871a 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -51,6 +51,7 @@ use model::{self, IntrinsicISizes, MarginCollapseInfo}; use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none}; use rustc_serialize::{Encodable, Encoder}; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW}; +use script_layout_interface::restyle_damage::REPOSITION; use std::cmp::{max, min}; use std::fmt; use std::sync::Arc; @@ -1842,6 +1843,8 @@ impl Flow for BlockFlow { self.fragment.assign_replaced_block_size_if_necessary(containing_block_block_size); if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { self.base.position.size.block = self.fragment.border_box.size.block; + self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); + self.fragment.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); } None } else if self.is_root() || self.formatting_context_type() != FormattingContextType::None { @@ -2114,6 +2117,8 @@ impl Flow for BlockFlow { flow::mut_base(kid).stacking_relative_position_of_display_port = stacking_relative_position_of_display_port_for_children; } + + self.base.restyle_damage.remove(REPOSITION) } fn mark_as_root(&mut self) { diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 36b8da6cc48..c8703272fd6 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -42,7 +42,8 @@ use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; use multicol::MulticolFlow; use parallel::FlowParallelInfo; use rustc_serialize::{Encodable, Encoder}; -use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; +use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW}; +use script_layout_interface::restyle_damage::{REPAINT, REPOSITION, RestyleDamage}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode}; use std::{fmt, mem, raw}; use std::iter::Zip; @@ -320,6 +321,7 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static { /// Phase 4 of reflow: computes absolute positions. fn compute_absolute_position(&mut self, _: &SharedLayoutContext) { // The default implementation is a no-op. + mut_base(self).restyle_damage.remove(REPOSITION) } /// Phase 5 of reflow: builds display lists. diff --git a/components/layout/inline.rs b/components/layout/inline.rs index d1d50b22fe4..ec1d223cd36 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -25,8 +25,8 @@ use gfx_traits::print_tree::PrintTree; use layout_debug; use model::IntrinsicISizesContribution; use range::{Range, RangeIndex}; -use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW}; -use script_layout_interface::restyle_damage::{REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT}; +use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW}; +use script_layout_interface::restyle_damage::{REPOSITION, RESOLVE_GENERATED_CONTENT}; use script_layout_interface::wrapper_traits::PseudoElementType; use std::{fmt, i32, isize, mem}; use std::cmp::max; @@ -1650,6 +1650,8 @@ impl Flow for InlineFlow { _ => {} } } + + self.base.restyle_damage.remove(REPOSITION) } fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {} diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index 2479731c69f..d59774c46d5 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -17,7 +17,7 @@ use generated_content::ResolveGeneratedContent; use gfx::display_list::{DisplayItem, StackingContext}; use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW}; use style::context::StyleContext; -use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList, ComputeAbsolutePositions}; +use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList}; use util::opts; pub use style::sequential::traverse_dom; @@ -78,7 +78,6 @@ pub fn build_display_list_for_subtree(flow_root: &mut Flow, root_stacking_context: &mut StackingContext, shared_layout_context: &SharedLayoutContext) -> Vec { - flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: shared_layout_context }); let mut children = vec![]; flow_root.collect_stacking_contexts(root_stacking_context.id, &mut children); diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index d3066ff0a6a..d40d7b1282e 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -21,6 +21,7 @@ use gfx_traits::print_tree::PrintTree; use layout_debug; use model::MaybeAuto; use rustc_serialize::{Encodable, Encoder}; +use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; use std::cmp::max; use std::fmt; use std::iter::{Enumerate, IntoIterator, Peekable}; @@ -106,73 +107,84 @@ impl TableRowFlow { /// methods #[inline(always)] fn assign_block_size_table_row_base(&mut self, layout_context: &LayoutContext) { - // Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of all - // cells). - let mut max_block_size = Au(0); - let thread_id = self.block_flow.base.thread_id; - for kid in self.block_flow.base.child_iter_mut() { - kid.place_float_if_applicable(); - if !flow::base(kid).flags.is_float() { - kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id); + if self.block_flow.base.restyle_damage.contains(REFLOW) { + // Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of + // all cells). + let mut max_block_size = Au(0); + let thread_id = self.block_flow.base.thread_id; + for kid in self.block_flow.base.child_iter_mut() { + kid.place_float_if_applicable(); + if !flow::base(kid).flags.is_float() { + kid.assign_block_size_for_inorder_child_if_necessary(layout_context, + thread_id); + } + + { + let child_fragment = kid.as_mut_table_cell().fragment(); + // TODO: Percentage block-size + let child_specified_block_size = + MaybeAuto::from_style(child_fragment.style().content_block_size(), + Au(0)).specified_or_zero(); + max_block_size = + max(max_block_size, + child_specified_block_size + + child_fragment.border_padding.block_start_end()); + } + let child_node = flow::mut_base(kid); + child_node.position.start.b = Au(0); + max_block_size = max(max_block_size, child_node.position.size.block); } - { - let child_fragment = kid.as_mut_table_cell().fragment(); - // TODO: Percentage block-size - let child_specified_block_size = - MaybeAuto::from_style(child_fragment.style().content_block_size(), - Au(0)).specified_or_zero(); - max_block_size = - max(max_block_size, - child_specified_block_size + - child_fragment.border_padding.block_start_end()); + let mut block_size = max_block_size; + // TODO: Percentage block-size + block_size = match MaybeAuto::from_style(self.block_flow + .fragment + .style() + .content_block_size(), + Au(0)) { + MaybeAuto::Auto => block_size, + MaybeAuto::Specified(value) => max(value, block_size), + }; + + // Assign the block-size of own fragment + let mut position = self.block_flow.fragment.border_box; + position.size.block = block_size; + self.block_flow.fragment.border_box = position; + self.block_flow.base.position.size.block = block_size; + + // Assign the block-size of kid fragments, which is the same value as own block-size. + for kid in self.block_flow.base.child_iter_mut() { + let child_table_cell = kid.as_mut_table_cell(); + { + let kid_fragment = child_table_cell.mut_fragment(); + let mut position = kid_fragment.border_box; + position.size.block = block_size; + kid_fragment.border_box = position; + } + + // Assign the child's block size. + child_table_cell.block_flow.base.position.size.block = block_size; + + // Now we know the cell height, vertical align the cell's children. + child_table_cell.valign_children(); + + // Write in the size of the relative containing block for children. (This + // information is also needed to handle RTL.) + child_table_cell.block_flow.base.early_absolute_position_info = + EarlyAbsolutePositionInfo { + relative_containing_block_size: self.block_flow + .fragment + .content_box() + .size, + relative_containing_block_mode: self.block_flow + .fragment + .style() + .writing_mode, + }; } - let child_node = flow::mut_base(kid); - child_node.position.start.b = Au(0); - max_block_size = max(max_block_size, child_node.position.size.block); } - let mut block_size = max_block_size; - // TODO: Percentage block-size - block_size = match MaybeAuto::from_style(self.block_flow - .fragment - .style() - .content_block_size(), - Au(0)) { - MaybeAuto::Auto => block_size, - MaybeAuto::Specified(value) => max(value, block_size), - }; - - // Assign the block-size of own fragment - let mut position = self.block_flow.fragment.border_box; - position.size.block = block_size; - self.block_flow.fragment.border_box = position; - self.block_flow.base.position.size.block = block_size; - - // Assign the block-size of kid fragments, which is the same value as own block-size. - for kid in self.block_flow.base.child_iter_mut() { - let child_table_cell = kid.as_mut_table_cell(); - { - let kid_fragment = child_table_cell.mut_fragment(); - let mut position = kid_fragment.border_box; - position.size.block = block_size; - kid_fragment.border_box = position; - } - - // Assign the child's block size. - child_table_cell.block_flow.base.position.size.block = block_size; - - // Now we know the cell height, vertical align the cell's children. - child_table_cell.valign_children(); - - // Write in the size of the relative containing block for children. (This information - // is also needed to handle RTL.) - child_table_cell.block_flow.base.early_absolute_position_info = - EarlyAbsolutePositionInfo { - relative_containing_block_size: self.block_flow.fragment.content_box().size, - relative_containing_block_mode: self.block_flow.fragment.style().writing_mode, - }; - } + self.block_flow.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); } pub fn populate_collapsed_border_spacing<'a, I>( diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 2b080bb0d70..6e8b32a2687 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -65,7 +65,7 @@ use layout::animation; use layout::construct::ConstructionResult; use layout::context::{LayoutContext, SharedLayoutContext, heap_size_of_local_context}; use layout::display_list_builder::ToGfxColor; -use layout::flow::{self, Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; +use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow_ref::{self, FlowRef}; use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT}; use layout::layout_debug; @@ -75,7 +75,7 @@ use layout::query::{process_margin_style_query, process_node_overflow_request, p use layout::query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request}; use layout::query::process_offset_parent_query; use layout::sequential; -use layout::traversal::RecalcStyleAndConstructFlows; +use layout::traversal::{ComputeAbsolutePositions, RecalcStyleAndConstructFlows}; use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use layout::wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData}; use layout_traits::LayoutThreadFactory; @@ -89,7 +89,8 @@ use script::layout_wrapper::{ServoLayoutDocument, ServoLayoutNode}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script_layout_interface::reporter::CSSErrorReporter; -use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, STORE_OVERFLOW}; +use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION}; +use script_layout_interface::restyle_damage::STORE_OVERFLOW; use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse}; use script_layout_interface::wrapper_traits::LayoutNode; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; @@ -629,6 +630,7 @@ impl LayoutThread { reflow_info.goal); self.perform_post_style_recalc_layout_passes(&reflow_info, + None, None, &mut *rw_data, &mut layout_context); @@ -900,8 +902,11 @@ impl LayoutThread { traversal); } + /// Computes the stacking-relative positions of all flows and, if the painting is dirty and the + /// reflow goal and query type need it, builds the display list. fn compute_abs_pos_and_build_display_list(&mut self, data: &Reflow, + query_type: Option<&ReflowQueryType>, document: Option<&ServoLayoutDocument>, layout_root: &mut Flow, shared_layout_context: &mut SharedLayoutContext, @@ -919,49 +924,64 @@ impl LayoutThread { flow::mut_base(layout_root).clip = ClippingRegion::from_rect(&data.page_clip_rect); + if flow::base(layout_root).restyle_damage.contains(REPOSITION) { + layout_root.traverse_preorder(&ComputeAbsolutePositions { + layout_context: shared_layout_context + }); + } + if flow::base(layout_root).restyle_damage.contains(REPAINT) || rw_data.display_list.is_none() { - let mut root_stacking_context = StackingContext::new(StackingContextId::new(0), - StackingContextType::Real, - &Rect::zero(), - &Rect::zero(), - 0, - filter::T::new(Vec::new()), - mix_blend_mode::T::normal, - Matrix4D::identity(), - Matrix4D::identity(), - true, - false, - None); + let display_list_needed = query_type.map(reflow_query_type_needs_display_list) + .unwrap_or(false); + match (data.goal, display_list_needed) { + (ReflowGoal::ForDisplay, _) | (ReflowGoal::ForScriptQuery, true) => { + let mut root_stacking_context = + StackingContext::new(StackingContextId::new(0), + StackingContextType::Real, + &Rect::zero(), + &Rect::zero(), + 0, + filter::T::new(Vec::new()), + mix_blend_mode::T::normal, + Matrix4D::identity(), + Matrix4D::identity(), + true, + false, + None); - let display_list_entries = - sequential::build_display_list_for_subtree(layout_root, - &mut root_stacking_context, - shared_layout_context); + let display_list_entries = + sequential::build_display_list_for_subtree(layout_root, + &mut root_stacking_context, + shared_layout_context); - debug!("Done building display list."); + debug!("Done building display list."); - let root_background_color = get_root_flow_background_color(layout_root); - let root_size = { - let root_flow = flow::base(layout_root); - if rw_data.stylist.viewport_constraints().is_some() { - root_flow.position.size.to_physical(root_flow.writing_mode) - } else { - root_flow.overflow.scroll.size + let root_background_color = get_root_flow_background_color(layout_root); + let root_size = { + let root_flow = flow::base(layout_root); + if rw_data.stylist.viewport_constraints().is_some() { + root_flow.position.size.to_physical(root_flow.writing_mode) + } else { + root_flow.overflow.scroll.size + } + }; + + let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size); + root_stacking_context.bounds = origin; + root_stacking_context.overflow = origin; + root_stacking_context.layer_info = + Some(LayerInfo::new(layout_root.layer_id(), + ScrollPolicy::Scrollable, + None, + root_background_color)); + + rw_data.display_list = + Some(Arc::new(DisplayList::new(root_stacking_context, + display_list_entries))) } - }; - - let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size); - root_stacking_context.bounds = origin; - root_stacking_context.overflow = origin; - root_stacking_context.layer_info = - Some(LayerInfo::new(layout_root.layer_id(), - ScrollPolicy::Scrollable, - None, - root_background_color)); - - rw_data.display_list = - Some(Arc::new(DisplayList::new(root_stacking_context, display_list_entries))) + (ReflowGoal::ForScriptQuery, false) => {} + } } if data.goal != ReflowGoal::ForDisplay { @@ -1038,6 +1058,12 @@ impl LayoutThread { let document = unsafe { ServoLayoutNode::new(&data.document) }; let document = document.as_document().unwrap(); + // FIXME(pcwalton): Combine `ReflowGoal` and `ReflowQueryType`. Then remove this assert. + debug_assert!((data.reflow_info.goal == ReflowGoal::ForDisplay && + data.query_type == ReflowQueryType::NoQuery) || + (data.reflow_info.goal == ReflowGoal::ForScriptQuery && + data.query_type != ReflowQueryType::NoQuery)); + debug!("layout: received layout request for: {}", self.url); let mut rw_data = possibly_locked_rw_data.lock(); @@ -1217,74 +1243,84 @@ impl LayoutThread { // Perform post-style recalculation layout passes. self.perform_post_style_recalc_layout_passes(&data.reflow_info, + Some(&data.query_type), Some(&document), &mut rw_data, &mut shared_layout_context); - if let Some(mut root_flow) = self.root_flow.clone() { - let root_flow = flow_ref::deref_mut(&mut root_flow); - match data.query_type { - ReflowQueryType::ContentBoxQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.content_box_response = process_content_box_request(node, root_flow); - }, - ReflowQueryType::ContentBoxesQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); - }, - ReflowQueryType::HitTestQuery(translated_point, client_point, update_cursor) => { - let translated_point = - Point2D::new(Au::from_f32_px(translated_point.x), - Au::from_f32_px(translated_point.y)); + self.respond_to_query_if_necessary(&data.query_type, + &mut *rw_data, + &mut shared_layout_context); + } - let client_point = - Point2D::new(Au::from_f32_px(client_point.x), - Au::from_f32_px(client_point.y)); + fn respond_to_query_if_necessary(&mut self, + query_type: &ReflowQueryType, + rw_data: &mut LayoutThreadData, + shared_layout_context: &mut SharedLayoutContext) { + let mut root_flow = match self.root_flow.clone() { + Some(root_flow) => root_flow, + None => return, + }; + let root_flow = flow_ref::deref_mut(&mut root_flow); + match *query_type { + ReflowQueryType::ContentBoxQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.content_box_response = process_content_box_request(node, root_flow); + }, + ReflowQueryType::ContentBoxesQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.content_boxes_response = process_content_boxes_request(node, root_flow); + }, + ReflowQueryType::HitTestQuery(translated_point, client_point, update_cursor) => { + let translated_point = Point2D::new(Au::from_f32_px(translated_point.x), + Au::from_f32_px(translated_point.y)); - let result = rw_data.display_list - .as_ref() - .expect("Tried to hit test with no display list") - .hit_test(&translated_point, - &client_point, - &rw_data.stacking_context_scroll_offsets); - rw_data.hit_test_response = (result.last().cloned(), update_cursor); - }, - ReflowQueryType::NodeGeometryQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.client_rect_response = process_node_geometry_request(node, root_flow); - }, - ReflowQueryType::NodeScrollGeometryQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow); - }, - ReflowQueryType::NodeOverflowQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.overflow_response = process_node_overflow_request(node); - }, - ReflowQueryType::NodeLayerIdQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.layer_id_response = Some(process_node_layer_id_request(node)); - }, - ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - let layout_context = LayoutContext::new(&shared_layout_context); - rw_data.resolved_style_response = - process_resolved_style_request(node, - &layout_context, - pseudo, - property, - root_flow); - }, - ReflowQueryType::OffsetParentQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); - }, - ReflowQueryType::MarginStyleQuery(node) => { - let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.margin_style_response = process_margin_style_query(node); - }, - ReflowQueryType::NoQuery => {} - } + let client_point = Point2D::new(Au::from_f32_px(client_point.x), + Au::from_f32_px(client_point.y)); + + let result = rw_data.display_list + .as_ref() + .expect("Tried to hit test with no display list") + .hit_test(&translated_point, + &client_point, + &rw_data.stacking_context_scroll_offsets); + rw_data.hit_test_response = (result.last().cloned(), update_cursor); + }, + ReflowQueryType::NodeGeometryQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.client_rect_response = process_node_geometry_request(node, root_flow); + }, + ReflowQueryType::NodeScrollGeometryQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow); + }, + ReflowQueryType::NodeOverflowQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.overflow_response = process_node_overflow_request(node); + }, + ReflowQueryType::NodeLayerIdQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.layer_id_response = Some(process_node_layer_id_request(node)); + }, + ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + let layout_context = LayoutContext::new(&shared_layout_context); + rw_data.resolved_style_response = + process_resolved_style_request(node, + &layout_context, + pseudo, + property, + root_flow); + }, + ReflowQueryType::OffsetParentQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.offset_parent_response = process_offset_parent_query(node, root_flow); + }, + ReflowQueryType::MarginStyleQuery(node) => { + let node = unsafe { ServoLayoutNode::new(&node) }; + rw_data.margin_style_response = process_margin_style_query(node); + }, + ReflowQueryType::NoQuery => {} } } @@ -1340,7 +1376,11 @@ impl LayoutThread { false, reflow_info.goal); - self.perform_post_main_layout_passes(&reflow_info, None, &mut *rw_data, &mut layout_context); + self.perform_post_main_layout_passes(&reflow_info, + None, + None, + &mut *rw_data, + &mut layout_context); true } @@ -1398,6 +1438,7 @@ impl LayoutThread { } self.perform_post_style_recalc_layout_passes(&reflow_info, + None, None, &mut *rw_data, &mut layout_context); @@ -1421,6 +1462,7 @@ impl LayoutThread { return } self.perform_post_style_recalc_layout_passes(&reflow_info, + None, None, &mut *rw_data, &mut layout_context); @@ -1428,6 +1470,7 @@ impl LayoutThread { fn perform_post_style_recalc_layout_passes(&mut self, data: &Reflow, + query_type: Option<&ReflowQueryType>, document: Option<&ServoLayoutDocument>, rw_data: &mut LayoutThreadData, layout_context: &mut SharedLayoutContext) { @@ -1503,18 +1546,24 @@ impl LayoutThread { flow_ref::deref_mut(&mut root_flow) as &mut Flow); }); - self.perform_post_main_layout_passes(data, document, rw_data, layout_context); + self.perform_post_main_layout_passes(data, + query_type, + document, + rw_data, + layout_context); } } fn perform_post_main_layout_passes(&mut self, data: &Reflow, + query_type: Option<&ReflowQueryType>, document: Option<&ServoLayoutDocument>, rw_data: &mut LayoutThreadData, layout_context: &mut SharedLayoutContext) { // Build the display list if necessary, and send it to the painter. if let Some(mut root_flow) = self.root_flow.clone() { self.compute_abs_pos_and_build_display_list(data, + query_type, document, flow_ref::deref_mut(&mut root_flow), &mut *layout_context, @@ -1632,6 +1681,18 @@ fn get_ua_stylesheets() -> Result { }) } +/// Returns true if the given reflow query type needs a full, up-to-date display list to be present +/// or false if it only needs stacking-relative positions. +fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool { + match *query_type { + ReflowQueryType::HitTestQuery(..) => true, + ReflowQueryType::ContentBoxQuery(_) | ReflowQueryType::ContentBoxesQuery(_) | + ReflowQueryType::NodeGeometryQuery(_) | ReflowQueryType::NodeScrollGeometryQuery(_) | + ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::NodeLayerIdQuery(_) | + ReflowQueryType::ResolvedStyleQuery(..) | ReflowQueryType::OffsetParentQuery(_) | + ReflowQueryType::MarginStyleQuery(_) | ReflowQueryType::NoQuery => false, + } +} lazy_static! { static ref UA_STYLESHEETS: UserAgentStylesheets = { diff --git a/components/script_layout_interface/restyle_damage.rs b/components/script_layout_interface/restyle_damage.rs index ef33370e064..ff0e26af03f 100644 --- a/components/script_layout_interface/restyle_damage.rs +++ b/components/script_layout_interface/restyle_damage.rs @@ -15,31 +15,36 @@ bitflags! { #[doc = "Currently unused; need to decide how this propagates."] const REPAINT = 0x01, + #[doc = "The stacking-context-relative position of this node or its descendants has \ + changed."] + #[doc = "Propagates both up and down the flow tree."] + const REPOSITION = 0x02, + #[doc = "Recompute the overflow regions (bounding box of object and all descendants)."] #[doc = "Propagates down the flow tree because the computation is bottom-up."] - const STORE_OVERFLOW = 0x02, + const STORE_OVERFLOW = 0x04, #[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."] #[doc = "Propagates down the flow tree because the computation is"] #[doc = "bottom-up."] - const BUBBLE_ISIZES = 0x04, + const BUBBLE_ISIZES = 0x08, #[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \ into account. \ Propagates up the flow tree because the computation is top-down."] - const REFLOW_OUT_OF_FLOW = 0x08, + const REFLOW_OUT_OF_FLOW = 0x10, #[doc = "Recompute actual inline_sizes and block_sizes."] #[doc = "Propagates up the flow tree because the computation is"] #[doc = "top-down."] - const REFLOW = 0x10, + const REFLOW = 0x20, #[doc = "Re-resolve generated content. \ Propagates up the flow tree because the computation is inorder."] - const RESOLVE_GENERATED_CONTENT = 0x20, + const RESOLVE_GENERATED_CONTENT = 0x40, #[doc = "The entire flow needs to be reconstructed."] - const RECONSTRUCT_FLOW = 0x40 + const RECONSTRUCT_FLOW = 0x80 } } @@ -63,7 +68,8 @@ impl TRestyleDamage for RestyleDamage { /// `RestyleDamage::all()` will result in unnecessary sequential resolution /// of generated content. fn rebuild_and_reflow() -> RestyleDamage { - REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW + REPAINT | REPOSITION | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | + RECONSTRUCT_FLOW } } @@ -72,9 +78,10 @@ impl RestyleDamage { /// returns the damage that we should add to the *parent* of this flow. pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage { if child_is_absolutely_positioned { - self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT) + self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | + RESOLVE_GENERATED_CONTENT) } else { - self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW | + self & (REPAINT | REPOSITION | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT) } } @@ -90,7 +97,7 @@ impl RestyleDamage { // Absolute children are out-of-flow and therefore insulated from changes. // // FIXME(pcwalton): Au contraire, if the containing block dimensions change! - self & REPAINT + self & (REPAINT | REPOSITION) } (true, false) => { // Changing the position of an absolutely-positioned block requires us to reflow @@ -103,7 +110,7 @@ impl RestyleDamage { } _ => { // TODO(pcwalton): Take floatedness into account. - self & (REPAINT | REFLOW) + self & (REPAINT | REPOSITION | REFLOW) } } } @@ -115,6 +122,7 @@ impl fmt::Display for RestyleDamage { let to_iter = [ (REPAINT, "Repaint") + , (REPOSITION, "Reposition") , (STORE_OVERFLOW, "StoreOverflow") , (BUBBLE_ISIZES, "BubbleISizes") , (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow") @@ -163,14 +171,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty // FIXME: Test somehow that every property is included. add_if_not_equal!(old, new, damage, - [ - REPAINT, - STORE_OVERFLOW, - BUBBLE_ISIZES, - REFLOW_OUT_OF_FLOW, - REFLOW, - RECONSTRUCT_FLOW - ], [ + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, + REFLOW, RECONSTRUCT_FLOW], [ get_box.float, get_box.display, get_box.position, get_counters.content, get_counters.counter_reset, get_counters.counter_increment, get_inheritedbox._servo_under_display_none, @@ -191,8 +193,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty get_column.column_width, get_column.column_count ]) || (new.get_box().display == display::T::inline && add_if_not_equal!(old, new, damage, - [REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW, - RECONSTRUCT_FLOW], [ + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, + REFLOW_OUT_OF_FLOW, REFLOW, RECONSTRUCT_FLOW], [ // For inline boxes only, border/padding styles are used in flow construction (to decide // whether to create fragments for empty flows). get_border.border_top_width, get_border.border_right_width, @@ -200,7 +202,8 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty get_padding.padding_top, get_padding.padding_right, get_padding.padding_bottom, get_padding.padding_left ])) || add_if_not_equal!(old, new, damage, - [ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ], + [REPAINT, REPOSITION, STORE_OVERFLOW, BUBBLE_ISIZES, + REFLOW_OUT_OF_FLOW, REFLOW], [get_border.border_top_width, get_border.border_right_width, get_border.border_bottom_width, get_border.border_left_width, get_margin.margin_top, get_margin.margin_right, @@ -225,11 +228,14 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty get_position.flex_shrink, get_position.align_self ]) || add_if_not_equal!(old, new, damage, - [ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [ + [REPAINT, REPOSITION, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW], [ get_position.top, get_position.left, - get_position.right, get_position.bottom + get_position.right, get_position.bottom, + get_effects.opacity, + get_effects.transform, get_effects.transform_style, get_effects.transform_origin, + get_effects.perspective, get_effects.perspective_origin ]) || add_if_not_equal!(old, new, damage, - [ REPAINT ], [ + [REPAINT], [ get_color.color, get_background.background_color, get_background.background_image, get_background.background_position, get_background.background_repeat, get_background.background_attachment, @@ -245,9 +251,7 @@ fn compute_damage(old: &ServoComputedValues, new: &ServoComputedValues) -> Resty get_inheritedtext._servo_text_decorations_in_effect, get_pointing.cursor, get_pointing.pointer_events, get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter, - get_effects.transform, get_effects.backface_visibility, get_effects.transform_style, - get_effects.transform_origin, get_effects.perspective, get_effects.perspective_origin, - get_effects.mix_blend_mode, get_effects.opacity, get_inheritedbox.image_rendering, + get_effects.mix_blend_mode, get_inheritedbox.image_rendering, // Note: May require REFLOW et al. if `visibility: collapse` is implemented. get_inheritedbox.visibility