Add support for switching frames with the webdriver API.

This moves webdriver_traits into msg to avoid a circular dependency.
This commit is contained in:
James Graham 2015-05-11 14:47:10 +01:00
parent c724444ccb
commit 49f1b13ad9
20 changed files with 273 additions and 122 deletions

View file

@ -37,9 +37,6 @@ path = "../style"
[dependencies.util] [dependencies.util]
path = "../util" path = "../util"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.devtools_traits] [dependencies.devtools_traits]
path = "../devtools_traits" path = "../devtools_traits"

View file

@ -29,7 +29,8 @@ use msg::constellation_msg::{IFrameSandboxState, MozBrowserEvent, NavigationDire
use msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData}; use msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData};
use msg::constellation_msg::{SubpageId, WindowSizeData}; use msg::constellation_msg::{SubpageId, WindowSizeData};
use msg::constellation_msg::{self, ConstellationChan, Failure}; use msg::constellation_msg::{self, ConstellationChan, Failure};
use msg::constellation_msg::{WebDriverCommandMsg}; use msg::constellation_msg::WebDriverCommandMsg;
use msg::webdriver_msg;
use net_traits::{self, ResourceTask}; use net_traits::{self, ResourceTask};
use net_traits::image_cache_task::ImageCacheTask; use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::{StorageTask, StorageTaskMsg}; use net_traits::storage_task::{StorageTask, StorageTaskMsg};
@ -50,7 +51,6 @@ use util::geometry::PagePx;
use util::opts; use util::opts;
use util::task::spawn_named; use util::task::spawn_named;
use clipboard::ClipboardContext; use clipboard::ClipboardContext;
use webdriver_traits;
/// Maintains the pipelines and navigation context and grants permission to composite. /// Maintains the pipelines and navigation context and grants permission to composite.
/// ///
@ -190,7 +190,7 @@ pub struct SendableFrameTree {
} }
struct WebDriverData { struct WebDriverData {
load_channel: Option<Sender<webdriver_traits::LoadComplete>> load_channel: Option<Sender<webdriver_msg::LoadComplete>>
} }
impl WebDriverData { impl WebDriverData {
@ -425,9 +425,13 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
subpage_id, subpage_id,
event); event);
} }
ConstellationMsg::GetRootPipeline(resp_chan) => { ConstellationMsg::GetPipeline(frame_id, resp_chan) => {
debug!("constellation got get root pipeline message"); debug!("constellation got get root pipeline message");
self.handle_get_root_pipeline(resp_chan); self.handle_get_pipeline(frame_id, resp_chan);
}
ConstellationMsg::GetFrame(parent_pipeline_id, subpage_id, resp_chan) => {
debug!("constellation got get root pipeline message");
self.handle_get_frame(parent_pipeline_id, subpage_id, resp_chan);
} }
ConstellationMsg::Focus(pipeline_id) => { ConstellationMsg::Focus(pipeline_id) => {
debug!("constellation got focus message"); debug!("constellation got focus message");
@ -691,7 +695,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
let back = !self.mut_frame(frame_id).prev.is_empty(); let back = !self.mut_frame(frame_id).prev.is_empty();
self.compositor_proxy.send(CompositorMsg::LoadComplete(back, forward)); self.compositor_proxy.send(CompositorMsg::LoadComplete(back, forward));
if let Some(ref reply_chan) = self.webdriver.load_channel { if let Some(ref reply_chan) = self.webdriver.load_channel {
reply_chan.send(webdriver_traits::LoadComplete).unwrap(); reply_chan.send(webdriver_msg::LoadComplete).unwrap();
} }
self.webdriver.load_channel = None; self.webdriver.load_channel = None;
} }
@ -815,14 +819,24 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipeline.trigger_mozbrowser_event(subpage_id, event); pipeline.trigger_mozbrowser_event(subpage_id, event);
} }
fn handle_get_root_pipeline(&mut self, resp_chan: Sender<Option<PipelineId>>) { fn handle_get_pipeline(&mut self, frame_id: Option<FrameId>,
let pipeline_id = self.root_frame_id.map(|frame_id| { resp_chan: Sender<Option<PipelineId>>) {
let pipeline_id = frame_id.or(self.root_frame_id).map(|frame_id| {
let frame = self.frames.get(&frame_id).unwrap(); let frame = self.frames.get(&frame_id).unwrap();
frame.current frame.current
}); });
resp_chan.send(pipeline_id).unwrap(); resp_chan.send(pipeline_id).unwrap();
} }
fn handle_get_frame(&mut self,
containing_pipeline_id: PipelineId,
subpage_id: SubpageId,
resp_chan: Sender<Option<FrameId>>) {
let frame_id = self.subpage_map.get(&(containing_pipeline_id, subpage_id)).and_then(
|x| self.pipeline_to_frame_map.get(&x)).map(|x| *x);
resp_chan.send(frame_id).unwrap();
}
fn focus_parent_pipeline(&self, pipeline_id: PipelineId) { fn focus_parent_pipeline(&self, pipeline_id: PipelineId) {
// Send a message to the parent of the provided pipeline (if it exists) // Send a message to the parent of the provided pipeline (if it exists)
// telling it to mark the iframe element as focused. // telling it to mark the iframe element as focused.

View file

@ -28,7 +28,6 @@ extern crate style;
#[macro_use] #[macro_use]
extern crate util; extern crate util;
extern crate gleam; extern crate gleam;
extern crate webdriver_traits;
extern crate clipboard; extern crate clipboard;
extern crate libc; extern crate libc;

View file

@ -13,9 +13,6 @@ path = "../style"
[dependencies.util] [dependencies.util]
path = "../util" path = "../util"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.azure] [dependencies.azure]
git = "https://github.com/servo/rust-azure" git = "https://github.com/servo/rust-azure"
@ -38,3 +35,4 @@ git = "https://github.com/servo/rust-png"
url = "0.2.16" url = "0.2.16"
bitflags = "*" bitflags = "*"
hyper = "0.4" hyper = "0.4"
rustc-serialize = "0.3.4"

View file

@ -18,8 +18,8 @@ use util::geometry::{PagePx, ViewportPx};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use style::viewport::ViewportConstraints; use style::viewport::ViewportConstraints;
use webdriver_traits::{WebDriverScriptCommand, LoadComplete};
use url::Url; use url::Url;
use webdriver_msg::{WebDriverScriptCommand, LoadComplete};
#[derive(Clone)] #[derive(Clone)]
pub struct ConstellationChan(pub Sender<Msg>); pub struct ConstellationChan(pub Sender<Msg>);
@ -230,8 +230,12 @@ pub enum Msg {
ChangeRunningAnimationsState(PipelineId, AnimationState), ChangeRunningAnimationsState(PipelineId, AnimationState),
/// 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), TickAnimation(PipelineId),
/// Request that the constellation send the current root pipeline id over a provided channel /// Request that the constellation send the current pipeline id for the provided frame
GetRootPipeline(Sender<Option<PipelineId>>), /// id, or for the root frame if this is None, over a provided channel
GetPipeline(Option<FrameId>, Sender<Option<PipelineId>>),
/// Request that the constellation send the FrameId corresponding to the document
/// with the provided parent pipeline id and subpage id
GetFrame(PipelineId, SubpageId, Sender<Option<FrameId>>),
/// Notifies the constellation that this frame has received focus. /// Notifies the constellation that this frame has received focus.
Focus(PipelineId), Focus(PipelineId),
/// Requests that the constellation retrieve the current contents of the clipboard /// Requests that the constellation retrieve the current contents of the clipboard

View file

@ -8,10 +8,10 @@ extern crate geom;
extern crate hyper; extern crate hyper;
extern crate layers; extern crate layers;
extern crate png; extern crate png;
extern crate rustc_serialize;
extern crate util; extern crate util;
extern crate url; extern crate url;
extern crate style; extern crate style;
extern crate webdriver_traits;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern crate core_foundation; extern crate core_foundation;
@ -20,3 +20,4 @@ extern crate io_surface;
pub mod compositor_msg; pub mod compositor_msg;
pub mod constellation_msg; pub mod constellation_msg;
pub mod webdriver_msg;

View file

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
use rustc_serialize::json::{Json, ToJson};
use constellation_msg::{PipelineId, SubpageId};
use std::sync::mpsc::Sender;
pub enum WebDriverScriptCommand {
ExecuteScript(String, Sender<WebDriverJSResult>),
ExecuteAsyncScript(String, Sender<WebDriverJSResult>),
FindElementCSS(String, Sender<Result<Option<String>, ()>>),
FindElementsCSS(String, Sender<Result<Vec<String>, ()>>),
GetActiveElement(Sender<Option<String>>),
GetElementTagName(String, Sender<Result<String, ()>>),
GetElementText(String, Sender<Result<String, ()>>),
GetFrameId(WebDriverFrameId, Sender<Result<Option<(PipelineId, SubpageId)>, ()>>),
GetTitle(Sender<String>)
}
pub enum WebDriverJSValue {
Undefined,
Null,
Boolean(bool),
Number(f64),
String(String),
// TODO: Object and WebElement
}
pub enum WebDriverJSError {
Timeout,
UnknownType
}
pub type WebDriverJSResult = Result<WebDriverJSValue, WebDriverJSError>;
pub enum WebDriverFrameId {
Short(u16),
Element(String),
Parent
}
impl ToJson for WebDriverJSValue {
fn to_json(&self) -> Json {
match *self {
WebDriverJSValue::Undefined => Json::Null,
WebDriverJSValue::Null => Json::Null,
WebDriverJSValue::Boolean(ref x) => x.to_json(),
WebDriverJSValue::Number(ref x) => x.to_json(),
WebDriverJSValue::String(ref x) => x.to_json()
}
}
}
pub struct LoadComplete;

View file

@ -45,9 +45,6 @@ path = "../canvas"
[dependencies.canvas_traits] [dependencies.canvas_traits]
path = "../canvas_traits" path = "../canvas_traits"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.selectors] [dependencies.selectors]
git = "https://github.com/servo/rust-selectors" git = "https://github.com/servo/rust-selectors"

View file

@ -38,9 +38,9 @@ use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
use webdriver_handlers::jsval_to_webdriver; use webdriver_handlers::jsval_to_webdriver;
use devtools_traits::{DevtoolsControlChan, TimelineMarker, TimelineMarkerType, TracingMetadata}; use devtools_traits::{DevtoolsControlChan, TimelineMarker, TimelineMarkerType, TracingMetadata};
use webdriver_traits::{WebDriverJSError, WebDriverJSResult};
use msg::compositor_msg::ScriptListener; use msg::compositor_msg::ScriptListener;
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId}; use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId};
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use net_traits::ResourceTask; use net_traits::ResourceTask;
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask};
use net_traits::storage_task::{StorageTask, StorageType}; use net_traits::storage_task::{StorageTask, StorageType};
@ -437,17 +437,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
// https://html.spec.whatwg.org/multipage/#dom-parent // https://html.spec.whatwg.org/multipage/#dom-parent
fn Parent(self) -> Temporary<Window> { fn Parent(self) -> Temporary<Window> {
let browser_context = self.browser_context(); self.parent().unwrap_or(self.Window())
let browser_context = browser_context.as_ref().unwrap();
browser_context.frame_element().map_or(self.Window(), |fe| {
let frame_element = fe.root();
let window = window_from_node(frame_element.r()).root();
// FIXME(https://github.com/rust-lang/rust/issues/23338)
let r = window.r();
let context = r.browser_context();
context.as_ref().unwrap().active_window()
})
} }
fn Performance(self) -> Temporary<Performance> { fn Performance(self) -> Temporary<Performance> {
@ -558,6 +548,7 @@ pub trait WindowHelpers {
fn drop_devtools_timeline_markers(self); fn drop_devtools_timeline_markers(self);
fn set_webdriver_script_chan(self, chan: Option<Sender<WebDriverJSResult>>); fn set_webdriver_script_chan(self, chan: Option<Sender<WebDriverJSResult>>);
fn is_alive(self) -> bool; fn is_alive(self) -> bool;
fn parent(self) -> Option<Temporary<Window>>;
} }
pub trait ScriptHelpers { pub trait ScriptHelpers {
@ -939,6 +930,20 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
fn is_alive(self) -> bool { fn is_alive(self) -> bool {
self.current_state.get() == WindowState::Alive self.current_state.get() == WindowState::Alive
} }
fn parent(self) -> Option<Temporary<Window>> {
let browser_context = self.browser_context();
let browser_context = browser_context.as_ref().unwrap();
browser_context.frame_element().map(|fe| {
let frame_element = fe.root();
let window = window_from_node(frame_element.r()).root();
// FIXME(https://github.com/rust-lang/rust/issues/23338)
let r = window.r();
let context = r.browser_context();
context.as_ref().unwrap().active_window()
})
}
} }
impl Window { impl Window {

View file

@ -52,7 +52,6 @@ extern crate unicase;
extern crate url; extern crate url;
extern crate uuid; extern crate uuid;
extern crate string_cache; extern crate string_cache;
extern crate webdriver_traits;
extern crate offscreen_gl_context; extern crate offscreen_gl_context;
pub mod cors; pub mod cors;

View file

@ -62,12 +62,12 @@ use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent};
use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel}; use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel};
use script_traits::{ConstellationControlMsg, ScriptControlChan}; use script_traits::{ConstellationControlMsg, ScriptControlChan};
use script_traits::{ScriptState, ScriptTaskFactory}; use script_traits::{ScriptState, ScriptTaskFactory};
use webdriver_traits::WebDriverScriptCommand;
use msg::compositor_msg::{LayerId, ScriptListener}; use msg::compositor_msg::{LayerId, ScriptListener};
use msg::constellation_msg::{ConstellationChan, FocusType}; use msg::constellation_msg::{ConstellationChan, FocusType};
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, WorkerId}; use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, WorkerId};
use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType}; use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType};
use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::Msg as ConstellationMsg;
use msg::webdriver_msg::WebDriverScriptCommand;
use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata}; use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata};
use net_traits::LoadData as NetLoadData; use net_traits::LoadData as NetLoadData;
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult}; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
@ -835,6 +835,8 @@ impl ScriptTask {
webdriver_handlers::handle_get_name(&page, pipeline_id, node_id, reply), webdriver_handlers::handle_get_name(&page, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetElementText(node_id, reply) => WebDriverScriptCommand::GetElementText(node_id, reply) =>
webdriver_handlers::handle_get_text(&page, pipeline_id, node_id, reply), webdriver_handlers::handle_get_text(&page, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetFrameId(frame_id, reply) =>
webdriver_handlers::handle_get_frame_id(&page, pipeline_id, frame_id, reply),
WebDriverScriptCommand::GetTitle(reply) => WebDriverScriptCommand::GetTitle(reply) =>
webdriver_handlers::handle_get_title(&page, pipeline_id, reply), webdriver_handlers::handle_get_title(&page, pipeline_id, reply),
WebDriverScriptCommand::ExecuteAsyncScript(script, reply) => WebDriverScriptCommand::ExecuteAsyncScript(script, reply) =>

View file

@ -2,12 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use webdriver_traits::{WebDriverJSValue, WebDriverJSError, WebDriverJSResult};
use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::conversions::FromJSValConvertible;
use dom::bindings::conversions::StringificationBehavior; use dom::bindings::conversions::StringificationBehavior;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast}; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLIFrameElementCast};
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::js::{OptionalRootable, Rootable, Temporary}; use dom::bindings::js::{OptionalRootable, Rootable, Temporary};
@ -17,7 +17,8 @@ use dom::document::DocumentHelpers;
use js::jsapi::JSContext; use js::jsapi::JSContext;
use js::jsval::JSVal; use js::jsval::JSVal;
use page::Page; use page::Page;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::{PipelineId, SubpageId};
use msg::webdriver_msg::{WebDriverJSValue, WebDriverJSError, WebDriverJSResult, WebDriverFrameId};
use script_task::get_page; use script_task::get_page;
use std::rc::Rc; use std::rc::Rc;
@ -73,6 +74,36 @@ pub fn handle_execute_async_script(page: &Rc<Page>, pipeline: PipelineId, eval:
window.r().evaluate_js_on_global_with_result(&eval); window.r().evaluate_js_on_global_with_result(&eval);
} }
pub fn handle_get_frame_id(page: &Rc<Page>,
pipeline: PipelineId,
webdriver_frame_id: WebDriverFrameId,
reply: Sender<Result<Option<(PipelineId, SubpageId)>, ()>>) {
let window = match webdriver_frame_id {
WebDriverFrameId::Short(_) => {
// This isn't supported yet
Ok(None)
},
WebDriverFrameId::Element(x) => {
match find_node_by_unique_id(page, pipeline, x) {
Some(ref node) => {
match HTMLIFrameElementCast::to_ref(node.root().r()) {
Some(ref elem) => Ok(elem.GetContentWindow()),
None => Err(())
}
},
None => Err(())
}
},
WebDriverFrameId::Parent => {
let window = page.window();
Ok(window.root().r().parent())
}
};
let frame_id = window.map(|x| x.and_then(|x| x.root().r().parent_info()));
reply.send(frame_id).unwrap()
}
pub fn handle_find_element_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String, pub fn handle_find_element_css(page: &Rc<Page>, _pipeline: PipelineId, selector: String,
reply: Sender<Result<Option<String>, ()>>) { reply: Sender<Result<Option<String>, ()>>) {
reply.send(match page.document().root().r().QuerySelector(selector.clone()) { reply.send(match page.document().root().r().QuerySelector(selector.clone()) {

View file

@ -19,9 +19,6 @@ path = "../util"
[dependencies.devtools_traits] [dependencies.devtools_traits]
path = "../devtools_traits" path = "../devtools_traits"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.geom] [dependencies.geom]
git = "https://github.com/servo/rust-geom" git = "https://github.com/servo/rust-geom"

View file

@ -15,7 +15,6 @@ extern crate msg;
extern crate net_traits; extern crate net_traits;
extern crate util; extern crate util;
extern crate url; extern crate url;
extern crate webdriver_traits;
use devtools_traits::DevtoolsControlChan; use devtools_traits::DevtoolsControlChan;
use libc::c_void; use libc::c_void;
@ -23,12 +22,12 @@ use msg::constellation_msg::{ConstellationChan, PipelineId, Failure, WindowSizeD
use msg::constellation_msg::{LoadData, SubpageId, Key, KeyState, KeyModifiers}; use msg::constellation_msg::{LoadData, SubpageId, Key, KeyState, KeyModifiers};
use msg::constellation_msg::{MozBrowserEvent, PipelineExitType}; use msg::constellation_msg::{MozBrowserEvent, PipelineExitType};
use msg::compositor_msg::ScriptListener; use msg::compositor_msg::ScriptListener;
use msg::webdriver_msg::WebDriverScriptCommand;
use net_traits::ResourceTask; use net_traits::ResourceTask;
use net_traits::image_cache_task::ImageCacheTask; use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask; use net_traits::storage_task::StorageTask;
use std::any::Any; use std::any::Any;
use std::sync::mpsc::{Sender, Receiver}; use std::sync::mpsc::{Sender, Receiver};
use webdriver_traits::WebDriverScriptCommand;
use url::Url; use url::Url;
use geom::point::Point2D; use geom::point::Point2D;

View file

@ -146,7 +146,6 @@ dependencies = [
"time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -786,10 +785,10 @@ dependencies = [
"io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)", "io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"png 0.1.0 (git+https://github.com/servo/rust-png)", "png 0.1.0 (git+https://github.com/servo/rust-png)",
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -1071,7 +1070,6 @@ dependencies = [
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver_traits 0.0.1",
"websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1094,7 +1092,6 @@ dependencies = [
"net_traits 0.0.1", "net_traits 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -1337,14 +1334,6 @@ dependencies = [
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)", "webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)",
"webdriver_traits 0.0.1",
]
[[package]]
name = "webdriver_traits"
version = "0.0.1"
dependencies = [
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View file

@ -13,9 +13,6 @@ path = "../msg"
[dependencies.util] [dependencies.util]
path = "../util" path = "../util"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.webdriver] [dependencies.webdriver]
git = "https://github.com/jgraham/webdriver-rust.git" git = "https://github.com/jgraham/webdriver-rust.git"

View file

@ -17,16 +17,17 @@ extern crate url;
extern crate util; extern crate util;
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate uuid; extern crate uuid;
extern crate webdriver_traits;
use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, NavigationDirection, WebDriverCommandMsg}; use msg::constellation_msg::{ConstellationChan, LoadData, FrameId, PipelineId, NavigationDirection,
WebDriverCommandMsg};
use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::Msg as ConstellationMsg;
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};
use webdriver_traits::{WebDriverScriptCommand, WebDriverJSError, WebDriverJSResult}; use msg::webdriver_msg::{WebDriverFrameId, WebDriverScriptCommand, WebDriverJSError, WebDriverJSResult};
use url::Url; use url::Url;
use webdriver::command::{WebDriverMessage, WebDriverCommand}; use webdriver::command::{WebDriverMessage, WebDriverCommand};
use webdriver::command::{GetParameters, JavascriptCommandParameters, LocatorParameters, TimeoutsParameters}; use webdriver::command::{GetParameters, JavascriptCommandParameters, LocatorParameters,
SwitchToFrameParameters, TimeoutsParameters};
use webdriver::common::{LocatorStrategy, WebElement}; use webdriver::common::{LocatorStrategy, WebElement};
use webdriver::response::{ use webdriver::response::{
WebDriverResponse, NewSessionResponse, ValueResponse}; WebDriverResponse, NewSessionResponse, ValueResponse};
@ -51,22 +52,24 @@ pub fn start_server(port: u16, constellation_chan: ConstellationChan) {
}); });
} }
struct WebdriverSession { struct WebDriverSession {
id: Uuid id: Uuid,
frame_id: Option<FrameId>
} }
struct Handler { struct Handler {
session: Option<WebdriverSession>, session: Option<WebDriverSession>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_timeout: u32, script_timeout: u32,
load_timeout: u32, load_timeout: u32,
implicit_wait_timeout: u32 implicit_wait_timeout: u32
} }
impl WebdriverSession { impl WebDriverSession {
pub fn new() -> WebdriverSession { pub fn new() -> WebDriverSession {
WebdriverSession { WebDriverSession {
id: Uuid::new_v4() id: Uuid::new_v4(),
frame_id: None
} }
} }
} }
@ -87,25 +90,60 @@ impl Handler {
let iterations = 30_000 / interval; let iterations = 30_000 / interval;
for _ in 0..iterations { for _ in 0..iterations {
let (sender, reciever) = channel(); if let Some(x) = self.get_pipeline(None) {
let ConstellationChan(ref const_chan) = self.constellation_chan; return Ok(x)
const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap();
if let Some(x) = reciever.recv().unwrap() {
return Ok(x);
}; };
sleep_ms(interval) sleep_ms(interval);
}; };
Err(WebDriverError::new(ErrorStatus::Timeout, Err(WebDriverError::new(ErrorStatus::Timeout,
"Failed to get root window handle")) "Failed to get root window handle"))
} }
fn get_frame_pipeline(&self) -> WebDriverResult<PipelineId> {
if let Some(ref session) = self.session {
match self.get_pipeline(session.frame_id) {
Some(x) => Ok(x),
None => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"Frame got closed"))
}
} else {
panic!("Command tried to access session but session is None");
}
}
fn get_session(&self) -> WebDriverResult<&WebDriverSession> {
match self.session {
Some(ref x) => Ok(x),
None => Err(WebDriverError::new(ErrorStatus::SessionNotCreated,
"Session not created"))
}
}
fn set_frame_id(&mut self, frame_id: Option<FrameId>) -> WebDriverResult<()> {
match self.session {
Some(ref mut x) => {
x.frame_id = frame_id;
Ok(())
},
None => Err(WebDriverError::new(ErrorStatus::SessionNotCreated,
"Session not created"))
}
}
fn get_pipeline(&self, frame_id: Option<FrameId>) -> Option<PipelineId> {
let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::GetPipeline(frame_id, sender)).unwrap();
reciever.recv().unwrap()
}
fn handle_new_session(&mut self) -> WebDriverResult<WebDriverResponse> { fn handle_new_session(&mut self) -> WebDriverResult<WebDriverResponse> {
if self.session.is_none() { if self.session.is_none() {
let session = WebdriverSession::new(); let session = WebDriverSession::new();
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());
@ -182,7 +220,7 @@ impl Handler {
} }
fn handle_find_element(&self, parameters: &LocatorParameters) -> WebDriverResult<WebDriverResponse> { fn handle_find_element(&self, parameters: &LocatorParameters) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.get_root_pipeline()); let pipeline_id = try!(self.get_frame_pipeline());
if parameters.using != LocatorStrategy::CSSSelector { if parameters.using != LocatorStrategy::CSSSelector {
return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
@ -204,8 +242,60 @@ impl Handler {
} }
} }
fn handle_switch_to_frame(&mut self, parameters: &SwitchToFrameParameters) -> WebDriverResult<WebDriverResponse> {
use webdriver::common::FrameId;
let frame_id = match parameters.id {
FrameId::Null => {
self.set_frame_id(None).unwrap();
return Ok(WebDriverResponse::Void)
},
FrameId::Short(ref x) => WebDriverFrameId::Short(*x),
FrameId::Element(ref x) => WebDriverFrameId::Element(x.id.clone())
};
self.switch_to_frame(frame_id)
}
fn handle_switch_to_parent_frame(&mut self) -> WebDriverResult<WebDriverResponse> {
self.switch_to_frame(WebDriverFrameId::Parent)
}
fn switch_to_frame(&mut self, frame_id: WebDriverFrameId) -> WebDriverResult<WebDriverResponse> {
if let WebDriverFrameId::Short(_) = frame_id {
return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
"Selecting frame by id not supported"));
}
let pipeline_id = try!(self.get_frame_pipeline());
let (sender, reciever) = channel();
let cmd = WebDriverScriptCommand::GetFrameId(frame_id, sender);
{
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::WebDriverCommand(
WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd))).unwrap();
}
let frame = match reciever.recv().unwrap() {
Ok(Some((pipeline_id, subpage_id))) => {
let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::GetFrame(pipeline_id, subpage_id, sender)).unwrap();
reciever.recv().unwrap()
},
Ok(None) => None,
Err(_) => {
return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
"Frame does not exist"));
}
};
self.set_frame_id(frame).unwrap();
Ok(WebDriverResponse::Void)
}
fn handle_find_elements(&self, parameters: &LocatorParameters) -> WebDriverResult<WebDriverResponse> { fn handle_find_elements(&self, parameters: &LocatorParameters) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.get_root_pipeline()); let pipeline_id = try!(self.get_frame_pipeline());
if parameters.using != LocatorStrategy::CSSSelector { if parameters.using != LocatorStrategy::CSSSelector {
return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, return Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
@ -229,7 +319,7 @@ impl Handler {
} }
fn handle_get_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_get_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.get_root_pipeline()); let pipeline_id = try!(self.get_frame_pipeline());
let (sender, reciever) = channel(); let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan; let ConstellationChan(ref const_chan) = self.constellation_chan;
@ -244,7 +334,7 @@ impl Handler {
} }
fn handle_get_active_element(&self) -> WebDriverResult<WebDriverResponse> { fn handle_get_active_element(&self) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.get_root_pipeline()); let pipeline_id = try!(self.get_frame_pipeline());
let (sender, reciever) = channel(); let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan; let ConstellationChan(ref const_chan) = self.constellation_chan;
@ -256,7 +346,7 @@ impl Handler {
} }
fn handle_get_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> { fn handle_get_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let pipeline_id = try!(self.get_root_pipeline()); let pipeline_id = try!(self.get_frame_pipeline());
let (sender, reciever) = channel(); let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan; let ConstellationChan(ref const_chan) = self.constellation_chan;
@ -314,9 +404,7 @@ impl Handler {
fn execute_script(&self, fn execute_script(&self,
command: WebDriverScriptCommand, command: WebDriverScriptCommand,
reciever: Receiver<WebDriverJSResult>) -> WebDriverResult<WebDriverResponse> { reciever: Receiver<WebDriverJSResult>) -> WebDriverResult<WebDriverResponse> {
// TODO: This isn't really right because it always runs the script in the let pipeline_id = try!(self.get_frame_pipeline());
// root window
let pipeline_id = try!(self.get_root_pipeline());
let ConstellationChan(ref const_chan) = self.constellation_chan; let ConstellationChan(ref const_chan) = self.constellation_chan;
let cmd_msg = WebDriverCommandMsg::ScriptCommand(pipeline_id, command); let cmd_msg = WebDriverCommandMsg::ScriptCommand(pipeline_id, command);
@ -376,6 +464,15 @@ impl WebDriverHandler for Handler {
_session: &Option<Session>, _session: &Option<Session>,
msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse> { msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse> {
// Unless we are trying to create a new session, we need to ensure that a
// session has previously been created
match msg.command {
WebDriverCommand::NewSession => {},
_ => {
try!(self.get_session());
}
}
match msg.command { match msg.command {
WebDriverCommand::NewSession => self.handle_new_session(), WebDriverCommand::NewSession => self.handle_new_session(),
WebDriverCommand::Get(ref parameters) => self.handle_get(parameters), WebDriverCommand::Get(ref parameters) => self.handle_get(parameters),
@ -384,6 +481,8 @@ impl WebDriverHandler for Handler {
WebDriverCommand::GetTitle => self.handle_get_title(), WebDriverCommand::GetTitle => self.handle_get_title(),
WebDriverCommand::GetWindowHandle => self.handle_get_window_handle(), WebDriverCommand::GetWindowHandle => self.handle_get_window_handle(),
WebDriverCommand::GetWindowHandles => self.handle_get_window_handles(), WebDriverCommand::GetWindowHandles => self.handle_get_window_handles(),
WebDriverCommand::SwitchToFrame(ref parameters) => self.handle_switch_to_frame(parameters),
WebDriverCommand::SwitchToParentFrame => self.handle_switch_to_parent_frame(),
WebDriverCommand::FindElement(ref parameters) => self.handle_find_element(parameters), WebDriverCommand::FindElement(ref parameters) => self.handle_find_element(parameters),
WebDriverCommand::FindElements(ref parameters) => self.handle_find_elements(parameters), WebDriverCommand::FindElements(ref parameters) => self.handle_find_elements(parameters),
WebDriverCommand::GetActiveElement => self.handle_get_active_element(), WebDriverCommand::GetActiveElement => self.handle_get_active_element(),

View file

@ -1,11 +0,0 @@
[package]
name = "webdriver_traits"
version = "0.0.1"
authors = ["The Servo Project Developers"]
[lib]
name = "webdriver_traits"
path = "lib.rs"
[dependencies]
rustc-serialize="0.3.4"

13
ports/cef/Cargo.lock generated
View file

@ -155,7 +155,6 @@ dependencies = [
"time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -788,10 +787,10 @@ dependencies = [
"io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)", "io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"png 0.1.0 (git+https://github.com/servo/rust-png)", "png 0.1.0 (git+https://github.com/servo/rust-png)",
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -1061,7 +1060,6 @@ dependencies = [
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver_traits 0.0.1",
"websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1076,7 +1074,6 @@ dependencies = [
"net_traits 0.0.1", "net_traits 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -1322,14 +1319,6 @@ dependencies = [
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)", "webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)",
"webdriver_traits 0.0.1",
]
[[package]]
name = "webdriver_traits"
version = "0.0.1"
dependencies = [
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

13
ports/gonk/Cargo.lock generated
View file

@ -132,7 +132,6 @@ dependencies = [
"time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -687,10 +686,10 @@ dependencies = [
"io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)", "io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"png 0.1.0 (git+https://github.com/servo/rust-png)", "png 0.1.0 (git+https://github.com/servo/rust-png)",
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -942,7 +941,6 @@ dependencies = [
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver_traits 0.0.1",
"websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -957,7 +955,6 @@ dependencies = [
"net_traits 0.0.1", "net_traits 0.0.1",
"url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1", "util 0.0.1",
"webdriver_traits 0.0.1",
] ]
[[package]] [[package]]
@ -1184,14 +1181,6 @@ dependencies = [
"util 0.0.1", "util 0.0.1",
"uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)", "webdriver 0.2.0 (git+https://github.com/jgraham/webdriver-rust.git)",
"webdriver_traits 0.0.1",
]
[[package]]
name = "webdriver_traits"
version = "0.0.1"
dependencies = [
"rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]