Webdriver uses browsing context ids rather than pipeline ids.

This commit is contained in:
Alan Jeffrey 2017-05-22 09:40:17 -05:00
parent 3c267d7fdd
commit 79743b5358
12 changed files with 265 additions and 246 deletions

View file

@ -754,10 +754,15 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let initial_viewport = self.window_rect.size.to_f32() / dppx; let initial_viewport = self.window_rect.size.to_f32() / dppx;
let msg = ConstellationMsg::WindowSize(WindowSizeData { let data = WindowSizeData {
device_pixel_ratio: dppx, device_pixel_ratio: dppx,
initial_viewport: initial_viewport, initial_viewport: initial_viewport,
}, size_type); };
let top_level_browsing_context_id = match self.root_pipeline {
Some(ref pipeline) => pipeline.top_level_browsing_context_id,
None => return warn!("Window resize without root pipeline."),
};
let msg = ConstellationMsg::WindowSize(top_level_browsing_context_id, data, size_type);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending window resize to constellation failed ({}).", e); warn!("Sending window resize to constellation failed ({}).", e);
@ -866,7 +871,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
WindowEvent::Reload => { WindowEvent::Reload => {
let msg = ConstellationMsg::Reload; let top_level_browsing_context_id = match self.root_pipeline {
Some(ref pipeline) => pipeline.top_level_browsing_context_id,
None => return warn!("Window reload without root pipeline."),
};
let msg = ConstellationMsg::Reload(top_level_browsing_context_id);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending reload to constellation failed ({}).", e); warn!("Sending reload to constellation failed ({}).", e);
} }
@ -1338,7 +1347,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
windowing::WindowNavigateMsg::Forward => TraversalDirection::Forward(1), windowing::WindowNavigateMsg::Forward => TraversalDirection::Forward(1),
windowing::WindowNavigateMsg::Back => TraversalDirection::Back(1), windowing::WindowNavigateMsg::Back => TraversalDirection::Back(1),
}; };
let msg = ConstellationMsg::TraverseHistory(None, direction); let top_level_browsing_context_id = match self.root_pipeline {
Some(ref pipeline) => pipeline.top_level_browsing_context_id,
None => return warn!("Sending navigation to constellation with no root pipeline."),
};
let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending navigation to constellation failed ({}).", e); warn!("Sending navigation to constellation failed ({}).", e);
} }

View file

