compositing: Move messages that go over the ScriptListener to go over

an IPC channel instead.

Because this used a boxed trait object to invoke messages across a
process boundary, and boxed trait objects are not supported across IPC,
we spawn a helper thread inside the compositor to perform the marshaling
for us.
This commit is contained in:
Patrick Walton 2015-07-10 18:08:03 -07:00
parent 2947d78e4e
commit e841065351
14 changed files with 211 additions and 82 deletions

View file

@ -52,6 +52,9 @@ git = "https://github.com/servo/rust-png"
[dependencies.clipboard]
git = "https://github.com/aweinstock314/rust-clipboard"
[dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel"
[dependencies]
log = "*"
num = "0.1.24"

View file

@ -13,10 +13,11 @@ use windowing::{WindowEvent, WindowMethods};
use euclid::point::Point2D;
use euclid::rect::Rect;
use ipc_channel::ipc::IpcReceiver;
use layers::platform::surface::NativeDisplay;
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
use msg::compositor_msg::{Epoch, LayerId, LayerProperties, FrameTreeId};
use msg::compositor_msg::{PaintListener, ScriptListener};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{Key, KeyState, KeyModifiers};
use profile_traits::mem;
@ -61,31 +62,28 @@ impl CompositorReceiver for Receiver<Msg> {
}
}
/// Implementation of the abstract `ScriptListener` interface.
impl ScriptListener for Box<CompositorProxy+'static+Send> {
fn scroll_fragment_point(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
point: Point2D<f32>) {
self.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point));
}
pub fn run_script_listener_thread(mut compositor_proxy: Box<CompositorProxy + 'static + Send>,
receiver: IpcReceiver<ScriptToCompositorMsg>) {
while let Ok(msg) = receiver.recv() {
match msg {
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point) => {
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point));
}
fn close(&mut self) {
let (chan, port) = channel();
self.send(Msg::Exit(chan));
port.recv().unwrap();
}
ScriptToCompositorMsg::Exit => {
let (chan, port) = channel();
compositor_proxy.send(Msg::Exit(chan));
port.recv().unwrap();
}
fn dup(&mut self) -> Box<ScriptListener+'static> {
box self.clone_compositor_proxy() as Box<ScriptListener+'static>
}
ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
}
fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) {
self.send(Msg::ChangePageTitle(pipeline_id, title))
}
fn send_key_event(&mut self, key: Key, state: KeyState, modifiers: KeyModifiers) {
self.send(Msg::KeyEvent(key, state, modifiers));
ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
}
}
}
}

View file

@ -14,6 +14,7 @@ extern crate azure;
extern crate devtools_traits;
extern crate euclid;
extern crate gfx;
extern crate ipc_channel;
extern crate layers;
extern crate layout_traits;
extern crate png;

View file

