aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/layout_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/layout_task.rs')
-rw-r--r--components/layout/layout_task.rs156
1 files changed, 90 insertions, 66 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 4d8885cf8ed..48941a0d336 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -13,8 +13,7 @@ use flow_ref::FlowRef;
use fragment::{Fragment, FragmentBoundsIterator};
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
use layout_debug;
-use parallel::UnsafeFlow;
-use parallel;
+use parallel::{mod, UnsafeFlow};
use sequential;
use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
@@ -26,7 +25,7 @@ use geom::rect::Rect;
use geom::size::Size2D;
use geom::scale_factor::ScaleFactor;
use gfx::color;
-use gfx::display_list::{DisplayList, OpaqueNode, StackingContext};
+use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, StackingContext};
use gfx::font_cache_task::FontCacheTask;
use gfx::paint_task::{mod, PaintInitMsg, PaintChan, PaintLayer};
use layout_traits;
@@ -40,22 +39,25 @@ use script::layout_interface::{ContentBoxesQuery, ContentBoxQuery, ExitNowMsg, G
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, LoadStylesheetMsg};
use script::layout_interface::{MouseOverResponse, Msg, NoQuery, PrepareToExitMsg};
use script::layout_interface::{ReapLayoutDataMsg, Reflow, ReflowForDisplay, ReflowMsg};
-use script::layout_interface::{ScriptLayoutChan, SetQuirksModeMsg, TrustedNodeAddress};
+use script::layout_interface::{ReflowForScriptQuery, ScriptLayoutChan, SetQuirksModeMsg};
+use script::layout_interface::{TrustedNodeAddress};
use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel};
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
use servo_msg::compositor_msg::Scrollable;
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg};
+use servo_msg::constellation_msg::{SetCursorMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_net::resource_task::{ResourceTask, load_bytes_iter};
+use servo_util::cursor::DefaultCursor;
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalPoint;
use servo_util::opts;
use servo_util::smallvec::{SmallVec, SmallVec1, VecLike};
use servo_util::task::spawn_named_with_send_on_failure;
use servo_util::task_state;
-use servo_util::time::{TimeProfilerChan, profile, TimerMetadataFrameType, TimerMetadataReflowType};
-use servo_util::time;
+use servo_util::time::{mod, ProfilerMetadata, TimeProfilerChan, TimerMetadataFrameType};
+use servo_util::time::{TimerMetadataReflowType, profile};
use servo_util::workqueue::WorkQueue;
use std::cell::Cell;
use std::comm::{channel, Sender, Receiver, Select};
@@ -73,6 +75,9 @@ pub struct LayoutTaskData {
/// The local image cache.
pub local_image_cache: Arc<Mutex<LocalImageCache<UntrustedNodeAddress>>>,
+ /// The channel on which messages can be sent to the constellation.
+ pub constellation_chan: ConstellationChan,
+
/// The size of the viewport.
pub screen_size: Size2D<Au>,
@@ -112,9 +117,6 @@ pub struct LayoutTask {
//// The channel to send messages to ourself.
pub chan: LayoutChan,
- /// The channel on which messages can be sent to the constellation.
- pub constellation_chan: ConstellationChan,
-
/// The channel on which messages can be sent to the script task.
pub script_chan: ScriptControlChan,
@@ -262,7 +264,6 @@ impl LayoutTask {
port: port,
pipeline_port: pipeline_port,
chan: chan,
- constellation_chan: constellation_chan,
script_chan: script_chan,
paint_chan: paint_chan,
time_profiler_chan: time_profiler_chan,
@@ -273,6 +274,7 @@ impl LayoutTask {
rw_data: Arc::new(Mutex::new(
LayoutTaskData {
local_image_cache: local_image_cache,
+ constellation_chan: constellation_chan,
screen_size: screen_size,
stacking_context: None,
stylist: box Stylist::new(device),
@@ -302,7 +304,7 @@ impl LayoutTask {
SharedLayoutContext {
image_cache: rw_data.local_image_cache.clone(),
screen_size: rw_data.screen_size.clone(),
- constellation_chan: self.constellation_chan.clone(),
+ constellation_chan: rw_data.constellation_chan.clone(),
layout_chan: self.chan.clone(),
font_cache_task: self.font_cache_task.clone(),
stylist: &*rw_data.stylist,
@@ -397,9 +399,7 @@ impl LayoutTask {
},
ReflowMsg(data) => {
profile(time::LayoutPerformCategory,
- Some((&data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental })),
+ self.profiler_metadata(&*data),
self.time_profiler_chan.clone(),
|| self.handle_reflow(&*data, possibly_locked_rw_data));
},
@@ -573,9 +573,7 @@ impl LayoutTask {
// NOTE: this currently computes borders, so any pruning should separate that
// operation out.
parallel::traverse_flow_tree_preorder(layout_root,
- &data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental },
+ self.profiler_metadata(data),
self.time_profiler_chan.clone(),
shared_layout_context,
traversal);
@@ -624,16 +622,14 @@ impl LayoutTask {
data: &Reflow,
node: &mut LayoutNode,
layout_root: &mut FlowRef,
- shared_layout_ctx: &mut SharedLayoutContext,
+ shared_layout_context: &mut SharedLayoutContext,
rw_data: &mut RWGuard<'a>) {
let writing_mode = flow::base(&**layout_root).writing_mode;
profile(time::LayoutDispListBuildCategory,
- Some((&data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental })),
- self.time_profiler_chan.clone(),
- || {
- shared_layout_ctx.dirty =
+ self.profiler_metadata(data),
+ self.time_profiler_chan.clone(),
+ || {
+ shared_layout_context.dirty =
flow::base(&**layout_root).position.to_physical(writing_mode,
rw_data.screen_size);
flow::mut_base(&mut **layout_root).stacking_relative_position =
@@ -645,15 +641,13 @@ impl LayoutTask {
let rw_data = rw_data.deref_mut();
match rw_data.parallel_traversal {
None => {
- sequential::build_display_list_for_subtree(layout_root, shared_layout_ctx);
+ sequential::build_display_list_for_subtree(layout_root, shared_layout_context);
}
Some(ref mut traversal) => {
parallel::build_display_list_for_subtree(layout_root,
- &data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental },
+ self.profiler_metadata(data),
self.time_profiler_chan.clone(),
- shared_layout_ctx,
+ shared_layout_context,
traversal);
}
}
@@ -746,9 +740,9 @@ impl LayoutTask {
rw_data.screen_size = current_screen_size;
// Create a layout context for use throughout the following passes.
- let mut shared_layout_ctx = self.build_shared_layout_context(rw_data.deref(),
- node,
- &data.url);
+ let mut shared_layout_context = self.build_shared_layout_context(rw_data.deref(),
+ node,
+ &data.url);
// Handle conditions where the entire flow tree is invalid.
let screen_size_changed = current_screen_size != old_screen_size;
@@ -775,19 +769,17 @@ impl LayoutTask {
}
let mut layout_root = profile(time::LayoutStyleRecalcCategory,
- Some((&data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental })),
+ self.profiler_metadata(data),
self.time_profiler_chan.clone(),
|| {
// Perform CSS selector matching and flow construction.
let rw_data = rw_data.deref_mut();
match rw_data.parallel_traversal {
None => {
- sequential::traverse_dom_preorder(*node, &shared_layout_ctx);
+ sequential::traverse_dom_preorder(*node, &shared_layout_context);
}
Some(ref mut traversal) => {
- parallel::traverse_dom_preorder(*node, &shared_layout_ctx, traversal)
+ parallel::traverse_dom_preorder(*node, &shared_layout_context, traversal)
}
}
@@ -795,13 +787,12 @@ impl LayoutTask {
});
profile(time::LayoutRestyleDamagePropagation,
- Some((&data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental })),
+ self.profiler_metadata(data),
self.time_profiler_chan.clone(),
|| {
- if opts::get().nonincremental_layout ||
- layout_root.deref_mut().compute_layout_damage().contains(REFLOW_ENTIRE_DOCUMENT) {
+ if opts::get().nonincremental_layout || layout_root.deref_mut()
+ .compute_layout_damage()
+ .contains(REFLOW_ENTIRE_DOCUMENT) {
layout_root.deref_mut().reflow_entire_document()
}
});
@@ -818,42 +809,45 @@ impl LayoutTask {
// Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes.
profile(time::LayoutMainCategory,
- Some((&data.url,
- if data.iframe { TimerMetadataFrameType::IFrame } else { TimerMetadataFrameType::RootWindow },
- if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental })),
+ self.profiler_metadata(data),
self.time_profiler_chan.clone(),
|| {
let rw_data = rw_data.deref_mut();
match rw_data.parallel_traversal {
None => {
// Sequential mode.
- self.solve_constraints(&mut layout_root, &shared_layout_ctx)
+ self.solve_constraints(&mut layout_root, &shared_layout_context)
}
Some(_) => {
// Parallel mode.
self.solve_constraints_parallel(data,
rw_data,
&mut layout_root,
- &mut shared_layout_ctx);
+ &mut shared_layout_context);
}
}
});
// Build the display list if necessary, and send it to the painter.
- if data.goal == ReflowForDisplay {
- self.build_display_list_for_reflow(data,
- node,
- &mut layout_root,
- &mut shared_layout_ctx,
- &mut rw_data);
+ match data.goal {
+ ReflowForDisplay => {
+ self.build_display_list_for_reflow(data,
+ node,
+ &mut layout_root,
+ &mut shared_layout_context,
+ &mut rw_data);
+ }
+ ReflowForScriptQuery => {}
}
match data.query_type {
- ContentBoxQuery(node) =>
- self.process_content_box_request(node, &mut layout_root, &mut rw_data),
- ContentBoxesQuery(node) =>
- self.process_content_boxes_request(node, &mut layout_root, &mut rw_data),
- NoQuery => {},
+ ContentBoxQuery(node) => {
+ self.process_content_box_request(node, &mut layout_root, &mut rw_data)
+ }
+ ContentBoxesQuery(node) => {
+ self.process_content_boxes_request(node, &mut layout_root, &mut rw_data)
+ }
+ NoQuery => {}
}
self.first_reflow.set(false);
@@ -896,11 +890,13 @@ impl LayoutTask {
}
}
- // When images can't be loaded in time to display they trigger
- // this callback in some task somewhere. This will send a message
- // to the script task, and ultimately cause the image to be
- // re-requested. We probably don't need to go all the way back to
- // the script task for this.
+ /// When images can't be loaded in time to display they trigger
+ /// this callback in some task somewhere. This will send a message
+ /// to the script task, and ultimately cause the image to be
+ /// re-requested. We probably don't need to go all the way back to
+ /// the script task for this.
+ ///
+ /// FIXME(pcwalton): Rewrite all of this.
fn make_on_image_available_cb(&self) -> Box<ImageResponder<UntrustedNodeAddress>+Send> {
// This has a crazy signature because the image cache needs to
// make multiple copies of the callback, and the dom event
@@ -919,6 +915,21 @@ impl LayoutTask {
let _: Option<LayoutDataWrapper> = mem::transmute(
mem::replace(&mut *layout_data_ref, None));
}
+
+ /// Returns profiling information which is passed to the time profiler.
+ fn profiler_metadata<'a>(&self, data: &'a Reflow) -> ProfilerMetadata<'a> {
+ Some((&data.url,
+ if data.iframe {
+ TimerMetadataFrameType::IFrame
+ } else {
+ TimerMetadataFrameType::RootWindow
+ },
+ if self.first_reflow.get() {
+ TimerMetadataReflowType::FirstReflow
+ } else {
+ TimerMetadataReflowType::Incremental
+ }))
+ }
}
struct LayoutRPCImpl(Arc<Mutex<LayoutTaskData>>);
@@ -951,7 +962,7 @@ impl LayoutRPC for LayoutRPCImpl {
let mut result = Vec::new();
stacking_context.hit_test(point, &mut result, true);
if !result.is_empty() {
- Some(HitTestResponse(result[0]))
+ Some(HitTestResponse(result[0].node.to_untrusted_node_address()))
} else {
None
}
@@ -967,7 +978,7 @@ impl LayoutRPC for LayoutRPCImpl {
fn mouse_over(&self, _: TrustedNodeAddress, point: Point2D<f32>)
-> Result<MouseOverResponse, ()> {
- let mut mouse_over_list: Vec<UntrustedNodeAddress> = vec!();
+ let mut mouse_over_list: Vec<DisplayItemMetadata> = vec!();
let point = Point2D(Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
{
let &LayoutRPCImpl(ref rw_data) = self;
@@ -978,12 +989,25 @@ impl LayoutRPC for LayoutRPCImpl {
stacking_context.hit_test(point, &mut mouse_over_list, false);
}
}
+
+ // Compute the new cursor.
+ let cursor = if !mouse_over_list.is_empty() {
+ mouse_over_list[0].cursor
+ } else {
+ DefaultCursor
+ };
+ let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan;
+ constellation_chan.send(SetCursorMsg(cursor));
}
if mouse_over_list.is_empty() {
Err(())
} else {
- Ok(MouseOverResponse(mouse_over_list))
+ let response_list =
+ mouse_over_list.iter()
+ .map(|metadata| metadata.node.to_untrusted_node_address())
+ .collect();
+ Ok(MouseOverResponse(response_list))
}
}
}