@ -29,6 +29,7 @@ pub use compositor::IOCompositor;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use msg::constellation_msg::TopLevelBrowsingContextId;
use script_traits::{ConstellationControlMsg, LayoutControlMsg}; use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use style_traits::CSSPixel; use style_traits::CSSPixel;
@ -48,6 +49,7 @@ pub struct SendableFrameTree {
#[derive(Clone)] #[derive(Clone)]
pub struct CompositionPipeline { pub struct CompositionPipeline {
pub id: PipelineId, pub id: PipelineId,
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
pub script_chan: IpcSender<ConstellationControlMsg>, pub script_chan: IpcSender<ConstellationControlMsg>,
pub layout_chan: IpcSender<LayoutControlMsg>, pub layout_chan: IpcSender<LayoutControlMsg>,
} }

View file

@ -863,6 +863,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got get root pipeline message"); debug!("constellation got get root pipeline message");
self.handle_get_pipeline(browsing_context_id, resp_chan); self.handle_get_pipeline(browsing_context_id, resp_chan);
} }
FromCompositorMsg::GetFocusTopLevelBrowsingContext(resp_chan) => {
debug!("constellation got get focus browsing context message");
let focus_browsing_context = self.focus_pipeline_id
.and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
.map(|pipeline| pipeline.top_level_browsing_context_id);
let _ = resp_chan.send(focus_browsing_context);
}
FromCompositorMsg::GetPipelineTitle(pipeline_id) => { FromCompositorMsg::GetPipelineTitle(pipeline_id) => {
debug!("constellation got get-pipeline-title message"); debug!("constellation got get-pipeline-title message");
self.handle_get_pipeline_title_msg(pipeline_id); self.handle_get_pipeline_title_msg(pipeline_id);
@ -896,13 +903,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_init_load(url); self.handle_init_load(url);
} }
// Handle a forward or back request // Handle a forward or back request
FromCompositorMsg::TraverseHistory(pipeline_id, direction) => { // Handle a forward or back request
FromCompositorMsg::TraverseHistory(top_level_browsing_context_id, direction) => {
debug!("constellation got traverse history message from compositor"); debug!("constellation got traverse history message from compositor");
self.handle_traverse_history_msg(pipeline_id, direction); self.handle_traverse_history_msg(top_level_browsing_context_id, direction);
} }
FromCompositorMsg::WindowSize(new_size, size_type) => { FromCompositorMsg::WindowSize(top_level_browsing_context_id, new_size, size_type) => {
debug!("constellation got window resize message"); debug!("constellation got window resize message");
self.handle_window_size_msg(new_size, size_type); self.handle_window_size_msg(top_level_browsing_context_id, new_size, size_type);
} }
FromCompositorMsg::TickAnimation(pipeline_id, tick_type) => { FromCompositorMsg::TickAnimation(pipeline_id, tick_type) => {
self.handle_tick_animation(pipeline_id, tick_type) self.handle_tick_animation(pipeline_id, tick_type)
@ -911,9 +919,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got webdriver command message"); debug!("constellation got webdriver command message");
self.handle_webdriver_msg(command); self.handle_webdriver_msg(command);
} }
FromCompositorMsg::Reload => { FromCompositorMsg::Reload(top_level_browsing_context_id) => {
debug!("constellation got reload message"); debug!("constellation got reload message");
self.handle_reload_msg(); self.handle_reload_msg(top_level_browsing_context_id);
} }
FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => { FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => {
self.handle_log_entry(top_level_browsing_context_id, thread_name, entry); self.handle_log_entry(top_level_browsing_context_id, thread_name, entry);
@ -963,14 +971,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_load_complete_msg(pipeline_id) self.handle_load_complete_msg(pipeline_id)
} }
// Handle a forward or back request // Handle a forward or back request
FromScriptMsg::TraverseHistory(pipeline_id, direction) => { FromScriptMsg::TraverseHistory(top_level_browsing_context_id, direction) => {
debug!("constellation got traverse history message from script"); debug!("constellation got traverse history message from script");
self.handle_traverse_history_msg(pipeline_id, direction); self.handle_traverse_history_msg(top_level_browsing_context_id, direction);
} }
// Handle a joint session history length request. // Handle a joint session history length request.
FromScriptMsg::JointSessionHistoryLength(pipeline_id, sender) => { FromScriptMsg::JointSessionHistoryLength(top_level_browsing_context_id, sender) => {
debug!("constellation got joint session history length message from script"); debug!("constellation got joint session history length message from script");
self.handle_joint_session_history_length(pipeline_id, sender); self.handle_joint_session_history_length(top_level_browsing_context_id, sender);
} }
// Notification that the new document is ready to become active // Notification that the new document is ready to become active
FromScriptMsg::ActivateDocument(pipeline_id) => { FromScriptMsg::ActivateDocument(pipeline_id) => {
@ -1392,6 +1400,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let window_size = self.window_size.initial_viewport; let window_size = self.window_size.initial_viewport;
let root_pipeline_id = PipelineId::new(); let root_pipeline_id = PipelineId::new();
let root_browsing_context_id = self.root_browsing_context_id; let root_browsing_context_id = self.root_browsing_context_id;
self.focus_pipeline_id = Some(root_pipeline_id);
let load_data = LoadData::new(url.clone(), None, None, None); let load_data = LoadData::new(url.clone(), None, None, None);
let sandbox = IFrameSandboxState::IFrameUnsandboxed; let sandbox = IFrameSandboxState::IFrameUnsandboxed;
self.new_pipeline(root_pipeline_id, self.new_pipeline(root_pipeline_id,
@ -1530,6 +1539,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Pipeline::new(new_pipeline_id, Pipeline::new(new_pipeline_id,
browsing_context_id, browsing_context_id,
top_level_browsing_context_id,
Some((parent_pipeline_id, frame_type)), Some((parent_pipeline_id, frame_type)),
script_sender, script_sender,
layout_sender, layout_sender,
@ -1747,14 +1757,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn handle_traverse_history_msg(&mut self, fn handle_traverse_history_msg(&mut self,
pipeline_id: Option<PipelineId>, top_level_browsing_context_id: TopLevelBrowsingContextId,
direction: TraversalDirection) { direction: TraversalDirection)
let top_level_browsing_context_id = pipeline_id {
.and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
.and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id))
.map(|browsing_context| browsing_context.top_level_id)
.unwrap_or(self.root_browsing_context_id);
let mut size = 0; let mut size = 0;
let mut table = HashMap::new(); let mut table = HashMap::new();
@ -1784,12 +1789,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) { fn handle_joint_session_history_length(&self,
let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) top_level_browsing_context_id: TopLevelBrowsingContextId,
.and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id)) sender: IpcSender<u32>)
.map(|browsing_context| browsing_context.top_level_id) {
.unwrap_or(self.root_browsing_context_id);
// Initialize length at 1 to count for the current active entry // Initialize length at 1 to count for the current active entry
let mut length = 1; let mut length = 1;
for browsing_context in self.all_browsing_contexts_iter(top_level_browsing_context_id) { for browsing_context in self.all_browsing_contexts_iter(top_level_browsing_context_id) {
@ -1827,23 +1830,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
fn handle_reload_msg(&mut self) { fn handle_reload_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) {
// Send Reload constellation msg to root script channel. let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
let root_pipeline_id = self.browsing_contexts.get(&root_browsing_context_id) Some(browsing_context) => browsing_context.pipeline_id,
.map(|root_browsing_context| root_browsing_context.pipeline_id); None => return warn!("Browsing context {} got reload event after closure.", browsing_context_id),
};
if let Some(pipeline_id) = root_pipeline_id {
let msg = ConstellationControlMsg::Reload(pipeline_id); let msg = ConstellationControlMsg::Reload(pipeline_id);
let result = match self.pipelines.get(&pipeline_id) { let result = match self.pipelines.get(&pipeline_id) {
None => return warn!("Pipeline {} got reload event after closure.", pipeline_id),
Some(pipeline) => pipeline.event_loop.send(msg), Some(pipeline) => pipeline.event_loop.send(msg),
None => return debug!("Pipeline {:?} got reload event after closure.", pipeline_id),
}; };
if let Err(e) = result { if let Err(e) = result {
self.handle_send_error(pipeline_id, e); self.handle_send_error(pipeline_id, e);
} }
} }
}
fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) { fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) {
let result = match self.pipelines.get(&pipeline_id) { let result = match self.pipelines.get(&pipeline_id) {
@ -1894,10 +1895,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn handle_get_pipeline(&mut self, fn handle_get_pipeline(&mut self,
browsing_context_id: Option<BrowsingContextId>, browsing_context_id: BrowsingContextId,
resp_chan: IpcSender<Option<PipelineId>>) { resp_chan: IpcSender<Option<PipelineId>>) {
let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id);
let browsing_context_id = browsing_context_id.unwrap_or(root_browsing_context_id);
let current_pipeline_id = self.browsing_contexts.get(&browsing_context_id) let current_pipeline_id = self.browsing_contexts.get(&browsing_context_id)
.map(|browsing_context| browsing_context.pipeline_id); .map(|browsing_context| browsing_context.pipeline_id);
let pipeline_id_loaded = self.pending_changes.iter().rev() let pipeline_id_loaded = self.pending_changes.iter().rev()
@ -2033,17 +2032,22 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.webdriver.resize_channel = Some(reply); self.webdriver.resize_channel = Some(reply);
self.compositor_proxy.send(ToCompositorMsg::ResizeTo(size)); self.compositor_proxy.send(ToCompositorMsg::ResizeTo(size));
}, },
WebDriverCommandMsg::LoadUrl(pipeline_id, load_data, reply) => { WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, reply) => {
self.load_url_for_webdriver(pipeline_id, load_data, reply, false); self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, false);
}, },
WebDriverCommandMsg::Refresh(pipeline_id, reply) => { WebDriverCommandMsg::Refresh(top_level_browsing_context_id, reply) => {
let load_data = match self.pipelines.get(&pipeline_id) { let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
Some(pipeline) => LoadData::new(pipeline.url.clone(), None, None, None), let load_data = match self.browsing_contexts.get(&browsing_context_id) {
None => return warn!("Pipeline {:?} Refresh after closure.", pipeline_id), Some(browsing_context) => browsing_context.load_data.clone(),
None => return warn!("Browsing context {} Refresh after closure.", browsing_context_id),
}; };
self.load_url_for_webdriver(pipeline_id, load_data, reply, true); self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, true);
} }
WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd) => { WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd) => {
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id,
None => return warn!("Browsing context {} ScriptCommand after closure.", browsing_context_id),
};
let control_msg = ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, cmd); let control_msg = ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, cmd);
let result = match self.pipelines.get(&pipeline_id) { let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.event_loop.send(control_msg), Some(pipeline) => pipeline.event_loop.send(control_msg),
@ -2053,10 +2057,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_send_error(pipeline_id, e); self.handle_send_error(pipeline_id, e);
} }
}, },
WebDriverCommandMsg::SendKeys(pipeline_id, cmd) => { WebDriverCommandMsg::SendKeys(browsing_context_id, cmd) => {
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id,
None => return warn!("Browsing context {} SendKeys after closure.", browsing_context_id),
};
let event_loop = match self.pipelines.get(&pipeline_id) { let event_loop = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.event_loop.clone(), Some(pipeline) => pipeline.event_loop.clone(),
None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id), None => return warn!("Pipeline {} SendKeys after closure.", pipeline_id),
}; };
for (key, mods, state) in cmd { for (key, mods, state) in cmd {
let event = CompositorEvent::KeyEvent(None, key, state, mods); let event = CompositorEvent::KeyEvent(None, key, state, mods);
@ -2066,17 +2074,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
}, },
WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => { WebDriverCommandMsg::TakeScreenshot(_, reply) => {
let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id);
let current_pipeline_id = self.browsing_contexts.get(&root_browsing_context_id)
.map(|root_browsing_context| root_browsing_context.pipeline_id);
if Some(pipeline_id) == current_pipeline_id {
self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply)); self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply));
} else {
if let Err(e) = reply.send(None) {
warn!("Screenshot reply failed ({})", e);
}
}
}, },
} }
} }
@ -2267,13 +2266,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn load_url_for_webdriver(&mut self, fn load_url_for_webdriver(&mut self,
pipeline_id: PipelineId, top_level_browsing_context_id: TopLevelBrowsingContextId,
load_data: LoadData, load_data: LoadData,
reply: IpcSender<webdriver_msg::LoadStatus>, reply: IpcSender<webdriver_msg::LoadStatus>,
replace: bool) { replace: bool)
let new_pipeline_id = self.load_url(pipeline_id, load_data, replace); {
if let Some(id) = new_pipeline_id { let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
self.webdriver.load_channel = Some((id, reply)); let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id,
None => return warn!("Webdriver load for closed browsing context {}.", browsing_context_id),
};
if let Some(new_pipeline_id) = self.load_url(pipeline_id, load_data, replace) {
self.webdriver.load_channel = Some((new_pipeline_id, reply));
} }
} }
@ -2369,10 +2373,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
/// Called when the window is resized. /// Called when the window is resized.
fn handle_window_size_msg(&mut self, new_size: WindowSizeData, size_type: WindowSizeType) { fn handle_window_size_msg(&mut self,
top_level_browsing_context_id: TopLevelBrowsingContextId,
new_size: WindowSizeData,
size_type: WindowSizeType)
{
debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped()); debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped());
let browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
self.resize_browsing_context(new_size, size_type, browsing_context_id); self.resize_browsing_context(new_size, size_type, browsing_context_id);
if let Some(resize_channel) = self.webdriver.resize_channel.take() { if let Some(resize_channel) = self.webdriver.resize_channel.take() {
@ -2792,9 +2800,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let top_level_browsing_context_id = self.browsing_contexts.get(&pipeline.browsing_context_id) let top_level_browsing_context_id = self.browsing_contexts.get(&pipeline.browsing_context_id)
.map(|browsing_context| browsing_context.top_level_id) .map(|browsing_context| browsing_context.top_level_id)
.unwrap_or(self.root_browsing_context_id); .unwrap_or(self.root_browsing_context_id);
let url = pipeline.url.clone();
let can_go_forward = !self.joint_session_future_is_empty(top_level_browsing_context_id); let can_go_forward = !self.joint_session_future_is_empty(top_level_browsing_context_id);
let can_go_back = !self.joint_session_past_is_empty(top_level_browsing_context_id); let can_go_back = !self.joint_session_past_is_empty(top_level_browsing_context_id);
let url = pipeline.url.to_string();
let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward); let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward);
parent.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event); parent.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event);
}, },

