mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
ports/cef: Implement accelerated compositing for the CEF port.
This commit is contained in:
parent
315e166cf7
commit
8b2aadc30b
35 changed files with 1746 additions and 642 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
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
|
||||
/// 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);
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue