mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #6053 - pcwalton:displayports, r=glennw
This improves Servo's performance on large pages. Please double-check the logic when it comes to nested layers—I'm sure I've messed up some of the geometry calculations :) r? @glennw <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6053) <!-- Reviewable:end -->
This commit is contained in:
commit
0880e54f98
26 changed files with 340 additions and 66 deletions
|
@ -14,7 +14,7 @@ use windowing::{MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg}
|
|||
use geom::point::{Point2D, TypedPoint2D};
|
||||
use geom::rect::{Rect, TypedRect};
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::TypedSize2D;
|
||||
use geom::size::{Size2D, TypedSize2D};
|
||||
use gfx::color;
|
||||
use gfx::paint_task::Msg as PaintMsg;
|
||||
use gfx::paint_task::PaintRequest;
|
||||
|
@ -25,6 +25,7 @@ use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
|
|||
use layers::rendergl::RenderContext;
|
||||
use layers::rendergl;
|
||||
use layers::scene::Scene;
|
||||
use layout_traits::{LayoutControlChan, LayoutControlMsg};
|
||||
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId};
|
||||
use msg::compositor_msg::{LayerProperties, ScrollPolicy};
|
||||
use msg::constellation_msg::AnimationState;
|
||||
|
@ -45,7 +46,7 @@ use std::sync::mpsc::Sender;
|
|||
use style::viewport::ViewportConstraints;
|
||||
use time::{precise_time_ns, precise_time_s};
|
||||
use url::Url;
|
||||
use util::geometry::{PagePx, ScreenPx, ViewportPx};
|
||||
use util::geometry::{Au, PagePx, ScreenPx, ViewportPx};
|
||||
use util::opts;
|
||||
|
||||
/// Holds the state when running reftests that determines when it is
|
||||
|
@ -434,7 +435,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.remove_pipeline_root_layer(pipeline_id);
|
||||
}
|
||||
|
||||
(Msg::ViewportConstrained(pipeline_id, constraints), ShutdownState::NotShuttingDown) => {
|
||||
(Msg::ViewportConstrained(pipeline_id, constraints),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.constrain_viewport(pipeline_id, constraints);
|
||||
}
|
||||
|
||||
|
@ -701,7 +703,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
panic!("Compositor: Tried to scroll to fragment with unknown layer.");
|
||||
}
|
||||
|
||||
self.start_scrolling_timer_if_necessary();
|
||||
self.perform_updates_after_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -937,9 +939,57 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Computes new display ports for each layer, taking the scroll position into account, and
|
||||
/// sends them to layout as necessary. This ultimately triggers a rerender of the content.
|
||||
fn send_updated_display_ports_to_layout(&mut self) {
|
||||
fn process_layer(layer: &Layer<CompositorData>,
|
||||
window_size: &TypedSize2D<LayerPixel, f32>,
|
||||
new_display_ports: &mut HashMap<PipelineId, Vec<(LayerId, Rect<Au>)>>) {
|
||||
let visible_rect =
|
||||
Rect(Point2D::zero(), *window_size).translate(&-*layer.content_offset.borrow())
|
||||
.intersection(&*layer.bounds.borrow())
|
||||
.unwrap_or(Rect::zero())
|
||||
.to_untyped();
|
||||
let visible_rect = Rect(Point2D(Au::from_f32_px(visible_rect.origin.x),
|
||||
Au::from_f32_px(visible_rect.origin.y)),
|
||||
Size2D(Au::from_f32_px(visible_rect.size.width),
|
||||
Au::from_f32_px(visible_rect.size.height)));
|
||||
|
||||
let extra_layer_data = layer.extra_data.borrow();
|
||||
if !new_display_ports.contains_key(&extra_layer_data.pipeline_id) {
|
||||
new_display_ports.insert(extra_layer_data.pipeline_id, Vec::new());
|
||||
}
|
||||
new_display_ports.get_mut(&extra_layer_data.pipeline_id)
|
||||
.unwrap()
|
||||
.push((extra_layer_data.id, visible_rect));
|
||||
|
||||
for kid in layer.children.borrow().iter() {
|
||||
process_layer(&*kid, window_size, new_display_ports)
|
||||
}
|
||||
}
|
||||
|
||||
let dppx = self.page_zoom * self.device_pixels_per_screen_px();
|
||||
let window_size = self.window_size.as_f32() / dppx * ScaleFactor::new(1.0);
|
||||
let mut new_visible_rects = HashMap::new();
|
||||
if let Some(ref layer) = self.scene.root {
|
||||
process_layer(&**layer, &window_size, &mut new_visible_rects)
|
||||
}
|
||||
|
||||
for (pipeline_id, new_visible_rects) in new_visible_rects.iter() {
|
||||
if let Some(pipeline_details) = self.pipeline_details.get(&pipeline_id) {
|
||||
if let Some(ref pipeline) = pipeline_details.pipeline {
|
||||
let LayoutControlChan(ref sender) = pipeline.layout_chan;
|
||||
sender.send(LayoutControlMsg::SetVisibleRects((*new_visible_rects).clone()))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs buffer requests and starts the scrolling timer or schedules a recomposite as
|
||||
/// necessary.
|
||||
fn perform_updates_after_scroll(&mut self) {
|
||||
self.send_updated_display_ports_to_layout();
|
||||
if self.send_buffer_requests_for_all_layers() {
|
||||
self.start_scrolling_timer_if_necessary();
|
||||
} else {
|
||||
|
|
|
@ -52,6 +52,7 @@ pub struct Pipeline {
|
|||
pub struct CompositionPipeline {
|
||||
pub id: PipelineId,
|
||||
pub script_chan: ScriptControlChan,
|
||||
pub layout_chan: LayoutControlChan,
|
||||
pub paint_chan: PaintChan,
|
||||
}
|
||||
|
||||
|
@ -245,6 +246,7 @@ impl Pipeline {
|
|||
CompositionPipeline {
|
||||
id: self.id.clone(),
|
||||
script_chan: self.script_chan.clone(),
|
||||
layout_chan: self.layout_chan.clone(),
|
||||
paint_chan: self.paint_chan.clone(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -245,7 +245,10 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
|||
}
|
||||
|
||||
debug!("PaintTask: returning surfaces");
|
||||
self.compositor.assign_painted_buffers(self.id, self.current_epoch.unwrap(), replies, frame_tree_id);
|
||||
self.compositor.assign_painted_buffers(self.id,
|
||||
self.current_epoch.unwrap(),
|
||||
replies,
|
||||
frame_tree_id);
|
||||
}
|
||||
Msg::UnusedBuffer(unused_buffers) => {
|
||||
debug!("PaintTask {:?}: Received {} unused buffers", self.id, unused_buffers.len());
|
||||
|
|
|
@ -43,6 +43,7 @@ use flow::{CLEARS_LEFT, CLEARS_RIGHT};
|
|||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
use layout_debug;
|
||||
use layout_task::DISPLAY_PORT_SIZE_FACTOR;
|
||||
use model::{IntrinsicISizes, MarginCollapseInfo};
|
||||
use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
@ -59,7 +60,7 @@ use style::computed_values::{position, text_align};
|
|||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use style::values::computed::{LengthOrPercentageOrNone};
|
||||
use util::geometry::{Au, MAX_AU};
|
||||
use util::geometry::{Au, MAX_AU, MAX_RECT};
|
||||
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
||||
use util::opts;
|
||||
|
||||
|
@ -377,7 +378,9 @@ impl Iterator for CandidateBSizeIterator {
|
|||
Some(max_block_size) if self.candidate_value > max_block_size => {
|
||||
CandidateBSizeIteratorStatus::TryingMax
|
||||
}
|
||||
_ if self.candidate_value < self.min_block_size => CandidateBSizeIteratorStatus::TryingMin,
|
||||
_ if self.candidate_value < self.min_block_size => {
|
||||
CandidateBSizeIteratorStatus::TryingMin
|
||||
}
|
||||
_ => CandidateBSizeIteratorStatus::Found,
|
||||
}
|
||||
}
|
||||
|
@ -718,13 +721,16 @@ impl BlockFlow {
|
|||
return
|
||||
}
|
||||
|
||||
let (block_start_margin_value, block_end_margin_value) = match self.base.collapsible_margins {
|
||||
CollapsibleMargins::CollapseThrough(_) => panic!("Margins unexpectedly collapsed through root flow."),
|
||||
CollapsibleMargins::Collapse(block_start_margin, block_end_margin) => {
|
||||
(block_start_margin.collapse(), block_end_margin.collapse())
|
||||
}
|
||||
CollapsibleMargins::None(block_start, block_end) => (block_start, block_end),
|
||||
};
|
||||
let (block_start_margin_value, block_end_margin_value) =
|
||||
match self.base.collapsible_margins {
|
||||
CollapsibleMargins::CollapseThrough(_) => {
|
||||
panic!("Margins unexpectedly collapsed through root flow.")
|
||||
}
|
||||
CollapsibleMargins::Collapse(block_start_margin, block_end_margin) => {
|
||||
(block_start_margin.collapse(), block_end_margin.collapse())
|
||||
}
|
||||
CollapsibleMargins::None(block_start, block_end) => (block_start, block_end),
|
||||
};
|
||||
|
||||
// Shift all kids down (or up, if margins are negative) if necessary.
|
||||
if block_start_margin_value != Au(0) {
|
||||
|
@ -757,7 +763,8 @@ impl BlockFlow {
|
|||
pub fn assign_block_size_block_base<'a>(&mut self,
|
||||
layout_context: &'a LayoutContext<'a>,
|
||||
margins_may_collapse: MarginsMayCollapseFlag) {
|
||||
let _scope = layout_debug_scope!("assign_block_size_block_base {:x}", self.base.debug_id());
|
||||
let _scope = layout_debug_scope!("assign_block_size_block_base {:x}",
|
||||
self.base.debug_id());
|
||||
|
||||
if self.base.restyle_damage.contains(REFLOW) {
|
||||
// Our current border-box position.
|
||||
|
@ -1661,13 +1668,14 @@ impl Flow for BlockFlow {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
// FIXME (mbrubeck): Get the real container size, taking the container writing mode into
|
||||
// account. Must handle vertical writing modes.
|
||||
let container_size = Size2D(self.base.block_container_inline_size, Au(0));
|
||||
|
||||
if self.is_root() {
|
||||
self.base.clip = ClippingRegion::max()
|
||||
self.base.clip = ClippingRegion::max();
|
||||
self.base.stacking_relative_position_of_display_port = MAX_RECT;
|
||||
}
|
||||
|
||||
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
|
@ -1761,7 +1769,8 @@ impl Flow for BlockFlow {
|
|||
let relative_offset = relative_offset.to_physical(self.base.writing_mode);
|
||||
let origin_for_children;
|
||||
let clip_in_child_coordinate_system;
|
||||
if self.fragment.establishes_stacking_context() {
|
||||
let is_stacking_context = self.fragment.establishes_stacking_context();
|
||||
if is_stacking_context {
|
||||
// We establish a stacking context, so the position of our children is vertically
|
||||
// correct, but has to be adjusted to accommodate horizontal margins. (Note the
|
||||
// calculation involving `position` below and recall that inline-direction flow
|
||||
|
@ -1771,11 +1780,31 @@ impl Flow for BlockFlow {
|
|||
let margin = self.fragment.margin.to_physical(self.base.writing_mode);
|
||||
origin_for_children = Point2D(-margin.left, Au(0)) + relative_offset;
|
||||
clip_in_child_coordinate_system =
|
||||
self.base.clip.translate(&-self.base.stacking_relative_position)
|
||||
self.base.clip.translate(&-self.base.stacking_relative_position);
|
||||
} else {
|
||||
origin_for_children = self.base.stacking_relative_position + relative_offset;
|
||||
clip_in_child_coordinate_system = self.base.clip.clone()
|
||||
clip_in_child_coordinate_system = self.base.clip.clone();
|
||||
}
|
||||
|
||||
let stacking_relative_position_of_display_port_for_children =
|
||||
if (is_stacking_context && self.will_get_layer()) || self.is_root() {
|
||||
let visible_rect =
|
||||
match layout_context.shared.visible_rects.get(&self.layer_id(0)) {
|
||||
Some(visible_rect) => *visible_rect,
|
||||
None => Rect(Point2D::zero(), layout_context.shared.screen_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)
|
||||
} else if is_stacking_context {
|
||||
self.base
|
||||
.stacking_relative_position_of_display_port
|
||||
.translate(&-self.base.stacking_relative_position)
|
||||
} else {
|
||||
self.base.stacking_relative_position_of_display_port
|
||||
};
|
||||
|
||||
let stacking_relative_border_box =
|
||||
self.fragment
|
||||
.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
|
@ -1820,7 +1849,9 @@ impl Flow for BlockFlow {
|
|||
}
|
||||
|
||||
flow::mut_base(kid).absolute_position_info = absolute_position_info_for_children;
|
||||
flow::mut_base(kid).clip = clip.clone()
|
||||
flow::mut_base(kid).clip = clip.clone();
|
||||
flow::mut_base(kid).stacking_relative_position_of_display_port =
|
||||
stacking_relative_position_of_display_port_for_children;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,21 @@ use geom::{Rect, Size2D};
|
|||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use gfx::font_context::FontContext;
|
||||
use msg::compositor_msg::LayerId;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState};
|
||||
use script::layout_interface::{Animation, LayoutChan, ReflowGoal};
|
||||
use std::boxed;
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_state::DefaultState;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use style::selector_matching::Stylist;
|
||||
use url::Url;
|
||||
use util::fnv::FnvHasher;
|
||||
use util::geometry::Au;
|
||||
use util::opts;
|
||||
|
||||
|
@ -99,6 +103,9 @@ pub struct SharedLayoutContext {
|
|||
/// sent.
|
||||
pub new_animations_sender: Sender<Animation>,
|
||||
|
||||
/// The visible rects for each layer, as reported to us by the compositor.
|
||||
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
|
||||
|
||||
/// Why is this reflow occurring
|
||||
pub goal: ReflowGoal,
|
||||
}
|
||||
|
|
|
@ -176,6 +176,8 @@ pub trait FragmentDisplayListBuilding {
|
|||
/// * `relative_containing_block_size`: The size of the containing block that
|
||||
/// `position: relative` makes use of.
|
||||
/// * `clip`: The region to clip the display items to.
|
||||
/// * `stacking_relative_display_port`: The position and size of the display port with respect
|
||||
/// to the nearest ancestor stacking context.
|
||||
fn build_display_list(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
|
@ -184,7 +186,8 @@ pub trait FragmentDisplayListBuilding {
|
|||
relative_containing_block_mode: WritingMode,
|
||||
border_painting_mode: BorderPaintingMode,
|
||||
background_and_border_level: BackgroundAndBorderLevel,
|
||||
clip: &ClippingRegion);
|
||||
clip: &ClippingRegion,
|
||||
stacking_relative_display_port: &Rect<Au>);
|
||||
|
||||
/// Sends the size and position of this iframe fragment to the constellation. This is out of
|
||||
/// line to guide inlining.
|
||||
|
@ -866,7 +869,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
relative_containing_block_mode: WritingMode,
|
||||
border_painting_mode: BorderPaintingMode,
|
||||
background_and_border_level: BackgroundAndBorderLevel,
|
||||
clip: &ClippingRegion) {
|
||||
clip: &ClippingRegion,
|
||||
stacking_relative_display_port: &Rect<Au>) {
|
||||
if self.style().get_inheritedbox().visibility != visibility::T::visible {
|
||||
return
|
||||
}
|
||||
|
@ -888,6 +892,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
stacking_relative_flow_origin,
|
||||
self);
|
||||
|
||||
if !stacking_relative_border_box.intersects(stacking_relative_display_port) {
|
||||
debug!("Fragment::build_display_list: outside display port");
|
||||
return
|
||||
}
|
||||
|
||||
if !stacking_relative_border_box.intersects(&layout_context.shared.dirty) {
|
||||
debug!("Fragment::build_display_list: Did not intersect...");
|
||||
return
|
||||
|
@ -1076,7 +1085,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let (sender, receiver) = channel::<Vec<u8>>();
|
||||
let canvas_data = match canvas_fragment_info.renderer {
|
||||
Some(ref renderer) => {
|
||||
renderer.lock().unwrap().send(CanvasMsg::Common(CanvasCommonMsg::SendPixelContents(sender))).unwrap();
|
||||
renderer.lock().unwrap().send(CanvasMsg::Common(
|
||||
CanvasCommonMsg::SendPixelContents(sender))).unwrap();
|
||||
receiver.recv().unwrap()
|
||||
},
|
||||
None => repeat(0xFFu8).take(width * height * 4).collect(),
|
||||
|
@ -1364,6 +1374,7 @@ pub trait BlockFlowDisplayListBuilding {
|
|||
display_list: Box<DisplayList>,
|
||||
layout_context: &LayoutContext,
|
||||
border_painting_mode: BorderPaintingMode);
|
||||
fn will_get_layer(&self) -> bool;
|
||||
}
|
||||
|
||||
impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||
|
@ -1386,7 +1397,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
self.base.absolute_position_info.relative_containing_block_mode,
|
||||
border_painting_mode,
|
||||
background_border_level,
|
||||
&clip);
|
||||
&clip,
|
||||
&self.base.stacking_relative_position_of_display_port);
|
||||
|
||||
// Add children.
|
||||
for kid in self.base.children.iter_mut() {
|
||||
|
@ -1422,6 +1434,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
}
|
||||
}
|
||||
|
||||
fn will_get_layer(&self) -> bool {
|
||||
self.base.absolute_position_info.layers_needed_for_positioned_flows ||
|
||||
self.base.flags.contains(NEEDS_LAYER)
|
||||
}
|
||||
|
||||
fn build_display_list_for_absolutely_positioned_block(
|
||||
&mut self,
|
||||
mut display_list: Box<DisplayList>,
|
||||
|
@ -1432,8 +1449,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
border_painting_mode,
|
||||
BackgroundAndBorderLevel::RootOfStackingContext);
|
||||
|
||||
if !self.base.absolute_position_info.layers_needed_for_positioned_flows &&
|
||||
!self.base.flags.contains(NEEDS_LAYER) {
|
||||
if !self.will_get_layer() {
|
||||
// We didn't need a layer.
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
|
||||
|
@ -1524,7 +1540,8 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
.relative_containing_block_mode,
|
||||
BorderPaintingMode::Separate,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.base.clip);
|
||||
&self.base.clip,
|
||||
&self.base.stacking_relative_position_of_display_port);
|
||||
|
||||
has_stacking_context = fragment.establishes_stacking_context();
|
||||
match fragment.specific {
|
||||
|
@ -1597,7 +1614,10 @@ impl ListItemFlowDisplayListBuilding for ListItemFlow {
|
|||
.relative_containing_block_mode,
|
||||
BorderPaintingMode::Separate,
|
||||
BackgroundAndBorderLevel::Content,
|
||||
&self.block_flow.base.clip);
|
||||
&self.block_flow.base.clip,
|
||||
&self.block_flow
|
||||
.base
|
||||
.stacking_relative_position_of_display_port);
|
||||
}
|
||||
|
||||
// Draw the rest of the block.
|
||||
|
|
|
@ -271,7 +271,7 @@ pub trait Flow: fmt::Debug + Sync {
|
|||
}
|
||||
|
||||
/// Phase 4 of reflow: computes absolute positions.
|
||||
fn compute_absolute_position(&mut self) {
|
||||
fn compute_absolute_position(&mut self, _: &LayoutContext) {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
|
||||
|
@ -859,6 +859,12 @@ pub struct BaseFlow {
|
|||
/// The clipping region for this flow and its descendants, in layer coordinates.
|
||||
pub clip: ClippingRegion,
|
||||
|
||||
/// The stacking-relative position of the display port.
|
||||
///
|
||||
/// FIXME(pcwalton): This might be faster as an Arc, since this varies only
|
||||
/// per-stacking-context.
|
||||
pub stacking_relative_position_of_display_port: Rect<Au>,
|
||||
|
||||
/// The results of display list building for this flow.
|
||||
pub display_list_building_result: DisplayListBuildingResult,
|
||||
|
||||
|
@ -909,10 +915,18 @@ impl Encodable for BaseFlow {
|
|||
FlowClass::Block => c.as_immutable_block().encode(e),
|
||||
FlowClass::Inline => c.as_immutable_inline().encode(e),
|
||||
FlowClass::Table => c.as_immutable_table().encode(e),
|
||||
FlowClass::TableWrapper => c.as_immutable_table_wrapper().encode(e),
|
||||
FlowClass::TableRowGroup => c.as_immutable_table_rowgroup().encode(e),
|
||||
FlowClass::TableRow => c.as_immutable_table_row().encode(e),
|
||||
FlowClass::TableCell => c.as_immutable_table_cell().encode(e),
|
||||
FlowClass::TableWrapper => {
|
||||
c.as_immutable_table_wrapper().encode(e)
|
||||
}
|
||||
FlowClass::TableRowGroup => {
|
||||
c.as_immutable_table_rowgroup().encode(e)
|
||||
}
|
||||
FlowClass::TableRow => {
|
||||
c.as_immutable_table_row().encode(e)
|
||||
}
|
||||
FlowClass::TableCell => {
|
||||
c.as_immutable_table_cell().encode(e)
|
||||
}
|
||||
_ => { Ok(()) } // TODO: Support captions
|
||||
}
|
||||
})
|
||||
|
@ -1024,6 +1038,7 @@ impl BaseFlow {
|
|||
display_list_building_result: DisplayListBuildingResult::None,
|
||||
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
|
||||
clip: ClippingRegion::max(),
|
||||
stacking_relative_position_of_display_port: Rect::zero(),
|
||||
flags: flags,
|
||||
writing_mode: writing_mode,
|
||||
thread_id: 0,
|
||||
|
|
|
@ -1464,7 +1464,7 @@ impl Flow for InlineFlow {
|
|||
self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
fn compute_absolute_position(&mut self, _: &LayoutContext) {
|
||||
// First, gather up the positions of all the containing blocks (if any).
|
||||
let mut containing_block_positions = Vec::new();
|
||||
let container_size = Size2D(self.base.block_container_inline_size, Au(0));
|
||||
|
@ -1504,14 +1504,18 @@ impl Flow for InlineFlow {
|
|||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin
|
||||
stacking_relative_border_box.origin;
|
||||
block_flow.base.stacking_relative_position_of_display_port =
|
||||
self.base.stacking_relative_position_of_display_port;
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin
|
||||
stacking_relative_border_box.origin;
|
||||
block_flow.base.stacking_relative_position_of_display_port =
|
||||
self.base.stacking_relative_position_of_display_port;
|
||||
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
|
||||
|
@ -1528,7 +1532,9 @@ impl Flow for InlineFlow {
|
|||
stacking_relative_position + *padding_box_origin;
|
||||
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin
|
||||
stacking_relative_border_box.origin;
|
||||
block_flow.base.stacking_relative_position_of_display_port =
|
||||
self.base.stacking_relative_position_of_display_port;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ use animation;
|
|||
use construct::ConstructionResult;
|
||||
use context::{SharedLayoutContext, SharedLayoutContextWrapper};
|
||||
use css::node_style::StyledNode;
|
||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use display_list_builder::ToGfxColor;
|
||||
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
|
||||
use data::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use layout_debug;
|
||||
use opaque_node::OpaqueNodeMethods;
|
||||
use parallel::{self, UnsafeFlow};
|
||||
|
@ -39,7 +39,7 @@ use gfx::paint_task::Msg as PaintMsg;
|
|||
use gfx::paint_task::{PaintChan, PaintLayer};
|
||||
use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
|
||||
use log;
|
||||
use msg::compositor_msg::{Epoch, ScrollPolicy};
|
||||
use msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
|
||||
use profile_traits::mem::{self, Report, ReportsChan};
|
||||
|
@ -57,6 +57,8 @@ use script_traits::{ConstellationControlMsg, OpaqueScriptLayoutChannel};
|
|||
use script_traits::{ScriptControlChan, StylesheetLoadResponder};
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_state::DefaultState;
|
||||
use std::mem::transmute;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
|
@ -69,6 +71,7 @@ use style::selector_matching::Stylist;
|
|||
use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt};
|
||||
use url::Url;
|
||||
use util::cursor::Cursor;
|
||||
use util::fnv::FnvHasher;
|
||||
use util::geometry::{Au, MAX_RECT};
|
||||
use util::logical_geometry::LogicalPoint;
|
||||
use util::mem::HeapSizeOf;
|
||||
|
@ -77,6 +80,12 @@ use util::task::spawn_named_with_send_on_failure;
|
|||
use util::task_state;
|
||||
use util::workqueue::WorkQueue;
|
||||
|
||||
/// The number of screens of data we're allowed to generate display lists for in each direction.
|
||||
pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
|
||||
|
||||
/// The number of screens we have to traverse before we decide to generate new display lists.
|
||||
const DISPLAY_PORT_THRESHOLD_SIZE_FACTOR: i32 = 4;
|
||||
|
||||
/// Mutable data belonging to the LayoutTask.
|
||||
///
|
||||
/// This needs to be protected by a mutex so we can do fast RPCs.
|
||||
|
@ -125,8 +134,12 @@ pub struct LayoutTaskData {
|
|||
/// sent.
|
||||
pub new_animations_sender: Sender<Animation>,
|
||||
|
||||
/// A counter for epoch messages
|
||||
/// A counter for epoch messages.
|
||||
epoch: Epoch,
|
||||
|
||||
/// The position and size of the visible rect for each layer. We do not build display lists
|
||||
/// for any areas more than `DISPLAY_PORT_SIZE_FACTOR` screens away from this area.
|
||||
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
|
||||
}
|
||||
|
||||
/// Information needed by the layout task.
|
||||
|
@ -330,6 +343,7 @@ impl LayoutTask {
|
|||
content_box_response: Rect::zero(),
|
||||
content_boxes_response: Vec::new(),
|
||||
running_animations: Vec::new(),
|
||||
visible_rects: Arc::new(HashMap::with_hash_state(Default::default())),
|
||||
new_animations_receiver: new_animations_receiver,
|
||||
new_animations_sender: new_animations_sender,
|
||||
epoch: Epoch(0),
|
||||
|
@ -365,6 +379,7 @@ impl LayoutTask {
|
|||
url: (*url).clone(),
|
||||
reflow_root: reflow_root.map(|node| OpaqueNodeMethods::from_layout_node(node)),
|
||||
dirty: Rect::zero(),
|
||||
visible_rects: rw_data.visible_rects.clone(),
|
||||
generation: rw_data.generation,
|
||||
new_animations_sender: rw_data.new_animations_sender.clone(),
|
||||
goal: goal,
|
||||
|
@ -406,6 +421,10 @@ impl LayoutTask {
|
|||
match port_to_read {
|
||||
PortToRead::Pipeline => {
|
||||
match self.pipeline_port.recv().unwrap() {
|
||||
LayoutControlMsg::SetVisibleRects(new_visible_rects) => {
|
||||
self.handle_request_helper(Msg::SetVisibleRects(new_visible_rects),
|
||||
possibly_locked_rw_data)
|
||||
}
|
||||
LayoutControlMsg::TickAnimations => {
|
||||
self.handle_request_helper(Msg::TickAnimations, possibly_locked_rw_data)
|
||||
}
|
||||
|
@ -509,6 +528,9 @@ impl LayoutTask {
|
|||
|| self.handle_reflow(&*data, possibly_locked_rw_data));
|
||||
},
|
||||
Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
|
||||
Msg::SetVisibleRects(new_visible_rects) => {
|
||||
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
|
||||
}
|
||||
Msg::ReapLayoutData(dead_layout_data) => {
|
||||
unsafe {
|
||||
self.handle_reap_layout_data(dead_layout_data)
|
||||
|
@ -964,6 +986,64 @@ impl LayoutTask {
|
|||
chan.send(ConstellationControlMsg::ReflowComplete(self.id, data.id)).unwrap();
|
||||
}
|
||||
|
||||
fn set_visible_rects<'a>(&'a self,
|
||||
new_visible_rects: Vec<(LayerId, Rect<Au>)>,
|
||||
possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>)
|
||||
-> bool {
|
||||
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||
|
||||
// First, determine if we need to regenerate the display lists. This will happen if the
|
||||
// layers have moved more than `DISPLAY_PORT_THRESHOLD_SIZE_FACTOR` away from their last
|
||||
// positions.
|
||||
let mut must_regenerate_display_lists = false;
|
||||
let mut old_visible_rects = HashMap::with_hash_state(Default::default());
|
||||
let inflation_amount =
|
||||
Size2D(rw_data.screen_size.width * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR,
|
||||
rw_data.screen_size.height * DISPLAY_PORT_THRESHOLD_SIZE_FACTOR);
|
||||
for &(ref layer_id, ref new_visible_rect) in new_visible_rects.iter() {
|
||||
match rw_data.visible_rects.get(layer_id) {
|
||||
None => {
|
||||
old_visible_rects.insert(*layer_id, *new_visible_rect);
|
||||
}
|
||||
Some(old_visible_rect) => {
|
||||
old_visible_rects.insert(*layer_id, *old_visible_rect);
|
||||
|
||||
if !old_visible_rect.inflate(inflation_amount.width, inflation_amount.height)
|
||||
.intersects(new_visible_rect) {
|
||||
must_regenerate_display_lists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !must_regenerate_display_lists {
|
||||
// Update `visible_rects` in case there are new layers that were discovered.
|
||||
rw_data.visible_rects = Arc::new(old_visible_rects);
|
||||
return true
|
||||
}
|
||||
|
||||
debug!("regenerating display lists!");
|
||||
for &(ref layer_id, ref new_visible_rect) in new_visible_rects.iter() {
|
||||
old_visible_rects.insert(*layer_id, *new_visible_rect);
|
||||
}
|
||||
rw_data.visible_rects = Arc::new(old_visible_rects);
|
||||
|
||||
// Regenerate the display lists.
|
||||
let reflow_info = Reflow {
|
||||
goal: ReflowGoal::ForDisplay,
|
||||
page_clip_rect: MAX_RECT,
|
||||
};
|
||||
|
||||
let mut layout_context = self.build_shared_layout_context(&*rw_data,
|
||||
false,
|
||||
None,
|
||||
&self.url,
|
||||
reflow_info.goal);
|
||||
|
||||
self.perform_post_main_layout_passes(&reflow_info, &mut *rw_data, &mut layout_context);
|
||||
true
|
||||
}
|
||||
|
||||
fn tick_all_animations<'a>(&'a self,
|
||||
possibly_locked_rw_data: &mut Option<MutexGuard<'a,
|
||||
LayoutTaskData>>) {
|
||||
|
@ -1045,7 +1125,15 @@ impl LayoutTask {
|
|||
}
|
||||
});
|
||||
|
||||
self.perform_post_main_layout_passes(data, rw_data, layout_context);
|
||||
}
|
||||
|
||||
fn perform_post_main_layout_passes<'a>(&'a self,
|
||||
data: &Reflow,
|
||||
rw_data: &mut LayoutTaskData,
|
||||
layout_context: &mut SharedLayoutContext) {
|
||||
// Build the display list if necessary, and send it to the painter.
|
||||
let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
|
||||
self.compute_abs_pos_and_build_display_list(data,
|
||||
&mut root_flow,
|
||||
&mut *layout_context,
|
||||
|
|
|
@ -117,8 +117,8 @@ impl Flow for ListItemFlow {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn place_float_if_applicable<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
|
|
|
@ -63,8 +63,8 @@ impl Flow for MulticolFlow {
|
|||
self.block_flow.assign_block_size(ctx);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -503,8 +503,8 @@ impl Flow for TableFlow {
|
|||
self.block_flow.assign_block_size_for_table_like_flow(layout_context, vertical_spacing)
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
|
|
|
@ -59,13 +59,13 @@ impl Flow for TableCaptionFlow {
|
|||
self.block_flow.assign_inline_sizes(ctx);
|
||||
}
|
||||
|
||||
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
||||
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
debug!("assign_block_size: assigning block_size for table_caption");
|
||||
self.block_flow.assign_block_size(ctx);
|
||||
self.block_flow.assign_block_size(layout_context);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -160,13 +160,13 @@ impl Flow for TableCellFlow {
|
|||
|_, _, _, _, _, _| {});
|
||||
}
|
||||
|
||||
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
||||
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
debug!("assign_block_size: assigning block_size for table_cell");
|
||||
self.assign_block_size_table_cell_base(ctx);
|
||||
self.assign_block_size_table_cell_base(layout_context);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -403,8 +403,8 @@ impl Flow for TableRowFlow {
|
|||
self.assign_block_size_table_row_base(layout_context);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -203,8 +203,8 @@ impl Flow for TableRowGroupFlow {
|
|||
self.spacing.vertical)
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -381,8 +381,8 @@ impl Flow for TableWrapperFlow {
|
|||
MarginsMayCollapseFlag::MarginsMayNotCollapse);
|
||||
}
|
||||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
self.block_flow.compute_absolute_position()
|
||||
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
|
||||
self.block_flow.compute_absolute_position(layout_context)
|
||||
}
|
||||
|
||||
fn place_float_if_applicable<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
|
||||
|
|
|
@ -364,7 +364,7 @@ pub struct ComputeAbsolutePositions<'a> {
|
|||
impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
|
||||
#[inline]
|
||||
fn process(&self, flow: &mut Flow) {
|
||||
flow.compute_absolute_position();
|
||||
flow.compute_absolute_position(self.layout_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ authors = ["The Servo Project Developers"]
|
|||
name = "layout_traits"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies.geom]
|
||||
git = "https://github.com/servo/rust-geom"
|
||||
|
||||
[dependencies.gfx]
|
||||
path = "../gfx"
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
extern crate geom;
|
||||
extern crate gfx;
|
||||
extern crate script_traits;
|
||||
extern crate msg;
|
||||
|
@ -15,25 +16,29 @@ extern crate util;
|
|||
// The traits are here instead of in layout so
|
||||
// that these modules won't have to depend on layout.
|
||||
|
||||
use geom::rect::Rect;
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use gfx::paint_task::PaintChan;
|
||||
use msg::compositor_msg::Epoch;
|
||||
use msg::compositor_msg::{Epoch, LayerId};
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId, PipelineExitType};
|
||||
use profile_traits::mem;
|
||||
use profile_traits::time;
|
||||
use net_traits::image_cache_task::ImageCacheTask;
|
||||
use url::Url;
|
||||
use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel};
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
use util::geometry::Au;
|
||||
use url::Url;
|
||||
|
||||
/// Messages sent to the layout task from the constellation
|
||||
/// Messages sent to the layout task from the constellation and/or compositor.
|
||||
pub enum LayoutControlMsg {
|
||||
ExitNow(PipelineExitType),
|
||||
GetCurrentEpoch(Sender<Epoch>),
|
||||
TickAnimations,
|
||||
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
||||
}
|
||||
|
||||
/// A channel wrapper for constellation messages
|
||||
#[derive(Clone)]
|
||||
pub struct LayoutControlChan(pub Sender<LayoutControlMsg>);
|
||||
|
||||
// A static method creating a layout task
|
||||
|
|
|
@ -34,7 +34,7 @@ impl FrameTreeId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Copy)]
|
||||
#[derive(Clone, PartialEq, Eq, Copy, Hash)]
|
||||
pub struct LayerId(pub usize, pub u32);
|
||||
|
||||
impl Debug for LayerId {
|
||||
|
|
|
@ -11,6 +11,7 @@ use dom::node::LayoutData;
|
|||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use libc::uintptr_t;
|
||||
use msg::compositor_msg::LayerId;
|
||||
use msg::constellation_msg::{PipelineExitType, WindowSizeData};
|
||||
use msg::compositor_msg::Epoch;
|
||||
use net_traits::PendingAsyncLoad;
|
||||
|
@ -47,6 +48,10 @@ pub enum Msg {
|
|||
/// Requests that the layout task render the next frame of all animations.
|
||||
TickAnimations,
|
||||
|
||||
/// Updates the layout visible rects, affecting the area that display lists will be constructed
|
||||
/// for.
|
||||
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
||||
|
||||
/// Destroys layout data associated with a DOM node.
|
||||
///
|
||||
/// TODO(pcwalton): Maybe think about batching to avoid message traffic.
|
||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -674,6 +674,7 @@ dependencies = [
|
|||
name = "layout_traits"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||
"gfx 0.0.1",
|
||||
"msg 0.0.1",
|
||||
"net_traits 0.0.1",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue