diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-11-24 17:23:30 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-12-10 08:35:47 -0800 |
commit | 8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e (patch) | |
tree | 722684b4013644a1ccc3d635f45f3521dd66dc08 /components | |
parent | 315e166cf7f24f4586e8ce863be597ce0a3f34c9 (diff) | |
download | servo-8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e.tar.gz servo-8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e.zip |
ports/cef: Implement accelerated compositing for the CEF port.
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/compositor.rs | 104 | ||||
-rw-r--r-- | components/compositing/compositor_task.rs | 22 | ||||
-rw-r--r-- | components/compositing/constellation.rs | 185 | ||||
-rw-r--r-- | components/compositing/headless.rs | 12 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 35 | ||||
-rw-r--r-- | components/compositing/windowing.rs | 25 | ||||
-rw-r--r-- | components/msg/compositor_msg.rs | 4 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 3 | ||||
-rw-r--r-- | components/script/dom/document.rs | 8 | ||||
-rw-r--r-- | components/script/dom/htmltitleelement.rs | 22 | ||||
-rw-r--r-- | components/script/dom/virtualmethods.rs | 8 | ||||
-rw-r--r-- | components/script/page.rs | 17 | ||||
-rw-r--r-- | components/script/script_task.rs | 17 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 3 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 4 | ||||
-rw-r--r-- | components/servo/lib.rs | 8 | ||||
-rw-r--r-- | components/servo/main.rs | 6 |
17 files changed, 359 insertions, 124 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 44015c8012c..c5a11fa1605 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -3,23 +3,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents}; -use compositor_layer::WantsScrollEvents; -use compositor_task::{ChangeReadyState, ChangePaintState, CompositorEventListener}; -use compositor_task::{CompositorProxy, CompositorReceiver, CompositorTask}; -use compositor_task::{CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer, Exit}; -use compositor_task::{FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties}; +use compositor_layer::{WantsScrollEvents}; +use compositor_task::{ChangePageLoadData, ChangePageTitle, ChangePaintState, ChangeReadyState}; +use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver}; +use compositor_task::{CompositorTask, CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer}; +use compositor_task::{Exit, FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties}; use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint}; use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete}; -use constellation::{SendableFrameTree, FrameTreeDiff}; +use constellation::{FrameId, FrameTreeDiff, SendableFrameTree}; use pipeline::CompositionPipeline; use scrolling::ScrollingTimerProxy; use windowing; -use windowing::{IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent}; -use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEvent}; -use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent}; +use windowing::{IdleWindowEvent, InitializeCompositingWindowEvent}; +use windowing::{KeyEvent, LoadUrlWindowEvent, MouseWindowClickEvent, MouseWindowEvent}; +use windowing::{MouseWindowEventClass, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; +use windowing::{MouseWindowMoveEventClass, NavigationWindowEvent, PinchZoomWindowEvent}; use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent}; use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent}; -use windowing::{PinchZoomWindowEvent, KeyEvent}; use azure::azure_hl; use std::cmp; @@ -40,11 +40,11 @@ use gleam::gl::types::{GLint, GLsizei}; use gleam::gl; use script_traits::{ViewportMsg, ScriptControlChan}; use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId}; -use servo_msg::compositor_msg::{ReadyState, PaintingPaintState, PaintState, Scrollable}; -use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg}; -use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg}; -use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key, KeyModifiers}; -use servo_msg::constellation_msg; +use servo_msg::compositor_msg::{ReadyState, PaintState, PaintingPaintState, Scrollable}; +use servo_msg::constellation_msg::{mod, ConstellationChan, ExitMsg}; +use servo_msg::constellation_msg::{GetPipelineTitleMsg, Key, KeyModifiers, KeyState, LoadData}; +use servo_msg::constellation_msg::{LoadUrlMsg, NavigateMsg, PipelineId, ResizedWindowMsg}; +use servo_msg::constellation_msg::{WindowSizeData}; use servo_util::geometry::{PagePx, ScreenPx, ViewportPx}; use servo_util::memory::MemoryProfilerChan; use servo_util::opts; @@ -58,6 +58,7 @@ use std::slice::bytes::copy_memory; use time::{precise_time_ns, precise_time_s}; use url::Url; +/// NB: Never block on the constellation, because sometimes the constellation blocks on us. pub struct IOCompositor<Window: WindowMethods> { /// The application window. window: Rc<Window>, @@ -65,8 +66,9 @@ pub struct IOCompositor<Window: WindowMethods> { /// The port on which we receive messages. port: Box<CompositorReceiver>, - /// The render context. - context: RenderContext, + /// The render context. This will be `None` if the windowing system has not yet sent us a + /// `PrepareRenderingEvent`. + context: Option<RenderContext>, /// The root pipeline. root_pipeline: Option<CompositionPipeline>, @@ -177,13 +179,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { // display list. This is only here because we don't have that logic in the painter yet. let window_size = window.framebuffer_size(); let hidpi_factor = window.hidpi_factor(); - let context = CompositorTask::create_graphics_context(&window.native_metadata()); - - let show_debug_borders = opts::get().show_debug_borders; IOCompositor { window: window, port: receiver, - context: rendergl::RenderContext::new(context, show_debug_borders), + context: None, root_pipeline: None, scene: Scene::new(Rect { origin: Zero::zero(), @@ -262,6 +261,14 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.change_paint_state(pipeline_id, paint_state); } + (ChangePageTitle(pipeline_id, title), NotShuttingDown) => { + self.change_page_title(pipeline_id, title); + } + + (ChangePageLoadData(frame_id, load_data), NotShuttingDown) => { + self.change_page_load_data(frame_id, load_data); + } + (PaintMsgDiscarded, NotShuttingDown) => { self.remove_outstanding_paint_msg(); } @@ -305,13 +312,18 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.scroll_fragment_to_point(pipeline_id, layer_id, point); } - (LoadComplete(..), NotShuttingDown) => { + (LoadComplete, NotShuttingDown) => { self.got_load_complete_message = true; // If we're painting in headless mode, schedule a recomposite. if opts::get().output_file.is_some() { self.composite_if_necessary(); } + + // Inform the embedder that the load has finished. + // + // TODO(pcwalton): Specify which frame's load completed. + self.window.load_end(); } (ScrollTimeout(timestamp), NotShuttingDown) => { @@ -371,6 +383,14 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.window.set_paint_state(paint_state); } + fn change_page_title(&mut self, _: PipelineId, title: Option<String>) { + self.window.set_page_title(title); + } + + fn change_page_load_data(&mut self, _: FrameId, load_data: LoadData) { + self.window.set_page_load_data(load_data); + } + fn all_pipelines_in_idle_paint_state(&self) -> bool { if self.ready_states.len() == 0 { return false; @@ -629,7 +649,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { IdleWindowEvent => {} RefreshWindowEvent => { - self.composite_if_necessary() + self.composite(); + } + + InitializeCompositingWindowEvent => { + self.initialize_compositing(); } ResizeWindowEvent(size) => { @@ -678,6 +702,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { } fn on_resize_window_event(&mut self, new_size: TypedSize2D<DevicePixel, uint>) { + debug!("compositor resizing to {}", new_size.to_untyped()); + // A size change could also mean a resolution change. let new_hidpi_factor = self.window.hidpi_factor(); if self.hidpi_factor != new_hidpi_factor { @@ -960,6 +986,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { } fn composite(&mut self) { + if !self.window.prepare_for_composite() { + return + } + let output_image = opts::get().output_file.is_some() && self.is_ready_to_paint_image_output(); @@ -995,7 +1025,14 @@ impl<Window: WindowMethods> IOCompositor<Window> { // paint the scene. match self.scene.root { Some(ref layer) => { - rendergl::render_scene(layer.clone(), self.context, &self.scene); + match self.context { + None => { + debug!("compositor: not compositing because context not yet set up") + } + Some(context) => { + rendergl::render_scene(layer.clone(), context, &self.scene); + } + } } None => {} } @@ -1053,6 +1090,12 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } + fn initialize_compositing(&mut self) { + let context = CompositorTask::create_graphics_context(&self.window.native_metadata()); + let show_debug_borders = opts::get().show_debug_borders; + self.context = Some(rendergl::RenderContext::new(context, show_debug_borders)) + } + fn find_topmost_layer_at_point_for_layer(&self, layer: Rc<Layer<CompositorData>>, point: TypedPoint2D<LayerPixel, f32>) @@ -1229,4 +1272,17 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind self.scrolling_timer.shutdown(); } + + fn pinch_zoom_level(&self) -> f32 { + self.viewport_zoom.get() as f32 + } + + fn get_title_for_main_frame(&self) { + let root_pipeline_id = match self.root_pipeline { + None => return, + Some(ref root_pipeline) => root_pipeline.id, + }; + let ConstellationChan(ref chan) = self.constellation_chan; + chan.send(GetPipelineTitleMsg(root_pipeline_id)); + } } diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs index 89aed5defa0..e7d851ceaf6 100644 --- a/components/compositing/compositor_task.rs +++ b/components/compositing/compositor_task.rs @@ -5,7 +5,7 @@ //! Communication with the compositor task. pub use windowing; -pub use constellation::{SendableFrameTree, FrameTreeDiff}; +pub use constellation::{FrameId, SendableFrameTree, FrameTreeDiff}; use compositor; use headless; @@ -19,7 +19,7 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics use layers::layers::LayerBufferSet; use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState}; use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy}; -use servo_msg::constellation_msg::{ConstellationChan, PipelineId}; +use servo_msg::constellation_msg::{ConstellationChan, LoadData, PipelineId}; use servo_util::memory::MemoryProfilerChan; use servo_util::time::TimeProfilerChan; use std::comm::{channel, Sender, Receiver}; @@ -81,8 +81,13 @@ impl ScriptListener for Box<CompositorProxy+'static+Send> { fn dup(&mut self) -> Box<ScriptListener+'static> { box self.clone_compositor_proxy() as Box<ScriptListener+'static> } + + fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) { + self.send(ChangePageTitle(pipeline_id, title)) + } } +/// Information about each layer that the compositor keeps. pub struct LayerProperties { pub pipeline_id: PipelineId, pub epoch: Epoch, @@ -184,9 +189,13 @@ pub enum Msg { ChangeReadyState(PipelineId, ReadyState), /// Alerts the compositor to the current status of painting. ChangePaintState(PipelineId, PaintState), - /// Alerts the compositor that the PaintMsg has been discarded. + /// Alerts the compositor that the current page has changed its title. + ChangePageTitle(PipelineId, Option<String>), + /// Alerts the compositor that the current page has changed its load data (including URL). + ChangePageLoadData(FrameId, LoadData), + /// Alerts the compositor that a `PaintMsg` has been discarded. PaintMsgDiscarded, - /// Sets the channel to the current layout and paint tasks, along with their id + /// Sets the channel to the current layout and paint tasks, along with their ID. SetIds(SendableFrameTree, Sender<()>, ConstellationChan), /// Sends an updated version of the frame tree. FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>), @@ -210,6 +219,8 @@ impl Show for Msg { Paint(..) => write!(f, "Paint"), ChangeReadyState(..) => write!(f, "ChangeReadyState"), ChangePaintState(..) => write!(f, "ChangePaintState"), + ChangePageTitle(..) => write!(f, "ChangePageTitle"), + ChangePageLoadData(..) => write!(f, "ChangePageLoadData"), PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"), SetIds(..) => write!(f, "SetIds"), FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"), @@ -269,5 +280,8 @@ pub trait CompositorEventListener { fn handle_event(&mut self, event: WindowEvent) -> bool; fn repaint_synchronously(&mut self); fn shutdown(&mut self); + fn pinch_zoom_level(&self) -> f32; + /// Requests that the compositor send the title for the main frame as soon as possible. + fn get_title_for_main_frame(&self); } diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 5155801f553..a993394de13 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -4,7 +4,8 @@ use pipeline::{Pipeline, CompositionPipeline}; -use compositor_task::{CompositorProxy, FrameTreeUpdateMsg, LoadComplete, ShutdownComplete, SetLayerOrigin, SetIds}; +use compositor_task::{ChangePageLoadData, ChangePageTitle, CompositorProxy, FrameTreeUpdateMsg}; +use compositor_task::{LoadComplete, SetLayerOrigin, SetIds, ShutdownComplete}; use devtools_traits; use devtools_traits::DevtoolsControlChan; use geom::rect::{Rect, TypedRect}; @@ -14,16 +15,16 @@ use gfx::paint_task; use layers::geometry::DevicePixel; use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg}; use libc; -use script_traits; -use script_traits::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg}; +use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg}; use script_traits::{ScriptControlChan, ScriptTaskFactory}; use servo_msg::compositor_msg::LayerId; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg}; +use servo_msg::constellation_msg::{GetPipelineTitleMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; -use servo_msg::constellation_msg::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg}; -use servo_msg::constellation_msg::{NavigationType, PipelineId, PainterReadyMsg, ResizedWindowMsg}; +use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers, LoadCompleteMsg}; +use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, Msg, NavigateMsg, NavigationType}; +use servo_msg::constellation_msg::{PainterReadyMsg, PipelineId, ResizedWindowMsg}; use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData}; -use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers}; use servo_msg::constellation_msg; use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::resource_task::ResourceTask; @@ -76,6 +77,10 @@ pub struct Constellation<LTF, STF> { /// The next free ID to assign to a pipeline. next_pipeline_id: PipelineId, + /// The next free ID to assign to a frame. + next_frame_id: FrameId, + + /// Navigation operations that are in progress. pending_frames: Vec<FrameChange>, pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>, @@ -86,17 +91,28 @@ pub struct Constellation<LTF, STF> { pub window_size: WindowSizeData, } -/// Stores the Id of the outermost frame's pipeline, along with a vector of children frames +/// A unique ID used to identify a frame. +pub struct FrameId(u32); + +/// One frame in the hierarchy. struct FrameTree { + /// The ID of this frame. + pub id: FrameId, + /// The pipeline for this frame. pub pipeline: Rc<Pipeline>, + /// The parent frame's pipeline. pub parent: RefCell<Option<Rc<Pipeline>>>, + /// A vector of child frames. pub children: RefCell<Vec<ChildFrameTree>>, + /// Whether this frame has a compositor layer. pub has_compositor_layer: Cell<bool>, } impl FrameTree { - fn new(pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>) -> FrameTree { + fn new(id: FrameId, pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>) + -> FrameTree { FrameTree { + id: id, pipeline: pipeline, parent: RefCell::new(parent_pipeline), children: RefCell::new(vec!()), @@ -234,16 +250,19 @@ impl Iterator<Rc<FrameTree>> for FrameTreeIterator { /// Represents the portion of a page that is changing in navigating. struct FrameChange { + /// The old pipeline ID. pub before: Option<PipelineId>, + /// The resulting frame tree after navigation. pub after: Rc<FrameTree>, + /// The kind of navigation that is occurring. pub navigation_type: NavigationType, } /// Stores the Id's of the pipelines previous and next in the browser's history struct NavigationContext { - pub previous: Vec<Rc<FrameTree>>, - pub next: Vec<Rc<FrameTree>>, - pub current: Option<Rc<FrameTree>>, + previous: Vec<Rc<FrameTree>>, + next: Vec<Rc<FrameTree>>, + current: Option<Rc<FrameTree>>, } impl NavigationContext { @@ -258,29 +277,30 @@ impl NavigationContext { /* Note that the following two methods can fail. They should only be called * * when it is known that there exists either a previous page or a next page. */ - fn back(&mut self) -> Rc<FrameTree> { + fn back(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> { self.next.push(self.current.take().unwrap()); let prev = self.previous.pop().unwrap(); - self.current = Some(prev.clone()); + self.set_current(prev.clone(), compositor_proxy); prev } - fn forward(&mut self) -> Rc<FrameTree> { + fn forward(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> { self.previous.push(self.current.take().unwrap()); let next = self.next.pop().unwrap(); - self.current = Some(next.clone()); + self.set_current(next.clone(), compositor_proxy); next } /// Loads a new set of page frames, returning all evicted frame trees - fn load(&mut self, frame_tree: Rc<FrameTree>) -> Vec<Rc<FrameTree>> { + fn load(&mut self, frame_tree: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy) + -> Vec<Rc<FrameTree>> { debug!("navigating to {}", frame_tree.pipeline.id); let evicted = replace(&mut self.next, vec!()); match self.current.take() { Some(current) => self.previous.push(current), None => (), } - self.current = Some(frame_tree); + self.set_current(frame_tree, compositor_proxy); evicted } @@ -308,6 +328,14 @@ impl NavigationContext { frame_tree.contains(pipeline_id) }) } + + /// Always use this method to set the currently-displayed frame. It correctly informs the + /// compositor of the new URLs. + fn set_current(&mut self, new_frame: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy) { + self.current = Some(new_frame.clone()); + compositor_proxy.send(ChangePageLoadData(new_frame.id, + new_frame.pipeline.load_data.clone())); + } } impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { @@ -334,6 +362,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { pipelines: HashMap::new(), navigation_context: NavigationContext::new(), next_pipeline_id: PipelineId(0), + next_frame_id: FrameId(0), pending_frames: vec!(), pending_sizes: HashMap::new(), time_profiler_chan: time_profiler_chan, @@ -358,31 +387,30 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { } /// Helper function for creating a pipeline - fn new_pipeline(&self, + fn new_pipeline(&mut self, id: PipelineId, subpage_id: Option<SubpageId>, script_pipeline: Option<Rc<Pipeline>>, load_data: LoadData) -> Rc<Pipeline> { - let pipe = Pipeline::create::<LTF, STF>(id, - subpage_id, - self.chan.clone(), - self.compositor_proxy.clone_compositor_proxy(), - self.devtools_chan.clone(), - self.image_cache_task.clone(), - self.font_cache_task.clone(), - self.resource_task.clone(), - self.storage_task.clone(), - self.time_profiler_chan.clone(), - self.window_size, - script_pipeline, - load_data); - pipe.load(); - Rc::new(pipe) - } - - - /// Helper function for getting a unique pipeline Id + let pipe = Pipeline::create::<LTF, STF>(id, + subpage_id, + self.chan.clone(), + self.compositor_proxy.clone_compositor_proxy(), + self.devtools_chan.clone(), + self.image_cache_task.clone(), + self.font_cache_task.clone(), + self.resource_task.clone(), + self.storage_task.clone(), + self.time_profiler_chan.clone(), + self.window_size, + script_pipeline, + load_data.clone()); + pipe.load(); + Rc::new(pipe) + } + + /// Helper function for getting a unique pipeline ID. fn get_next_pipeline_id(&mut self) -> PipelineId { let id = self.next_pipeline_id; let PipelineId(ref mut i) = self.next_pipeline_id; @@ -390,6 +418,14 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { id } + /// Helper function for getting a unique frame ID. + fn get_next_frame_id(&mut self) -> FrameId { + let id = self.next_frame_id; + let FrameId(ref mut i) = self.next_frame_id; + *i += 1; + id + } + /// Convenience function for getting the currently active frame tree. /// The currently active frame tree should always be the current painter fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> { @@ -465,6 +501,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { debug!("constellation got key event message"); self.handle_key_msg(key, state, modifiers); } + GetPipelineTitleMsg(pipeline_id) => { + debug!("constellation got get-pipeline-title message"); + self.handle_get_pipeline_title_msg(pipeline_id); + } } true } @@ -529,27 +569,38 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { debug!("creating replacement pipeline for about:failure"); let new_id = self.get_next_pipeline_id(); + let new_frame_id = self.get_next_frame_id(); let pipeline = self.new_pipeline(new_id, subpage_id, None, LoadData::new(Url::parse("about:failure").unwrap())); - self.pending_frames.push(FrameChange{ - before: Some(pipeline_id), - after: Rc::new(FrameTree::new(pipeline.clone(), None)), - navigation_type: constellation_msg::Load, - }); + self.browse(Some(pipeline_id), + Rc::new(FrameTree::new(new_frame_id, pipeline.clone(), None)), + constellation_msg::Load); self.pipelines.insert(new_id, pipeline); } + /// Performs navigation. This pushes a `FrameChange` object onto the list of pending frames. + /// + /// TODO(pcwalton): Send a `BeforeBrowse` message to the embedder and allow cancellation. + fn browse(&mut self, + before: Option<PipelineId>, + after: Rc<FrameTree>, + navigation_type: NavigationType) { + self.pending_frames.push(FrameChange { + before: before, + after: after, + navigation_type: navigation_type, + }); + } + fn handle_init_load(&mut self, url: Url) { let next_pipeline_id = self.get_next_pipeline_id(); + let next_frame_id = self.get_next_frame_id(); let pipeline = self.new_pipeline(next_pipeline_id, None, None, LoadData::new(url)); - - self.pending_frames.push(FrameChange { - before: None, - after: Rc::new(FrameTree::new(pipeline.clone(), None)), - navigation_type: constellation_msg::Load, - }); + self.browse(None, + Rc::new(FrameTree::new(next_frame_id, pipeline.clone(), None)), + constellation_msg::Load); self.pipelines.insert(pipeline.id, pipeline); } @@ -690,15 +741,19 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { let rect = self.pending_sizes.remove(&(source_pipeline_id, subpage_id)); for frame_tree in frame_trees.iter() { + let next_frame_id = self.get_next_frame_id(); frame_tree.children.borrow_mut().push(ChildFrameTree::new( - Rc::new(FrameTree::new(pipeline.clone(), Some(source_pipeline.clone()))), + Rc::new(FrameTree::new(next_frame_id, + pipeline.clone(), + Some(source_pipeline.clone()))), rect)); } self.pipelines.insert(pipeline.id, pipeline); } fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) { - debug!("Constellation: received message to load {:s}", load_data.url.to_string()); + let url = load_data.url.to_string(); + debug!("Constellation: received message to load {:s}", url); // Make sure no pending page would be overridden. let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect( "Constellation: received a LoadUrlMsg from a pipeline_id associated @@ -723,14 +778,13 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { let parent = source_frame.parent.clone(); let subpage_id = source_frame.pipeline.subpage_id; let next_pipeline_id = self.get_next_pipeline_id(); - + let next_frame_id = self.get_next_frame_id(); let pipeline = self.new_pipeline(next_pipeline_id, subpage_id, None, load_data); - - self.pending_frames.push(FrameChange { - before: Some(source_id), - after: Rc::new(FrameTree::new(pipeline.clone(), parent.borrow().clone())), - navigation_type: constellation_msg::Load, - }); + self.browse(Some(source_id), + Rc::new(FrameTree::new(next_frame_id, + pipeline.clone(), + parent.borrow().clone())), + constellation_msg::Load); self.pipelines.insert(pipeline.id, pipeline); } @@ -752,7 +806,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { frame.pipeline.revoke_paint_permission(); } } - self.navigation_context.forward() + self.navigation_context.forward(&mut *self.compositor_proxy) } constellation_msg::Back => { if self.navigation_context.previous.is_empty() { @@ -764,7 +818,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { frame.pipeline.revoke_paint_permission(); } } - self.navigation_context.back() + self.navigation_context.back(&mut *self.compositor_proxy) } }; @@ -787,6 +841,16 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { }); } + fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) { + match self.pipelines.get(&pipeline_id) { + None => self.compositor_proxy.send(ChangePageTitle(pipeline_id, None)), + Some(pipeline) => { + let ScriptControlChan(ref script_channel) = pipeline.script_chan; + script_channel.send(GetTitleMsg(pipeline_id)); + } + } + } + fn handle_painter_ready_msg(&mut self, pipeline_id: PipelineId) { debug!("Painter {} ready to send paint msg", pipeline_id); // This message could originate from a pipeline in the navigation context or @@ -941,7 +1005,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { match navigation_type { constellation_msg::Load => { debug!("evicting old frames due to load"); - let evicted = self.navigation_context.load(frame_tree); + let evicted = self.navigation_context.load(frame_tree, + &mut *self.compositor_proxy); self.handle_evicted_frames(evicted); } _ => { diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs index 459af00fcc2..7fc1df7dbe6 100644 --- a/components/compositing/headless.rs +++ b/components/compositing/headless.rs @@ -5,7 +5,8 @@ use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer}; use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds}; use compositor_task::{SetLayerOrigin, ShutdownComplete, ChangePaintState, PaintMsgDiscarded}; -use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, FrameTreeUpdateMsg}; +use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, ChangePageTitle}; +use compositor_task::{ChangePageLoadData, FrameTreeUpdateMsg}; use windowing::WindowEvent; use geom::scale_factor::ScaleFactor; @@ -104,7 +105,8 @@ impl CompositorEventListener for NullCompositor { CreateOrUpdateDescendantLayer(..) | SetLayerOrigin(..) | Paint(..) | ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) | - LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) => () + LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) | ChangePageTitle(..) | + ChangePageLoadData(..) => () } true } @@ -119,4 +121,10 @@ impl CompositorEventListener for NullCompositor { self.time_profiler_chan.send(time::ExitMsg); self.memory_profiler_chan.send(memory::ExitMsg); } + + fn pinch_zoom_level(&self) -> f32 { + 1.0 + } + + fn get_title_for_main_frame(&self) {} } diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index cf1ebd16f8c..6dd9dabb0bf 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -28,8 +28,10 @@ pub struct Pipeline { pub paint_chan: PaintChan, pub layout_shutdown_port: Receiver<()>, pub paint_shutdown_port: Receiver<()>, - /// The most recently loaded page + /// Load data corresponding to the most recently-loaded page. pub load_data: LoadData, + /// The title of the most recently-loaded page. + pub title: Option<String>, } /// The subset of the pipeline that is needed for layer composition. @@ -44,21 +46,21 @@ impl Pipeline { /// Starts a paint task, layout task, and possibly a script task. /// Returns the channels wrapped in a struct. /// If script_pipeline is not None, then subpage_id must also be not None. - pub fn create<LTF:LayoutTaskFactory, STF:ScriptTaskFactory>( - id: PipelineId, - subpage_id: Option<SubpageId>, - constellation_chan: ConstellationChan, - compositor_proxy: Box<CompositorProxy+'static+Send>, - devtools_chan: Option<DevtoolsControlChan>, - image_cache_task: ImageCacheTask, - font_cache_task: FontCacheTask, - resource_task: ResourceTask, - storage_task: StorageTask, - time_profiler_chan: TimeProfilerChan, - window_size: WindowSizeData, - script_pipeline: Option<Rc<Pipeline>>, - load_data: LoadData) - -> Pipeline { + pub fn create<LTF,STF>(id: PipelineId, + subpage_id: Option<SubpageId>, + constellation_chan: ConstellationChan, + compositor_proxy: Box<CompositorProxy+'static+Send>, + devtools_chan: Option<DevtoolsControlChan>, + image_cache_task: ImageCacheTask, + font_cache_task: FontCacheTask, + resource_task: ResourceTask, + storage_task: StorageTask, + time_profiler_chan: TimeProfilerChan, + window_size: WindowSizeData, + script_pipeline: Option<Rc<Pipeline>>, + load_data: LoadData) + -> Pipeline + where LTF: LayoutTaskFactory, STF:ScriptTaskFactory { let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>); let (paint_port, paint_chan) = PaintChan::new(); let (paint_shutdown_chan, paint_shutdown_port) = channel(); @@ -153,6 +155,7 @@ impl Pipeline { layout_shutdown_port: layout_shutdown_port, paint_shutdown_port: paint_shutdown_port, load_data: load_data, + title: None, } } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 0dffe0a8f94..339a5fe789d 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -11,8 +11,8 @@ use geom::scale_factor::ScaleFactor; use geom::size::TypedSize2D; use layers::geometry::DevicePixel; use layers::platform::surface::NativeGraphicsMetadata; -use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers}; -use servo_msg::compositor_msg::{ReadyState, PaintState}; +use servo_msg::compositor_msg::{PaintState, ReadyState}; +use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData}; use servo_util::geometry::ScreenPx; use std::fmt::{FormatError, Formatter, Show}; use std::rc::Rc; @@ -37,8 +37,12 @@ pub enum WindowEvent { /// It's possible that this should be something like /// `CompositorMessageWindowEvent(compositor_task::Msg)` instead. IdleWindowEvent, - /// Sent when part of the window is marked dirty and needs to be redrawn. + /// Sent when part of the window is marked dirty and needs to be redrawn. Before sending this + /// message, the window must make the same GL context as in `PrepareRenderingEvent` current. RefreshWindowEvent, + /// Sent to initialize the GL context. The windowing system must have a valid, current GL + /// context when this message is sent. + InitializeCompositingWindowEvent, /// Sent when the window is resized. ResizeWindowEvent(TypedSize2D<DevicePixel, uint>), /// Sent when a new URL is to be loaded. @@ -47,7 +51,8 @@ pub enum WindowEvent { MouseWindowEventClass(MouseWindowEvent), /// Sent when a mouse move. MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>), - /// Sent when the user scrolls. Includes the current cursor position. + /// Sent when the user scrolls. The first point is the delta and the second point is the + /// origin. ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>), /// Sent when the user zooms. ZoomWindowEvent(f32), @@ -66,6 +71,7 @@ impl Show for WindowEvent { match *self { IdleWindowEvent => write!(f, "Idle"), RefreshWindowEvent => write!(f, "Refresh"), + InitializeCompositingWindowEvent => write!(f, "InitializeCompositing"), ResizeWindowEvent(..) => write!(f, "Resize"), KeyEvent(..) => write!(f, "Key"), LoadUrlWindowEvent(..) => write!(f, "LoadUrl"), @@ -92,6 +98,12 @@ pub trait WindowMethods { fn set_ready_state(&self, ready_state: ReadyState); /// Sets the paint state of the current page. fn set_paint_state(&self, paint_state: PaintState); + /// Sets the page title for the current page. + fn set_page_title(&self, title: Option<String>); + /// Sets the load data for the current page. + fn set_page_load_data(&self, load_data: LoadData); + /// Called when the browser is done loading a frame. + fn load_end(&self); /// Returns the hidpi factor of the monitor. fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>; @@ -106,5 +118,10 @@ pub trait WindowMethods { /// magic to wake the up window's event loop. fn create_compositor_channel(_: &Option<Rc<Self>>) -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>); + + /// Requests that the window system prepare a composite. Typically this will involve making + /// some type of platform-specific graphics context current. Returns true if the composite may + /// proceed and false if it should not. + fn prepare_for_composite(&self) -> bool; } diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs index 4635e2667d4..dad31c08976 100644 --- a/components/msg/compositor_msg.rs +++ b/components/msg/compositor_msg.rs @@ -19,7 +19,7 @@ pub enum PaintState { PaintingPaintState, } -#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone)] +#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone, Show)] pub enum ReadyState { /// Informs the compositor that nothing has been done yet. Used for setting status Blank, @@ -111,6 +111,8 @@ pub trait ScriptListener { pipeline_id: PipelineId, layer_id: LayerId, point: Point2D<f32>); + /// Informs the compositor that the title of the page with the given pipeline ID has changed. + fn set_title(&mut self, pipeline_id: PipelineId, new_title: Option<String>); fn close(&mut self); fn dup(&mut self) -> Box<ScriptListener+'static>; } diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 483f03803cf..9b2a654310c 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -205,6 +205,9 @@ pub enum Msg { PainterReadyMsg(PipelineId), ResizedWindowMsg(WindowSizeData), KeyEvent(Key, KeyState, KeyModifiers), + /// Requests that the constellation inform the compositor of the title of the pipeline + /// immediately. + GetPipelineTitleMsg(PipelineId), } /// Similar to net::resource_task::LoadData diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4fbdaab837d..738ac6be90e 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -189,6 +189,7 @@ pub trait DocumentHelpers<'a> { fn begin_focus_transaction(self); fn request_focus(self, elem: JSRef<Element>); fn commit_focus_transaction(self); + fn send_title_to_compositor(self); } impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { @@ -369,6 +370,12 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { //TODO: dispatch blur, focus, focusout, and focusin events self.focused.assign(self.possibly_focused.get()); } + + /// Sends this document's title to the compositor. + fn send_title_to_compositor(self) { + let window = self.window().root(); + window.page().send_title_to_compositor(); + } } #[deriving(PartialEq)] @@ -985,3 +992,4 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { global_event_handlers!() event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange) } + diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs index ef8b70aa4fa..4e6e9f7e9bb 100644 --- a/components/script/dom/htmltitleelement.rs +++ b/components/script/dom/htmltitleelement.rs @@ -5,15 +5,17 @@ use dom::bindings::codegen::Bindings::HTMLTitleElementBinding; use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; -use dom::bindings::codegen::InheritTypes::{HTMLTitleElementDerived, NodeCast, TextCast}; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTitleElementDerived, NodeCast}; +use dom::bindings::codegen::InheritTypes::{TextCast}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; -use dom::document::Document; +use dom::document::{Document, DocumentHelpers}; use dom::element::HTMLTitleElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; use dom::text::Text; +use dom::virtualmethods::VirtualMethods; use servo_util::str::DOMString; #[dom_struct] @@ -68,3 +70,19 @@ impl Reflectable for HTMLTitleElement { self.htmlelement.reflector() } } + +impl<'a> VirtualMethods for JSRef<'a, HTMLTitleElement> { + fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> { + let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self); + Some(htmlelement as &VirtualMethods) + } + + fn bind_to_tree(&self, is_in_doc: bool) { + let node: JSRef<Node> = NodeCast::from_ref(*self); + if is_in_doc { + let document = node.owner_doc().root(); + document.send_title_to_compositor() + } + } +} + diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 66378463a82..a90055bc50d 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -24,6 +24,7 @@ use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast; use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast; use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast; use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast; +use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast; use dom::bindings::js::JSRef; use dom::document::Document; use dom::element::Element; @@ -47,6 +48,7 @@ use dom::element::HTMLStyleElementTypeId; use dom::element::HTMLTableDataCellElementTypeId; use dom::element::HTMLTableHeaderCellElementTypeId; use dom::element::HTMLTextAreaElementTypeId; +use dom::element::HTMLTitleElementTypeId; use dom::event::Event; use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlareaelement::HTMLAreaElement; @@ -67,6 +69,7 @@ use dom::htmlselectelement::HTMLSelectElement; use dom::htmlstyleelement::HTMLStyleElement; use dom::htmltablecellelement::HTMLTableCellElement; use dom::htmltextareaelement::HTMLTextAreaElement; +use dom::htmltitleelement::HTMLTitleElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag}; use servo_util::str::DOMString; @@ -232,6 +235,11 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a { let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap(); element as &'a VirtualMethods + 'a } + ElementNodeTypeId(HTMLTitleElementTypeId) => { + let element: &'a JSRef<'a, HTMLTitleElement> = + HTMLTitleElementCast::to_borrowed_ref(node).unwrap(); + element as &'a VirtualMethods + 'a + } ElementNodeTypeId(ElementTypeId_) => { let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap(); element as &'a VirtualMethods + 'a diff --git a/components/script/page.rs b/components/script/page.rs index 37f4ba155bb..c8e46463077 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -21,7 +21,6 @@ use script_traits::{UntrustedNodeAddress, ScriptControlChan}; use geom::{Point2D, Rect, Size2D}; use js::rust::Cx; -use servo_msg::compositor_msg::PerformingLayout; use servo_msg::compositor_msg::ScriptListener; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData}; use servo_msg::constellation_msg::{PipelineId, SubpageId}; @@ -266,6 +265,17 @@ impl Page { // because it was built for infinite clip (MAX_RECT). had_clip_rect } + + pub fn send_title_to_compositor(&self) { + match *self.frame() { + None => {} + Some(ref frame) => { + let window = frame.window.root(); + let document = frame.document.root(); + window.compositor().set_title(self.id, Some(document.Title())); + } + } + } } impl Iterator<Rc<Page>> for PageIterator { @@ -356,7 +366,7 @@ impl Page { pub fn reflow(&self, goal: ReflowGoal, script_chan: ScriptControlChan, - compositor: &mut ScriptListener, + _: &mut ScriptListener, query_type: ReflowQueryType) { let root = match *self.frame() { None => return, @@ -376,9 +386,6 @@ impl Page { // Now, join the layout so that they will see the latest changes we have made. self.join_layout(); - // Tell the user that we're performing layout. - compositor.set_ready_state(self.id, PerformingLayout); - // Layout will let us know when it's done. let (join_chan, join_port) = channel(); let mut layout_join_port = self.layout_join_port.borrow_mut(); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index f41558b598c..b4fdaa6f833 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -43,10 +43,12 @@ use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, Scrip use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg}; use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel}; use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent}; -use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading}; +use script_traits::{GetTitleMsg}; +use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout}; use servo_msg::compositor_msg::{ScriptListener}; -use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection}; -use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState}; +use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg}; +use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, NavigationDirection, PipelineId}; +use servo_msg::constellation_msg::{Failure, FailureMsg, WindowSizeData, Key, KeyState}; use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed}; use servo_msg::constellation_msg::{Released}; use servo_msg::constellation_msg; @@ -550,6 +552,9 @@ impl ScriptTask { FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"), FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id), FromConstellation(ResizeMsg(..)) => panic!("should have handled ResizeMsg already"), + FromConstellation(GetTitleMsg(pipeline_id)) => { + self.handle_get_title_msg(pipeline_id) + } FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_progress(addr, progress), FromScript(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr), FromScript(DOMMessage(..)) => panic!("unexpected message"), @@ -661,6 +666,11 @@ impl ScriptTask { self.compositor.borrow_mut().close(); } + /// Handles a request for the window title. + fn handle_get_title_msg(&self, pipeline_id: PipelineId) { + get_page(&*self.page.borrow(), pipeline_id).send_title_to_compositor(); + } + /// Handles a request to exit the script task and shut down layout. /// Returns true if the script task should shut down and false otherwise. fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool { @@ -784,6 +794,7 @@ impl ScriptTask { parse_html(*document, parser_input, &final_url); document.set_ready_state(DocumentReadyStateValues::Interactive); + self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout); // Kick off the initial reflow of the page. debug!("kicking off initial reflow of {}", final_url); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index dec1d090178..59a1447a75a 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -65,7 +65,10 @@ pub enum ConstellationControlMsg { SendEventMsg(PipelineId, CompositorEvent), /// Notifies script that reflow is finished. ReflowCompleteMsg(PipelineId, uint), + /// Notifies script of the viewport. ViewportMsg(PipelineId, Rect<f32>), + /// Requests that the script task immediately send the constellation the title of a pipeline. + GetTitleMsg(PipelineId), } /// Events from the compositor that the script task needs to know about diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index ade8b873593..f9200ea627c 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -58,7 +58,7 @@ dependencies = [ [[package]] name = "cocoa" version = "0.1.1" -source = "git+https://github.com/servo/rust-cocoa#78b823bec1affcab20b6977e1057125088a6034c" +source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec" [[package]] name = "compile_msg" @@ -394,7 +394,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6 [[package]] name = "layers" version = "0.1.0" -source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf" +source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f" dependencies = [ "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)", "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 1ddfbc1dc5d..9e5d4be9467 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -153,6 +153,14 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static { self.compositor.repaint_synchronously() } + pub fn pinch_zoom_level(&self) -> f32 { + self.compositor.pinch_zoom_level() + } + + pub fn get_title_for_main_frame(&self) { + self.compositor.get_title_for_main_frame() + } + pub fn shutdown(mut self) { self.compositor.shutdown(); } diff --git a/components/servo/main.rs b/components/servo/main.rs index 16ef1980668..a6d7f28db73 100644 --- a/components/servo/main.rs +++ b/components/servo/main.rs @@ -30,7 +30,9 @@ use servo_util::rtinstrument; #[cfg(not(any(test,target_os="android")))] use servo::Browser; #[cfg(not(any(test,target_os="android")))] -use compositing::windowing::{IdleWindowEvent, ResizeWindowEvent, WindowEvent}; +use compositing::windowing::{IdleWindowEvent, InitializeCompositingWindowEvent, ResizeWindowEvent}; +#[cfg(not(any(test,target_os="android")))] +use compositing::windowing::{WindowEvent}; #[cfg(not(any(test,target_os="android")))] use std::os; @@ -65,6 +67,8 @@ fn start(argc: int, argv: *const *const u8) -> int { } } + browser.browser.handle_event(InitializeCompositingWindowEvent); + loop { let should_continue = match window { None => browser.browser.handle_event(IdleWindowEvent), |