View file

@ -52,6 +52,9 @@ pub struct Pipeline {
/// The ID of the browsing context that contains this Pipeline. /// The ID of the browsing context that contains this Pipeline.
pub browsing_context_id: BrowsingContextId, pub browsing_context_id: BrowsingContextId,
/// The ID of the top-level browsing context that contains this Pipeline.
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
/// The parent pipeline of this one. `None` if this is a root pipeline. /// The parent pipeline of this one. `None` if this is a root pipeline.
/// Note that because of mozbrowser iframes, even top-level pipelines /// Note that because of mozbrowser iframes, even top-level pipelines
/// may have a parent (in which case the frame type will be /// may have a parent (in which case the frame type will be
@ -282,6 +285,7 @@ impl Pipeline {
Ok(Pipeline::new(state.id, Ok(Pipeline::new(state.id,
state.browsing_context_id, state.browsing_context_id,
state.top_level_browsing_context_id,
state.parent_info, state.parent_info,
script_chan, script_chan,
pipeline_chan, pipeline_chan,
@ -295,6 +299,7 @@ impl Pipeline {
/// spawned. /// spawned.
pub fn new(id: PipelineId, pub fn new(id: PipelineId,
browsing_context_id: BrowsingContextId, browsing_context_id: BrowsingContextId,
top_level_browsing_context_id: TopLevelBrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>, parent_info: Option<(PipelineId, FrameType)>,
event_loop: Rc<EventLoop>, event_loop: Rc<EventLoop>,
layout_chan: IpcSender<LayoutControlMsg>, layout_chan: IpcSender<LayoutControlMsg>,
@ -306,6 +311,7 @@ impl Pipeline {
let pipeline = Pipeline { let pipeline = Pipeline {
id: id, id: id,
browsing_context_id: browsing_context_id, browsing_context_id: browsing_context_id,
top_level_browsing_context_id: top_level_browsing_context_id,
parent_info: parent_info, parent_info: parent_info,
event_loop: event_loop, event_loop: event_loop,
layout_chan: layout_chan, layout_chan: layout_chan,
@ -372,6 +378,7 @@ impl Pipeline {
pub fn to_sendable(&self) -> CompositionPipeline { pub fn to_sendable(&self) -> CompositionPipeline {
CompositionPipeline { CompositionPipeline {
id: self.id.clone(), id: self.id.clone(),
top_level_browsing_context_id: self.top_level_browsing_context_id.clone(),
script_chan: self.event_loop.sender(), script_chan: self.event_loop.sender(),
layout_chan: self.layout_chan.clone(), layout_chan: self.layout_chan.clone(),
} }

View file

@ -44,10 +44,9 @@ impl History {
if !self.window.Document().is_fully_active() { if !self.window.Document().is_fully_active() {
return Err(Error::Security); return Err(Error::Security);
} }
let global_scope = self.window.upcast::<GlobalScope>(); let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id();
let pipeline = global_scope.pipeline_id(); let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg);
let _ = global_scope.constellation_chan().send(msg);
Ok(()) Ok(())
} }
} }
@ -58,11 +57,10 @@ impl HistoryMethods for History {
if !self.window.Document().is_fully_active() { if !self.window.Document().is_fully_active() {
return Err(Error::Security); return Err(Error::Security);
} }
let global_scope = self.window.upcast::<GlobalScope>(); let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id();
let pipeline = global_scope.pipeline_id();
let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length."); let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length.");
let msg = ConstellationMsg::JointSessionHistoryLength(pipeline, sender); let msg = ConstellationMsg::JointSessionHistoryLength(top_level_browsing_context_id, sender);
let _ = global_scope.constellation_chan().send(msg); let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg);
Ok(recv.recv().unwrap()) Ok(recv.recv().unwrap())
} }

View file

@ -498,7 +498,7 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent,
} }
MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => { MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => {
BrowserElementLocationChangeEventDetail { BrowserElementLocationChangeEventDetail {
url: Some(DOMString::from(url)), url: Some(DOMString::from(url.as_str())),
canGoBack: Some(can_go_back), canGoBack: Some(can_go_back),
canGoForward: Some(can_go_forward), canGoForward: Some(can_go_forward),
}.to_jsval(cx, rval); }.to_jsval(cx, rval);
@ -540,19 +540,17 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent,
pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult { pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult {
if iframe.Mozbrowser() { if iframe.Mozbrowser() {
if iframe.upcast::<Node>().is_in_doc_with_browsing_context() { if let Some(top_level_browsing_context_id) = iframe.top_level_browsing_context_id() {
let window = window_from_node(iframe); let window = window_from_node(iframe);
let msg = ConstellationMsg::TraverseHistory(iframe.pipeline_id(), direction); let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
return Ok(());
}
} }
Ok(())
} else {
debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top", debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top",
"level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)")); "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"));
Err(Error::NotSupported) Err(Error::NotSupported)
} }
}
impl HTMLIFrameElementMethods for HTMLIFrameElement { impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-src // https://html.spec.whatwg.org/multipage/#dom-iframe-src

View file

@ -1280,8 +1280,8 @@ impl ScriptThread {
webdriver_handlers::handle_get_rect(&*documents, pipeline_id, node_id, reply), webdriver_handlers::handle_get_rect(&*documents, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetElementText(node_id, reply) => WebDriverScriptCommand::GetElementText(node_id, reply) =>
webdriver_handlers::handle_get_text(&*documents, pipeline_id, node_id, reply), webdriver_handlers::handle_get_text(&*documents, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetPipelineId(browsing_context_id, reply) => WebDriverScriptCommand::GetBrowsingContextId(webdriver_frame_id, reply) =>
webdriver_handlers::handle_get_pipeline_id(&*documents, pipeline_id, browsing_context_id, reply), webdriver_handlers::handle_get_browsing_context_id(&*documents, pipeline_id, webdriver_frame_id, reply),
WebDriverScriptCommand::GetUrl(reply) => WebDriverScriptCommand::GetUrl(reply) =>
webdriver_handlers::handle_get_url(&*documents, pipeline_id, reply), webdriver_handlers::handle_get_url(&*documents, pipeline_id, reply),
WebDriverScriptCommand::IsEnabled(element_id, reply) => WebDriverScriptCommand::IsEnabled(element_id, reply) =>

View file

@ -29,6 +29,7 @@ use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use msg::constellation_msg::BrowsingContextId;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::CookieSource::{HTTP, NonHTTP}; use net_traits::CookieSource::{HTTP, NonHTTP};
use net_traits::CoreResourceMsg::{GetCookiesDataForUrl, SetCookieForUrl}; use net_traits::CoreResourceMsg::{GetCookiesDataForUrl, SetCookieForUrl};
@ -109,23 +110,23 @@ pub fn handle_execute_async_script(documents: &Documents,
window.upcast::<GlobalScope>().evaluate_js_on_global_with_result(&eval, rval.handle_mut()); window.upcast::<GlobalScope>().evaluate_js_on_global_with_result(&eval, rval.handle_mut());
} }
pub fn handle_get_pipeline_id(documents: &Documents, pub fn handle_get_browsing_context_id(documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,
webdriver_frame_id: WebDriverFrameId, webdriver_frame_id: WebDriverFrameId,
reply: IpcSender<Result<Option<PipelineId>, ()>>) { reply: IpcSender<Result<BrowsingContextId, ()>>) {
let result = match webdriver_frame_id { let result = match webdriver_frame_id {
WebDriverFrameId::Short(_) => { WebDriverFrameId::Short(_) => {
// This isn't supported yet // This isn't supported yet
Ok(None) Err(())
}, },
WebDriverFrameId::Element(x) => { WebDriverFrameId::Element(x) => {
find_node_by_unique_id(documents, pipeline, x) find_node_by_unique_id(documents, pipeline, x)
.and_then(|node| node.downcast::<HTMLIFrameElement>().map(|elem| elem.pipeline_id())) .and_then(|node| node.downcast::<HTMLIFrameElement>().and_then(|elem| elem.browsing_context_id()))
.ok_or(()) .ok_or(())
}, },
WebDriverFrameId::Parent => { WebDriverFrameId::Parent => {
documents.find_window(pipeline) documents.find_window(pipeline)
.map(|window| window.parent_info().map(|(parent_id, _)| parent_id)) .and_then(|window| window.window_proxy().parent().map(|parent| parent.browsing_context_id()))
.ok_or(()) .ok_or(())
} }
}; };

View file

@ -602,7 +602,7 @@ pub enum MozBrowserEvent {
/// Sent when the browser `<iframe>` starts to load a new page. /// Sent when the browser `<iframe>` starts to load a new page.
LoadStart, LoadStart,
/// Sent when a browser `<iframe>`'s location changes. /// Sent when a browser `<iframe>`'s location changes.
LocationChange(String, bool, bool), LocationChange(ServoUrl, bool, bool),
/// Sent when a new tab is opened within a browser `<iframe>` as a result of the user /// Sent when a new tab is opened within a browser `<iframe>` as a result of the user
/// issuing a command to open a link target in a new tab (for example ctrl/cmd + click.) /// issuing a command to open a link target in a new tab (for example ctrl/cmd + click.)
/// Includes the URL. /// Includes the URL.
@ -715,21 +715,20 @@ pub enum WindowSizeType {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub enum WebDriverCommandMsg { pub enum WebDriverCommandMsg {
/// Get the window size. /// Get the window size.
GetWindowSize(PipelineId, IpcSender<WindowSizeData>), GetWindowSize(TopLevelBrowsingContextId, IpcSender<WindowSizeData>),
/// Load a URL in the pipeline with the given ID. /// Load a URL in the top-level browsing context with the given ID.
LoadUrl(PipelineId, LoadData, IpcSender<LoadStatus>), LoadUrl(TopLevelBrowsingContextId, LoadData, IpcSender<LoadStatus>),
/// Refresh the pipeline with the given ID. /// Refresh the top-level browsing context with the given ID.
Refresh(PipelineId, IpcSender<LoadStatus>), Refresh(TopLevelBrowsingContextId, IpcSender<LoadStatus>),
/// Pass a webdriver command to the script thread of the pipeline with the /// Pass a webdriver command to the script thread of the current pipeline
/// given ID for execution. /// of a browsing context.
ScriptCommand(PipelineId, WebDriverScriptCommand), ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
/// Act as if keys were pressed in the pipeline with the given ID. /// Act as if keys were pressed in the browsing context with the given ID.
SendKeys(PipelineId, Vec<(Key, KeyModifiers, KeyState)>), SendKeys(BrowsingContextId, Vec<(Key, KeyModifiers, KeyState)>),
/// Set the window size. /// Set the window size.
SetWindowSize(PipelineId, Size2D<u32>, IpcSender<WindowSizeData>), SetWindowSize(TopLevelBrowsingContextId, Size2D<u32>, IpcSender<WindowSizeData>),
/// Take a screenshot of the window, if the pipeline with the given ID is /// Take a screenshot of the window.
/// the root pipeline. TakeScreenshot(TopLevelBrowsingContextId, IpcSender<Option<Image>>),
TakeScreenshot(PipelineId, IpcSender<Option<Image>>),
} }
/// Messages to the constellation. /// Messages to the constellation.
@ -740,10 +739,12 @@ pub enum ConstellationMsg {
/// Request that the constellation send the BrowsingContextId corresponding to the document /// Request that the constellation send the BrowsingContextId corresponding to the document
/// with the provided pipeline id /// with the provided pipeline id
GetBrowsingContext(PipelineId, IpcSender<Option<BrowsingContextId>>), GetBrowsingContext(PipelineId, IpcSender<Option<BrowsingContextId>>),
/// Request that the constellation send the current pipeline id for the provided frame /// Request that the constellation send the current pipeline id for the provided
/// id, or for the root frame if this is None, over a provided channel. /// browsing context id, over a provided channel.
/// Also returns a boolean saying whether the document has finished loading or not. GetPipeline(BrowsingContextId, IpcSender<Option<PipelineId>>),
GetPipeline(Option<BrowsingContextId>, IpcSender<Option<PipelineId>>), /// Request that the constellation send the current focused top-level browsing context id,
/// over a provided channel.
GetFocusTopLevelBrowsingContext(IpcSender<Option<TopLevelBrowsingContextId>>),
/// Requests that the constellation inform the compositor of the title of the pipeline /// Requests that the constellation inform the compositor of the title of the pipeline
/// immediately. /// immediately.
GetPipelineTitle(PipelineId), GetPipelineTitle(PipelineId),
@ -755,16 +756,16 @@ pub enum ConstellationMsg {
KeyEvent(Option<char>, Key, KeyState, KeyModifiers), KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Request to load a page. /// Request to load a page.
LoadUrl(PipelineId, LoadData), LoadUrl(PipelineId, LoadData),
/// Request to traverse the joint session history. /// Request to traverse the joint session history of the provided browsing context.
TraverseHistory(Option<PipelineId>, TraversalDirection), TraverseHistory(TopLevelBrowsingContextId, TraversalDirection),
/// Inform the constellation of a window being resized. /// Inform the constellation of a window being resized.
WindowSize(WindowSizeData, WindowSizeType), WindowSize(TopLevelBrowsingContextId, WindowSizeData, WindowSizeType),
/// Requests that the constellation instruct layout to begin a new tick of the animation. /// Requests that the constellation instruct layout to begin a new tick of the animation.
TickAnimation(PipelineId, AnimationTickType), TickAnimation(PipelineId, AnimationTickType),
/// Dispatch a webdriver command /// Dispatch a webdriver command
WebDriverCommand(WebDriverCommandMsg), WebDriverCommand(WebDriverCommandMsg),
/// Reload the current page. /// Reload a top-level browsing context.
Reload, Reload(TopLevelBrowsingContextId),
/// A log entry, with the top-level browsing context id and thread name /// A log entry, with the top-level browsing context id and thread name
LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry), LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry),
/// Set the WebVR thread channel. /// Set the WebVR thread channel.

View file

@ -86,7 +86,7 @@ pub enum ScriptMsg {
ForwardEvent(PipelineId, CompositorEvent), ForwardEvent(PipelineId, CompositorEvent),
/// Requests that the constellation retrieve the current contents of the clipboard /// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(IpcSender<String>), GetClipboardContents(IpcSender<String>),
/// Get the frame id for a given pipeline. /// Get the browsing context id for a given pipeline.
GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>), GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>),
/// Get the parent info for a given pipeline. /// Get the parent info for a given pipeline.
GetParentInfo(PipelineId, IpcSender<Option<(PipelineId, FrameType)>>), GetParentInfo(PipelineId, IpcSender<Option<(PipelineId, FrameType)>>),
@ -104,9 +104,9 @@ pub enum ScriptMsg {
/// The first PipelineId is for the parent, the second is for the originating pipeline. /// The first PipelineId is for the parent, the second is for the originating pipeline.
MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent), MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent),
/// HTMLIFrameElement Forward or Back traversal. /// HTMLIFrameElement Forward or Back traversal.
TraverseHistory(Option<PipelineId>, TraversalDirection), TraverseHistory(TopLevelBrowsingContextId, TraversalDirection),
/// Gets the length of the joint session history from the constellation. /// Gets the length of the joint session history from the constellation.
JointSessionHistoryLength(PipelineId, IpcSender<u32>), JointSessionHistoryLength(TopLevelBrowsingContextId, IpcSender<u32>),
/// Favicon detected /// Favicon detected
NewFavicon(ServoUrl), NewFavicon(ServoUrl),
/// Status message to be displayed in the chrome, eg. a link URL on mouseover. /// Status message to be displayed in the chrome, eg. a link URL on mouseover.

View file

@ -8,7 +8,7 @@ use cookie_rs::Cookie;
use euclid::rect::Rect; use euclid::rect::Rect;
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::BrowsingContextId;
use rustc_serialize::json::{Json, ToJson}; use rustc_serialize::json::{Json, ToJson};
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -31,7 +31,7 @@ pub enum WebDriverScriptCommand {
GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>), GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>),
GetElementTagName(String, IpcSender<Result<String, ()>>), GetElementTagName(String, IpcSender<Result<String, ()>>),
GetElementText(String, IpcSender<Result<String, ()>>), GetElementText(String, IpcSender<Result<String, ()>>),
GetPipelineId(WebDriverFrameId, IpcSender<Result<Option<PipelineId>, ()>>), GetBrowsingContextId(WebDriverFrameId, IpcSender<Result<BrowsingContextId, ()>>),
GetUrl(IpcSender<ServoUrl>), GetUrl(IpcSender<ServoUrl>),
IsEnabled(String, IpcSender<Result<bool, ()>>), IsEnabled(String, IpcSender<Result<bool, ()>>),
IsSelected(String, IpcSender<Result<bool, ()>>), IsSelected(String, IpcSender<Result<bool, ()>>),

View file

@ -32,7 +32,7 @@ use hyper::method::Method::{self, Post};
use image::{DynamicImage, ImageFormat, RgbImage}; use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use keys::keycodes_to_keys; use keys::keycodes_to_keys;
use msg::constellation_msg::{BrowsingContextId, PipelineId, TraversalDirection}; use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, TraversalDirection};
use net_traits::image::base::PixelFormat; use net_traits::image::base::PixelFormat;
use regex::Captures; use regex::Captures;
use rustc_serialize::json::{Json, ToJson}; use rustc_serialize::json::{Json, ToJson};
@ -102,7 +102,8 @@ pub fn start_server(port: u16, constellation_chan: Sender<ConstellationMsg>) {
/// Represents the current WebDriver session and holds relevant session state. /// Represents the current WebDriver session and holds relevant session state.
struct WebDriverSession { struct WebDriverSession {
id: Uuid, id: Uuid,
browsing_context_id: Option<BrowsingContextId>, browsing_context_id: BrowsingContextId,
top_level_browsing_context_id: TopLevelBrowsingContextId,
/// Time to wait for injected scripts to run before interrupting them. A [`None`] value /// Time to wait for injected scripts to run before interrupting them. A [`None`] value
/// specifies that the script should run indefinitely. /// specifies that the script should run indefinitely.
@ -117,10 +118,14 @@ struct WebDriverSession {
} }
impl WebDriverSession { impl WebDriverSession {
pub fn new() -> WebDriverSession { pub fn new(browsing_context_id: BrowsingContextId,
top_level_browsing_context_id: TopLevelBrowsingContextId)
-> WebDriverSession
{
WebDriverSession { WebDriverSession {
id: Uuid::new_v4(), id: Uuid::new_v4(),
browsing_context_id: None, browsing_context_id: browsing_context_id,
top_level_browsing_context_id: top_level_browsing_context_id,
script_timeout: Some(30_000), script_timeout: Some(30_000),
load_timeout: Some(300_000), load_timeout: Some(300_000),
@ -264,33 +269,28 @@ impl Handler {
} }
} }
fn pipeline_id(&self, frame_id: Option<BrowsingContextId>) -> WebDriverResult<PipelineId> { fn focus_top_level_browsing_context_id(&self) -> WebDriverResult<TopLevelBrowsingContextId> {
debug!("Getting focused context.");
let interval = 20; let interval = 20;
let iterations = 30_000 / interval; let iterations = 30_000 / interval;
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
for _ in 0..iterations { for _ in 0..iterations {
let msg = ConstellationMsg::GetPipeline(frame_id, sender.clone()); let msg = ConstellationMsg::GetFocusTopLevelBrowsingContext(sender.clone());
self.constellation_chan.send(msg).unwrap(); self.constellation_chan.send(msg).unwrap();
// Wait until the document is ready before returning the pipeline id. // Wait until the document is ready before returning the top-level browsing context id.
if let Some(x) = receiver.recv().unwrap() { if let Some(x) = receiver.recv().unwrap() {
debug!("Focused context is {}", x);
return Ok(x); return Ok(x);
} }
thread::sleep(Duration::from_millis(interval)); thread::sleep(Duration::from_millis(interval));
} }
debug!("Timed out getting focused context.");
Err(WebDriverError::new(ErrorStatus::Timeout, Err(WebDriverError::new(ErrorStatus::Timeout,
"Failed to get window handle")) "Failed to get window handle"))
} }
fn root_pipeline(&self) -> WebDriverResult<PipelineId> {
self.pipeline_id(None)
}
fn frame_pipeline(&self) -> WebDriverResult<PipelineId> {
self.pipeline_id(self.session.as_ref().and_then(|session| session.browsing_context_id))
}
fn session(&self) -> WebDriverResult<&WebDriverSession> { fn session(&self) -> WebDriverResult<&WebDriverSession> {
match self.session { match self.session {
Some(ref x) => Ok(x), Some(ref x) => Ok(x),
@ -299,31 +299,30 @@ impl Handler {
} }
} }
fn set_browsing_context_id(&mut self, browsing_context_id: Option<BrowsingContextId>) -> WebDriverResult<()> { fn session_mut(&mut self) -> WebDriverResult<&mut WebDriverSession> {
match self.session { match self.session {
Some(ref mut x) => { Some(ref mut x) => Ok(x),
x.browsing_context_id = browsing_context_id;
Ok(())
},
None => Err(WebDriverError::new(ErrorStatus::SessionNotCreated, None => Err(WebDriverError::new(ErrorStatus::SessionNotCreated,
"Session not created")) "Session not created"))
} }
} }
fn handle_new_session(&mut self) -> WebDriverResult<WebDriverResponse> { fn handle_new_session(&mut self) -> WebDriverResult<WebDriverResponse> {
debug!("new session");
if self.session.is_none() { if self.session.is_none() {
let session = WebDriverSession::new(); let top_level_browsing_context_id = self.focus_top_level_browsing_context_id()?;
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
let session = WebDriverSession::new(browsing_context_id, top_level_browsing_context_id);
let mut capabilities = BTreeMap::new(); let mut capabilities = BTreeMap::new();
capabilities.insert("browserName".to_owned(), "servo".to_json()); capabilities.insert("browserName".to_owned(), "servo".to_json());
capabilities.insert("browserVersion".to_owned(), "0.0.1".to_json()); capabilities.insert("browserVersion".to_owned(), "0.0.1".to_json());
capabilities.insert("acceptInsecureCerts".to_owned(), false.to_json()); capabilities.insert("acceptInsecureCerts".to_owned(), false.to_json());
let rv = Ok(WebDriverResponse::NewSession( let response = NewSessionResponse::new(session.id.to_string(), Json::Object(capabilities));
NewSessionResponse::new( debug!("new session created {}.", session.id);
session.id.to_string(),
Json::Object(capabilities))));
self.session = Some(session); self.session = Some(session);
rv Ok(WebDriverResponse::NewSession(response))
} else { } else {
debug!("new session failed.");
Err(WebDriverError::new(ErrorStatus::UnknownError, Err(WebDriverError::new(ErrorStatus::UnknownError,
"Session already created")) "Session already created"))
} }
@ -334,16 +333,18 @@ impl Handler {
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
} }
#[inline] fn browsing_context_script_command(&self, cmd_msg: WebDriverScriptCommand) -> WebDriverResult<()> {
fn frame_script_command(&self, cmd_msg: WebDriverScriptCommand) -> WebDriverResult<()> { let browsing_context_id = self.session()?.browsing_context_id;
Ok(self.constellation_chan.send(ConstellationMsg::WebDriverCommand( let msg = ConstellationMsg::WebDriverCommand(WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd_msg));
WebDriverCommandMsg::ScriptCommand(try!(self.frame_pipeline()), cmd_msg))).unwrap()) self.constellation_chan.send(msg).unwrap();
Ok(())
} }
#[inline] fn top_level_script_command(&self, cmd_msg: WebDriverScriptCommand) -> WebDriverResult<()> {
fn root_script_command(&self, cmd_msg: WebDriverScriptCommand) -> WebDriverResult<()> { let browsing_context_id = BrowsingContextId::from(self.session()?.top_level_browsing_context_id);
Ok(self.constellation_chan.send(ConstellationMsg::WebDriverCommand( let msg = ConstellationMsg::WebDriverCommand(WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd_msg));
WebDriverCommandMsg::ScriptCommand(try!(self.root_pipeline()), cmd_msg))).unwrap()) self.constellation_chan.send(msg).unwrap();
Ok(())
} }
fn handle_get(&self, parameters: &GetParameters) -> WebDriverResult<WebDriverResponse> { fn handle_get(&self, parameters: &GetParameters) -> WebDriverResult<WebDriverResponse> {
@ -353,12 +354,12 @@ impl Handler {
"Invalid URL")) "Invalid URL"))
}; };
let pipeline_id = try!(self.root_pipeline()); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let load_data = LoadData::new(url, Some(pipeline_id), None, None); let load_data = LoadData::new(url, None, None, None);
let cmd_msg = WebDriverCommandMsg::LoadUrl(pipeline_id, load_data, sender.clone()); let cmd_msg = WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, sender.clone());
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
self.wait_for_load(sender, receiver) self.wait_for_load(sender, receiver)
@ -368,15 +369,10 @@ impl Handler {
sender: IpcSender<LoadStatus>, sender: IpcSender<LoadStatus>,
receiver: IpcReceiver<LoadStatus>) receiver: IpcReceiver<LoadStatus>)
-> WebDriverResult<WebDriverResponse> { -> WebDriverResult<WebDriverResponse> {
let session = try!(self.session let timeout = self.session()?.load_timeout;
.as_ref()
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
let timeout = session.load_timeout;
let timeout_chan = sender;
thread::spawn(move || { thread::spawn(move || {
thread::sleep(Duration::from_millis(timeout.unwrap())); thread::sleep(Duration::from_millis(timeout.unwrap()));
let _ = timeout_chan.send(LoadStatus::LoadTimeout); let _ = sender.send(LoadStatus::LoadTimeout);
}); });
// wait to get a load event // wait to get a load event
@ -390,7 +386,7 @@ impl Handler {
fn handle_current_url(&self) -> WebDriverResult<WebDriverResponse> { fn handle_current_url(&self) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.root_script_command(WebDriverScriptCommand::GetUrl(sender))); self.top_level_script_command(WebDriverScriptCommand::GetUrl(sender))?;
let url = receiver.recv().unwrap(); let url = receiver.recv().unwrap();
@ -399,8 +395,8 @@ impl Handler {
fn handle_window_size(&self) -> WebDriverResult<WebDriverResponse> { fn handle_window_size(&self) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let pipeline_id = try!(self.root_pipeline()); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let cmd_msg = WebDriverCommandMsg::GetWindowSize(pipeline_id, sender); let cmd_msg = WebDriverCommandMsg::GetWindowSize(top_level_browsing_context_id, sender);
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
@ -413,8 +409,8 @@ impl Handler {
fn handle_set_window_size(&self, params: &WindowSizeParameters) -> WebDriverResult<WebDriverResponse> { fn handle_set_window_size(&self, params: &WindowSizeParameters) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let size = Size2D::new(params.width as u32, params.height as u32); let size = Size2D::new(params.width as u32, params.height as u32);
let pipeline_id = try!(self.root_pipeline()); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let cmd_msg = WebDriverCommandMsg::SetWindowSize(pipeline_id, size, sender.clone()); let cmd_msg = WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, sender.clone());
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
@ -424,7 +420,7 @@ impl Handler {
// On timeout, we send a GetWindowSize message to the constellation, // On timeout, we send a GetWindowSize message to the constellation,
// which will give the current window size. // which will give the current window size.
thread::sleep(Duration::from_millis(timeout as u64)); thread::sleep(Duration::from_millis(timeout as u64));
let cmd_msg = WebDriverCommandMsg::GetWindowSize(pipeline_id, sender); let cmd_msg = WebDriverCommandMsg::GetWindowSize(top_level_browsing_context_id, sender);
constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
}); });
@ -437,7 +433,7 @@ impl Handler {
fn handle_is_enabled(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_is_enabled(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.root_script_command(WebDriverScriptCommand::IsEnabled(element.id.clone(), sender))); self.top_level_script_command(WebDriverScriptCommand::IsEnabled(element.id.clone(), sender))?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(is_enabled) => Ok(WebDriverResponse::Generic(ValueResponse::new(is_enabled.to_json()))), Ok(is_enabled) => Ok(WebDriverResponse::Generic(ValueResponse::new(is_enabled.to_json()))),
@ -448,7 +444,7 @@ impl Handler {
fn handle_is_selected(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_is_selected(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.root_script_command(WebDriverScriptCommand::IsSelected(element.id.clone(), sender))); self.top_level_script_command(WebDriverScriptCommand::IsSelected(element.id.clone(), sender))?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(is_selected) => Ok(WebDriverResponse::Generic(ValueResponse::new(is_selected.to_json()))), Ok(is_selected) => Ok(WebDriverResponse::Generic(ValueResponse::new(is_selected.to_json()))),
@ -457,21 +453,27 @@ impl Handler {
} }
fn handle_go_back(&self) -> WebDriverResult<WebDriverResponse> { fn handle_go_back(&self) -> WebDriverResult<WebDriverResponse> {
self.constellation_chan.send(ConstellationMsg::TraverseHistory(None, TraversalDirection::Back(1))).unwrap(); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let direction = TraversalDirection::Back(1);
let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
self.constellation_chan.send(msg).unwrap();
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
} }
fn handle_go_forward(&self) -> WebDriverResult<WebDriverResponse> { fn handle_go_forward(&self) -> WebDriverResult<WebDriverResponse> {
self.constellation_chan.send(ConstellationMsg::TraverseHistory(None, TraversalDirection::Forward(1))).unwrap(); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let direction = TraversalDirection::Forward(1);
let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
self.constellation_chan.send(msg).unwrap();
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
} }
fn handle_refresh(&self) -> WebDriverResult<WebDriverResponse> { fn handle_refresh(&self) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.root_pipeline()); let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let cmd_msg = WebDriverCommandMsg::Refresh(pipeline_id, sender.clone()); let cmd_msg = WebDriverCommandMsg::Refresh(top_level_browsing_context_id, sender.clone());
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
self.wait_for_load(sender, receiver) self.wait_for_load(sender, receiver)
@ -480,7 +482,7 @@ impl Handler {
fn handle_title(&self) -> WebDriverResult<WebDriverResponse> { fn handle_title(&self) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.root_script_command(WebDriverScriptCommand::GetTitle(sender))); self.top_level_script_command(WebDriverScriptCommand::GetTitle(sender))?;
let value = receiver.recv().unwrap(); let value = receiver.recv().unwrap();
Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))) Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json())))
@ -508,8 +510,8 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::FindElementCSS(parameters.value.clone(), let cmd = WebDriverScriptCommand::FindElementCSS(parameters.value.clone(), sender);
sender))); self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => { Ok(value) => {
@ -525,8 +527,9 @@ impl Handler {
use webdriver::common::FrameId; use webdriver::common::FrameId;
let frame_id = match parameters.id { let frame_id = match parameters.id {
FrameId::Null => { FrameId::Null => {
self.set_browsing_context_id(None).unwrap(); let session = self.session_mut()?;
return Ok(WebDriverResponse::Void) session.browsing_context_id = BrowsingContextId::from(session.top_level_browsing_context_id);
return Ok(WebDriverResponse::Void);
}, },
FrameId::Short(ref x) => WebDriverFrameId::Short(*x), FrameId::Short(ref x) => WebDriverFrameId::Short(*x),
FrameId::Element(ref x) => WebDriverFrameId::Element(x.id.clone()) FrameId::Element(ref x) => WebDriverFrameId::Element(x.id.clone())
@ -545,28 +548,15 @@ impl Handler {
return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
"Selecting frame by id not supported")); "Selecting frame by id not supported"));
} }
let pipeline_id = try!(self.frame_pipeline());
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetPipelineId(frame_id, sender);
{
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(
WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd))).unwrap();
}
let context_id = match receiver.recv().unwrap() {
Ok(Some(pipeline_id)) => {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
self.constellation_chan.send(ConstellationMsg::GetBrowsingContext(pipeline_id, sender)).unwrap(); let cmd = WebDriverScriptCommand::GetBrowsingContextId(frame_id, sender);
receiver.recv().unwrap() self.browsing_context_script_command(cmd)?;
},
Ok(None) => None,
Err(_) => {
return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"Frame does not exist"));
}
};
self.set_browsing_context_id(context_id).unwrap(); let browsing_context_id = receiver.recv().unwrap()
.or(Err(WebDriverError::new(ErrorStatus::NoSuchFrame, "Frame does not exist")))?;
self.session_mut()?.browsing_context_id = browsing_context_id;
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
} }
@ -578,8 +568,8 @@ impl Handler {
} }
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::FindElementsCSS(parameters.value.clone(), let cmd = WebDriverScriptCommand::FindElementsCSS(parameters.value.clone(), sender);
sender))); self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => { Ok(value) => {
let resp_value: Vec<Json> = value.into_iter().map( let resp_value: Vec<Json> = value.into_iter().map(
@ -594,7 +584,8 @@ impl Handler {
// https://w3c.github.io/webdriver/webdriver-spec.html#get-element-rect // https://w3c.github.io/webdriver/webdriver-spec.html#get-element-rect
fn handle_element_rect(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_element_rect(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetElementRect(element.id.clone(), sender))); let cmd = WebDriverScriptCommand::GetElementRect(element.id.clone(), sender);
self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(rect) => { Ok(rect) => {
let response = ElementRectResponse::new(rect.origin.x, rect.origin.y, let response = ElementRectResponse::new(rect.origin.x, rect.origin.y,
@ -608,7 +599,8 @@ impl Handler {
fn handle_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetElementText(element.id.clone(), sender))); let cmd = WebDriverScriptCommand::GetElementText(element.id.clone(), sender);
self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference, Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference,
@ -618,14 +610,16 @@ impl Handler {
fn handle_active_element(&self) -> WebDriverResult<WebDriverResponse> { fn handle_active_element(&self) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetActiveElement(sender))); let cmd = WebDriverScriptCommand::GetActiveElement(sender);
self.browsing_context_script_command(cmd)?;
let value = receiver.recv().unwrap().map(|x| WebElement::new(x).to_json()); let value = receiver.recv().unwrap().map(|x| WebElement::new(x).to_json());
Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))) Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json())))
} }
fn handle_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetElementTagName(element.id.clone(), sender))); let cmd = WebDriverScriptCommand::GetElementTagName(element.id.clone(), sender);
self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference, Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference,
@ -635,8 +629,8 @@ impl Handler {
fn handle_element_attribute(&self, element: &WebElement, name: &str) -> WebDriverResult<WebDriverResponse> { fn handle_element_attribute(&self, element: &WebElement, name: &str) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetElementAttribute(element.id.clone(), name.to_owned(), let cmd = WebDriverScriptCommand::GetElementAttribute(element.id.clone(), name.to_owned(), sender);
sender))); self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference, Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference,
@ -646,8 +640,8 @@ impl Handler {
fn handle_element_css(&self, element: &WebElement, name: &str) -> WebDriverResult<WebDriverResponse> { fn handle_element_css(&self, element: &WebElement, name: &str) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetElementCSS(element.id.clone(), name.to_owned(), let cmd = WebDriverScriptCommand::GetElementCSS(element.id.clone(), name.to_owned(), sender);
sender))); self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference, Err(_) => Err(WebDriverError::new(ErrorStatus::StaleElementReference,
@ -657,7 +651,8 @@ impl Handler {
fn handle_get_cookies(&self) -> WebDriverResult<WebDriverResponse> { fn handle_get_cookies(&self) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetCookies(sender))); let cmd = WebDriverScriptCommand::GetCookies(sender);
self.browsing_context_script_command(cmd)?;
let cookies = receiver.recv().unwrap(); let cookies = receiver.recv().unwrap();
let response = cookies.into_iter().map(|cookie| { let response = cookies.into_iter().map(|cookie| {
cookie_msg_to_cookie(cookie.into_inner()) cookie_msg_to_cookie(cookie.into_inner())
@ -667,7 +662,8 @@ impl Handler {
fn handle_get_cookie(&self, name: &str) -> WebDriverResult<WebDriverResponse> { fn handle_get_cookie(&self, name: &str) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
try!(self.frame_script_command(WebDriverScriptCommand::GetCookie(name.to_owned(), sender))); let cmd = WebDriverScriptCommand::GetCookie(name.to_owned(), sender);
self.browsing_context_script_command(cmd)?;
let cookies = receiver.recv().unwrap(); let cookies = receiver.recv().unwrap();
let response = cookies.into_iter().map(|cookie| { let response = cookies.into_iter().map(|cookie| {
cookie_msg_to_cookie(cookie.into_inner()) cookie_msg_to_cookie(cookie.into_inner())
@ -690,7 +686,8 @@ impl Handler {
_ => cookie.finish(), _ => cookie.finish(),
}; };
try!(self.frame_script_command(WebDriverScriptCommand::AddCookie(cookie, sender))); let cmd = WebDriverScriptCommand::AddCookie(cookie, sender);
self.browsing_context_script_command(cmd)?;
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(_) => Ok(WebDriverResponse::Void), Ok(_) => Ok(WebDriverResponse::Void),
Err(response) => match response { Err(response) => match response {
@ -728,20 +725,18 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let command = WebDriverScriptCommand::ExecuteScript(script, sender); let command = WebDriverScriptCommand::ExecuteScript(script, sender);
self.execute_script(command, receiver) self.browsing_context_script_command(command)?;
let result = receiver.recv().unwrap();
self.postprocess_js_result(result)
} }
fn handle_execute_async_script(&self, fn handle_execute_async_script(&self,
parameters: &JavascriptCommandParameters) parameters: &JavascriptCommandParameters)
-> WebDriverResult<WebDriverResponse> { -> WebDriverResult<WebDriverResponse> {
let session = try!(self.session
.as_ref()
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
let func_body = &parameters.script; let func_body = &parameters.script;
let args_string = "window.webdriverCallback"; let args_string = "window.webdriverCallback";
let script = match session.script_timeout { let script = match self.session()?.script_timeout {
Some(timeout) => { Some(timeout) => {
format!("setTimeout(webdriverTimeout, {}); (function(callback) {{ {} }})({})", format!("setTimeout(webdriverTimeout, {}); (function(callback) {{ {} }})({})",
timeout, timeout,
@ -753,19 +748,13 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let command = WebDriverScriptCommand::ExecuteAsyncScript(script, sender); let command = WebDriverScriptCommand::ExecuteAsyncScript(script, sender);
self.execute_script(command, receiver) self.browsing_context_script_command(command)?;
let result = receiver.recv().unwrap();
self.postprocess_js_result(result)
} }
fn execute_script(&self, fn postprocess_js_result(&self, result: WebDriverJSResult) -> WebDriverResult<WebDriverResponse> {
command: WebDriverScriptCommand, match result {
receiver: IpcReceiver<WebDriverJSResult>)
-> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.frame_pipeline());
let cmd_msg = WebDriverCommandMsg::ScriptCommand(pipeline_id, command);
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
match receiver.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(WebDriverJSError::Timeout) => Err(WebDriverError::new(ErrorStatus::Timeout, "")), Err(WebDriverJSError::Timeout) => Err(WebDriverError::new(ErrorStatus::Timeout, "")),
Err(WebDriverJSError::UnknownType) => Err(WebDriverError::new( Err(WebDriverJSError::UnknownType) => Err(WebDriverError::new(
@ -778,12 +767,12 @@ impl Handler {
fn handle_element_send_keys(&self, fn handle_element_send_keys(&self,
element: &WebElement, element: &WebElement,
keys: &SendKeysParameters) -> WebDriverResult<WebDriverResponse> { keys: &SendKeysParameters) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.frame_pipeline()); let browsing_context_id = self.session()?.browsing_context_id;
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::FocusElement(element.id.clone(), sender); let cmd = WebDriverScriptCommand::FocusElement(element.id.clone(), sender);
let cmd_msg = WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd); let cmd_msg = WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd);
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
// TODO: distinguish the not found and not focusable cases // TODO: distinguish the not found and not focusable cases
@ -793,7 +782,9 @@ impl Handler {
let keys = try!(keycodes_to_keys(&keys.value).or_else(|_| let keys = try!(keycodes_to_keys(&keys.value).or_else(|_|
Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, "Failed to convert keycodes")))); Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, "Failed to convert keycodes"))));
let cmd_msg = WebDriverCommandMsg::SendKeys(pipeline_id, keys); // TODO: there's a race condition caused by these being two separate messages,
// so the constellation may have changed state between them.
let cmd_msg = WebDriverCommandMsg::SendKeys(browsing_context_id, keys);
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
@ -801,14 +792,14 @@ impl Handler {
fn handle_take_screenshot(&self) -> WebDriverResult<WebDriverResponse> { fn handle_take_screenshot(&self) -> WebDriverResult<WebDriverResponse> {
let mut img = None; let mut img = None;
let pipeline_id = try!(self.root_pipeline()); let top_level_id = self.session()?.top_level_browsing_context_id;
let interval = 1000; let interval = 1000;
let iterations = 30_000 / interval; let iterations = 30_000 / interval;
for _ in 0..iterations { for _ in 0..iterations {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let cmd_msg = WebDriverCommandMsg::TakeScreenshot(pipeline_id, sender); let cmd_msg = WebDriverCommandMsg::TakeScreenshot(top_level_id, sender);
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap(); self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
if let Some(x) = receiver.recv().unwrap() { if let Some(x) = receiver.recv().unwrap() {