@ -7,13 +7,16 @@ use layout_traits::{LayoutControlMsg, LayoutTaskFactory, LayoutControlChan};
use script_traits::{ScriptControlChan, ScriptTaskFactory};
use script_traits::{NewLayoutInfo, ConstellationControlMsg};
use compositor_task;
use devtools_traits::DevtoolsControlChan;
use euclid::rect::{TypedRect};
use euclid::scale_factor::ScaleFactor;
use gfx::paint_task::Msg as PaintMsg;
use gfx::paint_task::{PaintChan, PaintTask};
use gfx::font_cache_task::FontCacheTask;
use ipc_channel::ipc;
use layers::geometry::DevicePixel;
use msg::compositor_msg::ScriptListener;
use msg::constellation_msg::{ConstellationChan, Failure, FrameId, PipelineId, SubpageId};
use msg::constellation_msg::{LoadData, WindowSizeData, PipelineExitType, MozBrowserEvent};
use profile_traits::mem;
@ -22,6 +25,7 @@ use net_traits::ResourceTask;
use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;
use std::sync::mpsc::{Receiver, channel};
use std::thread;
use url::Url;
use util::geometry::{PagePx, ViewportPx};
use util::opts;
@ -91,6 +95,8 @@ impl Pipeline {
let script_chan = match script_chan {
None => {
let (script_chan, script_port) = channel();
let (script_to_compositor_chan, script_to_compositor_port) =
ipc::channel().unwrap();
let window_size = window_rect.map(|rect| {
WindowSizeData {
@ -100,10 +106,18 @@ impl Pipeline {
}
});
let compositor_proxy_for_script_listener_thread =
compositor_proxy.clone_compositor_proxy();
thread::spawn(move || {
compositor_task::run_script_listener_thread(
compositor_proxy_for_script_listener_thread,
script_to_compositor_port)
});
ScriptTaskFactory::create(None::<&mut STF>,
id,
parent_info,
compositor_proxy.clone_compositor_proxy(),
ScriptListener::new(script_to_compositor_chan),
&layout_pair,
ScriptControlChan(script_chan.clone()),
script_port,

View file

@ -22,12 +22,17 @@ git = "https://github.com/servo/rust-layers"
[dependencies.png]
git = "https://github.com/servo/rust-png"
[dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel"
[dependencies]
url = "0.2.35"
bitflags = "*"
hyper = "0.5"
rustc-serialize = "0.3.4"
euclid = "0.1"
serde = "*"
serde_macros = "*"
[target.x86_64-apple-darwin.dependencies]
core-foundation = "*"

View file

@ -7,6 +7,7 @@ use constellation_msg::{Key, KeyState, KeyModifiers};
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::Matrix4;
use ipc_channel::ipc::IpcSender;
use layers::platform::surface::NativeDisplay;
use layers::layers::{BufferRequest, LayerBufferSet};
use std::fmt::{Formatter, Debug};
@ -35,7 +36,7 @@ impl FrameTreeId {
}
}
#[derive(Clone, PartialEq, Eq, Copy, Hash)]
#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize)]
pub struct LayerId(pub usize, pub u32);
impl Debug for LayerId {
@ -115,16 +116,47 @@ pub trait PaintListener {
fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId);
}
#[derive(Deserialize, Serialize)]
pub enum ScriptToCompositorMsg {
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>),
SetTitle(PipelineId, Option<String>),
SendKeyEvent(Key, KeyState, KeyModifiers),
Exit,
}
/// The interface used by the script task to tell the compositor to update its ready state,
/// which is used in displaying the appropriate message in the window's title.
pub trait ScriptListener {
fn scroll_fragment_point(&mut self,
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>;
fn send_key_event(&mut self, key: Key, state: KeyState, modifiers: KeyModifiers);
#[derive(Clone)]
pub struct ScriptListener(IpcSender<ScriptToCompositorMsg>);
impl ScriptListener {
pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> ScriptListener {
ScriptListener(sender)
}
pub fn scroll_fragment_point(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
point: Point2D<f32>) {
self.0
.send(ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point))
.unwrap()
}
pub fn close(&mut self) {
self.0.send(ScriptToCompositorMsg::Exit).unwrap()
}
pub fn dup(&mut self) -> ScriptListener {
self.clone()
}
pub fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) {
self.0.send(ScriptToCompositorMsg::SetTitle(pipeline_id, title)).unwrap()
}
pub fn send_key_event(&mut self, key: Key, state: KeyState, modifiers: KeyModifiers) {
self.0.send(ScriptToCompositorMsg::SendKeyEvent(key, state, modifiers)).unwrap()
}
}

View file

@ -57,7 +57,7 @@ pub struct WindowSizeData {
pub device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>,
}
#[derive(PartialEq, Eq, Copy, Clone)]
#[derive(PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum KeyState {
Pressed,
Released,
@ -65,7 +65,7 @@ pub enum KeyState {
}
//N.B. Based on the glutin key enum
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
pub enum Key {
Space,
Apostrophe,
@ -191,6 +191,7 @@ pub enum Key {
}
bitflags! {
#[derive(Deserialize, Serialize)]
flags KeyModifiers: u8 {
const NONE = 0x00,
const SHIFT = 0x01,
@ -368,10 +369,10 @@ pub struct FrameId(pub u32);
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug)]
pub struct WorkerId(pub u32);
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
pub struct PipelineId(pub u32);
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
pub struct SubpageId(pub u32);
// The type of pipeline exit. During complete shutdowns, pipelines do not have to

View file

@ -2,13 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate azure;
#[macro_use] extern crate bitflags;
extern crate euclid;
extern crate hyper;
extern crate ipc_channel;
extern crate layers;
extern crate png;
extern crate rustc_serialize;
extern crate serde;
extern crate util;
extern crate url;
extern crate style;

View file

@ -328,7 +328,7 @@ impl<A,B> JSTraceable for fn(A) -> B {
}
}
impl JSTraceable for Box<ScriptListener+'static> {
impl JSTraceable for ScriptListener {
#[inline]
fn trace(&self, _: *mut JSTracer) {
// Do nothing

View file

@ -251,8 +251,11 @@ pub trait DocumentHelpers<'a> {
fn title_changed(self);
fn send_title_to_compositor(self);
fn dirty_all_nodes(self);
fn dispatch_key_event(self, key: Key, state: KeyState,
modifiers: KeyModifiers, compositor: &mut Box<ScriptListener+'static>);
fn dispatch_key_event(self,
key: Key,
state: KeyState,
modifiers: KeyModifiers,
compositor: &mut ScriptListener);
fn node_from_nodes_and_strings(self, nodes: Vec<NodeOrString>)
-> Fallible<Root<Node>>;
fn get_body_attribute(self, local_name: &Atom) -> DOMString;
@ -763,10 +766,11 @@ impl<'a> DocumentHelpers<'a> for &'a Document {
}
/// The entry point for all key processing for web content
fn dispatch_key_event(self, key: Key,
fn dispatch_key_event(self,
key: Key,
state: KeyState,
modifiers: KeyModifiers,
compositor: &mut Box<ScriptListener+'static>) {
compositor: &mut ScriptListener) {
let window = self.window.root();
let focused = self.get_focused_element();
let body = self.GetBody();

View file

@ -105,7 +105,7 @@ pub struct Window {
navigator: MutNullableHeap<JS<Navigator>>,
image_cache_task: ImageCacheTask,
image_cache_chan: ImageCacheChan,
compositor: DOMRefCell<Box<ScriptListener+'static>>,
compositor: DOMRefCell<ScriptListener>,
browser_context: DOMRefCell<Option<BrowserContext>>,
page: Rc<Page>,
performance: MutNullableHeap<JS<Performance>>,
@ -241,7 +241,7 @@ impl Window {
&self.image_cache_task
}
pub fn compositor<'a>(&'a self) -> RefMut<'a, Box<ScriptListener+'static>> {
pub fn compositor<'a>(&'a self) -> RefMut<'a, ScriptListener> {
self.compositor.borrow_mut()
}
@ -964,7 +964,7 @@ impl Window {
script_chan: Box<ScriptChan+Send>,
image_cache_chan: ImageCacheChan,
control_chan: ScriptControlChan,
compositor: Box<ScriptListener+'static>,
compositor: ScriptListener,
image_cache_task: ImageCacheTask,
resource_task: ResourceTask,
storage_task: StorageTask,

View file

@ -297,8 +297,9 @@ pub struct ScriptTask {
/// For communicating load url messages to the constellation
constellation_chan: ConstellationChan,
/// A handle to the compositor for communicating ready state messages.
compositor: DOMRefCell<Box<ScriptListener+'static>>,
compositor: DOMRefCell<ScriptListener>,
/// The port on which we receive messages from the image cache
image_cache_port: Receiver<ImageCacheResult>,
@ -374,29 +375,28 @@ impl ScriptTaskFactory for ScriptTask {
box pair.sender() as Box<Any+Send>
}
fn create<C>(_phantom: Option<&mut ScriptTask>,
id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
compositor: C,
layout_chan: &OpaqueScriptLayoutChannel,
control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>,
constellation_chan: ConstellationChan,
failure_msg: Failure,
resource_task: ResourceTask,
storage_task: StorageTask,
image_cache_task: ImageCacheTask,
devtools_chan: Option<DevtoolsControlChan>,
window_size: Option<WindowSizeData>,
load_data: LoadData)
where C: ScriptListener + Send + 'static {
fn create(_phantom: Option<&mut ScriptTask>,
id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
compositor: ScriptListener,
layout_chan: &OpaqueScriptLayoutChannel,
control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>,
constellation_chan: ConstellationChan,
failure_msg: Failure,
resource_task: ResourceTask,
storage_task: StorageTask,
image_cache_task: ImageCacheTask,
devtools_chan: Option<DevtoolsControlChan>,
window_size: Option<WindowSizeData>,
load_data: LoadData) {
let ConstellationChan(const_chan) = constellation_chan.clone();
let (script_chan, script_port) = channel();
let layout_chan = LayoutChan(layout_chan.sender());
spawn_named_with_send_on_failure(format!("ScriptTask {:?}", id), task_state::SCRIPT, move || {
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
let script_task = ScriptTask::new(box compositor as Box<ScriptListener>,
let script_task = ScriptTask::new(compositor,
script_port,
NonWorkerScriptChan(script_chan),
control_chan,
@ -464,7 +464,7 @@ impl ScriptTask {
}
/// Creates a new script task.
pub fn new(compositor: Box<ScriptListener+'static>,
pub fn new(compositor: ScriptListener,
port: Receiver<ScriptMsg>,
chan: NonWorkerScriptChan,
control_chan: ScriptControlChan,

View file

@ -150,22 +150,21 @@ pub struct ScriptControlChan(pub Sender<ConstellationControlMsg>);
/// crate.
pub trait ScriptTaskFactory {
/// Create a `ScriptTask`.
fn create<C>(_phantom: Option<&mut Self>,
id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
compositor: C,
layout_chan: &OpaqueScriptLayoutChannel,
control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>,
constellation_msg: ConstellationChan,
failure_msg: Failure,
resource_task: ResourceTask,
storage_task: StorageTask,
image_cache_task: ImageCacheTask,
devtools_chan: Option<DevtoolsControlChan>,
window_size: Option<WindowSizeData>,
load_data: LoadData)
where C: ScriptListener + Send;
fn create(_phantom: Option<&mut Self>,
id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
compositor: ScriptListener,
layout_chan: &OpaqueScriptLayoutChannel,
control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>,
constellation_msg: ConstellationChan,
failure_msg: Failure,
resource_task: ResourceTask,
storage_task: StorageTask,
image_cache_task: ImageCacheTask,
devtools_chan: Option<DevtoolsControlChan>,
window_size: Option<WindowSizeData>,
load_data: LoadData);
/// Create a script -> layout channel (`Sender`, `Receiver` pair).
fn create_layout_channel(_phantom: Option<&mut Self>) -> OpaqueScriptLayoutChannel;
/// Clone the `Sender` in `pair`.

View file

@ -47,6 +47,11 @@ name = "android_glue"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aster"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "azure"
version = "0.1.0"
@ -157,6 +162,7 @@ dependencies = [
"gfx 0.0.1",
"gfx_traits 0.0.1",
"gleam 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"layout_traits 0.0.1",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -612,6 +618,17 @@ dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ipc-channel"
version = "0.1.0"
source = "git+https://github.com/pcwalton/ipc-channel#aa2eab807ba1e7e287d283c2788c317c53d26970"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "js"
version = "0.1.0"
@ -789,9 +806,12 @@ dependencies = [
"euclid 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"io-surface 0.1.0 (git+https://github.com/servo/io-surface-rs)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"png 0.1.0 (git+https://github.com/servo/rust-png)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"url 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
@ -1007,6 +1027,27 @@ dependencies = [
"url 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quasi_codegen"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quasi_macros"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quasi_codegen 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quicksort"
version = "1.0.0"
@ -1124,6 +1165,32 @@ dependencies = [
"string_cache_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_codegen"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aster 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quasi_macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_macros"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shared_library"
version = "0.1.0"