servo: Merge #5808 - Add script execution support via WebDriver (from jgraham:webdriver_execute_script); r=jdm

Source-Repo: https://github.com/servo/servo
Source-Revision: 38ac11d0b8ae4244f49b59a6321a1a570ea01e03
This commit is contained in:
James Graham 2015-04-23 13:41:11 -05:00
Родитель 3fb22167fa
Коммит 72de17b9be
19 изменённых файлов: 223 добавлений и 18 удалений

Просмотреть файл

@ -31,8 +31,8 @@ path = "../net_traits"
[dependencies.util]
path = "../util"
[dependencies.webdriver_server]
path = "../webdriver_server"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.devtools_traits]
path = "../devtools_traits"

Просмотреть файл

@ -39,6 +39,7 @@ use util::geometry::PagePx;
use util::opts;
use util::task::spawn_named;
use clipboard::ClipboardContext;
use webdriver_traits::WebDriverScriptCommand;
/// Maintains the pipelines and navigation context and grants permission to composite.
pub struct Constellation<LTF, STF> {
@ -410,6 +411,12 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
};
sender.send(result).unwrap();
}
ConstellationMsg::WebDriverCommandMsg(pipeline_id,
command) => {
debug!("constellation got webdriver command message");
self.handle_webdriver_command_msg(pipeline_id,
command);
}
}
true
}
@ -753,6 +760,17 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
self.focus_parent_pipeline(pipeline_id);
}
fn handle_webdriver_command_msg(&mut self,
pipeline_id: PipelineId,
msg: WebDriverScriptCommand) {
// Find the script channel for the given parent pipeline,
// and pass the event to that script task.
let pipeline = self.pipeline(pipeline_id);
let control_msg = ConstellationControlMsg::WebDriverCommandMsg(pipeline_id, msg);
let ScriptControlChan(ref script_channel) = pipeline.script_chan;
script_channel.send(control_msg).unwrap();
}
fn add_or_replace_pipeline_in_frame_tree(&mut self, frame_change: FrameChange) {
// If the currently focused pipeline is the one being changed (or a child

Просмотреть файл

@ -27,7 +27,7 @@ extern crate net_traits;
#[macro_use]
extern crate util;
extern crate gleam;
extern crate webdriver_server;
extern crate webdriver_traits;
extern crate clipboard;
extern crate libc;

Просмотреть файл

@ -14,6 +14,9 @@ path = "../style"
[dependencies.util]
path = "../util"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.azure]
git = "https://github.com/servo/rust-azure"

Просмотреть файл

@ -14,6 +14,7 @@ use layers::geometry::DevicePixel;
use util::cursor::Cursor;
use util::geometry::{PagePx, ViewportPx};
use std::sync::mpsc::{channel, Sender, Receiver};
use webdriver_traits::WebDriverScriptCommand;
use url::Url;
#[derive(Clone)]
@ -231,6 +232,8 @@ pub enum Msg {
FocusMsg(PipelineId),
/// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(Sender<String>),
// Dispatch a webdriver command
WebDriverCommandMsg(PipelineId, WebDriverScriptCommand)
}
// https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events

Просмотреть файл

@ -9,6 +9,7 @@ extern crate hyper;
extern crate layers;
extern crate util;
extern crate url;
extern crate webdriver_traits;
#[cfg(target_os="macos")]
extern crate core_foundation;

Просмотреть файл

@ -42,6 +42,9 @@ path = "../gfx"
[dependencies.canvas]
path = "../canvas"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.cssparser]
git = "https://github.com/servo/rust-cssparser"

Просмотреть файл

@ -52,6 +52,7 @@ extern crate style;
extern crate url;
extern crate uuid;
extern crate string_cache;
extern crate webdriver_traits;
pub mod cors;
@ -67,3 +68,4 @@ pub mod script_task;
mod timers;
pub mod textinput;
mod devtools;
mod webdriver_handlers;

Просмотреть файл

@ -45,6 +45,7 @@ use layout_interface;
use page::{Page, IterablePage, Frame};
use timers::TimerId;
use devtools;
use webdriver_handlers;
use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo};
use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg};
@ -56,6 +57,7 @@ use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent};
use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel};
use script_traits::{ConstellationControlMsg, ScriptControlChan};
use script_traits::ScriptTaskFactory;
use webdriver_traits::WebDriverScriptCommand;
use msg::compositor_msg::ReadyState::{FinishedLoading, Loading, PerformingLayout};
use msg::compositor_msg::{LayerId, ScriptListener};
use msg::constellation_msg::{ConstellationChan, FocusType};
@ -727,6 +729,9 @@ impl ScriptTask {
self.handle_update_subpage_id(containing_pipeline_id, old_subpage_id, new_subpage_id),
ConstellationControlMsg::FocusIFrameMsg(containing_pipeline_id, subpage_id) =>
self.handle_focus_iframe_msg(containing_pipeline_id, subpage_id),
ConstellationControlMsg::WebDriverCommandMsg(pipeline_id, msg) => {
self.handle_webdriver_msg(pipeline_id, msg);
}
}
}
@ -783,6 +788,14 @@ impl ScriptTask {
msg.responder.unwrap().respond(msg.image);
}
fn handle_webdriver_msg(&self, pipeline_id: PipelineId, msg: WebDriverScriptCommand) {
let page = self.root_page();
match msg {
WebDriverScriptCommand::EvaluateJS(script, reply) =>
webdriver_handlers::handle_evaluate_js(&page, pipeline_id, script, reply)
}
}
fn handle_resize(&self, id: PipelineId, size: WindowSizeData) {
let page = self.page.borrow();
if let Some(ref page) = page.as_ref() {

Просмотреть файл

@ -0,0 +1,38 @@
/* 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 webdriver_traits::{EvaluateJSReply};
use dom::bindings::conversions::FromJSValConvertible;
use dom::bindings::conversions::StringificationBehavior;
use dom::bindings::js::OptionalRootable;
use dom::window::ScriptHelpers;
use dom::document::DocumentHelpers;
use page::Page;
use msg::constellation_msg::PipelineId;
use script_task::get_page;
use std::rc::Rc;
use std::sync::mpsc::Sender;
pub fn handle_evaluate_js(page: &Rc<Page>, pipeline: PipelineId, eval: String, reply: Sender<Result<EvaluateJSReply, ()>>){
let page = get_page(&*page, pipeline);
let window = page.window().root();
let cx = window.r().get_cx();
let rval = window.r().evaluate_js_on_global_with_result(&eval);
reply.send(if rval.is_undefined() {
Ok(EvaluateJSReply::VoidValue)
} else if rval.is_boolean() {
Ok(EvaluateJSReply::BooleanValue(rval.to_boolean()))
} else if rval.is_double() {
Ok(EvaluateJSReply::NumberValue(FromJSValConvertible::from_jsval(cx, rval, ()).unwrap()))
} else if rval.is_string() {
//FIXME: use jsstring_to_str when jsval grows to_jsstring
Ok(EvaluateJSReply::StringValue(FromJSValConvertible::from_jsval(cx, rval, StringificationBehavior::Default).unwrap()))
} else if rval.is_null() {
Ok(EvaluateJSReply::NullValue)
} else {
Err(())
}).unwrap();
}

Просмотреть файл

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

Просмотреть файл

@ -9,6 +9,7 @@ extern crate msg;
extern crate net_traits;
extern crate util;
extern crate url;
extern crate webdriver_traits;
// This module contains traits in script used generically
// in the rest of Servo.
@ -26,6 +27,7 @@ use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;
use std::any::Any;
use std::sync::mpsc::{Sender, Receiver};
use webdriver_traits::WebDriverScriptCommand;
use geom::point::Point2D;
use geom::rect::Rect;
@ -75,6 +77,8 @@ pub enum ConstellationControlMsg {
UpdateSubpageId(PipelineId, SubpageId, SubpageId),
/// Set an iframe to be focused. Used when an element in an iframe gains focus.
FocusIFrameMsg(PipelineId, SubpageId),
// Passes a webdriver command to the script task for execution
WebDriverCommandMsg(PipelineId, WebDriverScriptCommand)
}
/// The mouse button involved in the event.

15
servo/components/servo/Cargo.lock сгенерированный
Просмотреть файл

@ -126,7 +126,7 @@ dependencies = [
"time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_server 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -660,6 +660,7 @@ dependencies = [
"style 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -856,6 +857,7 @@ dependencies = [
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"uuid 0.1.11 (git+https://github.com/rust-lang/uuid)",
"webdriver_traits 0.0.1",
]
[[package]]
@ -876,6 +878,7 @@ dependencies = [
"net_traits 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -1050,7 +1053,7 @@ dependencies = [
[[package]]
name = "webdriver"
version = "0.0.1"
source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd"
source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de"
dependencies = [
"hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1069,6 +1072,14 @@ dependencies = [
"util 0.0.1",
"uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.0.1 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

Просмотреть файл

@ -13,10 +13,13 @@ path = "../msg"
[dependencies.util]
path = "../util"
[dependencies.webdriver_traits]
path = "../webdriver_traits"
[dependencies.webdriver]
git = "https://github.com/jgraham/webdriver-rust.git"
[dependencies]
rustc-serialize="0.3.4"
rustc-serialize = "0.3.4"
url = "0.2.16"
uuid = "0.1.11"

Просмотреть файл

@ -17,14 +17,16 @@ extern crate url;
extern crate util;
extern crate "rustc-serialize" as rustc_serialize;
extern crate uuid;
extern crate webdriver_traits;
use msg::constellation_msg::{ConstellationChan, LoadData};
use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId};
use msg::constellation_msg::Msg as ConstellationMsg;
use std::sync::mpsc::channel;
use webdriver_traits::WebDriverScriptCommand;
use url::Url;
use webdriver::command::{WebDriverMessage, WebDriverCommand};
use webdriver::command::GetParameters;
use webdriver::command::{GetParameters, JavascriptCommandParameters};
use webdriver::response::{
WebDriverResponse, NewSessionResponse, ValueResponse};
use webdriver::server::{self, WebDriverHandler, Session};
@ -51,7 +53,7 @@ struct WebdriverSession {
struct Handler {
session: Option<WebdriverSession>,
constellation_chan: ConstellationChan
constellation_chan: ConstellationChan,
}
impl WebdriverSession {
@ -70,6 +72,14 @@ impl Handler {
}
}
fn get_root_pipeline(&self) -> PipelineId {
let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap();
reciever.recv().unwrap().unwrap()
}
fn handle_new_session(&mut self) -> WebDriverResult<WebDriverResponse> {
if self.session.is_none() {
let session = WebdriverSession::new();
@ -92,13 +102,10 @@ impl Handler {
"Invalid URL"))
};
let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap();
let pipeline_id = reciever.recv().unwrap().unwrap();
let pipeline_id = self.get_root_pipeline();
let load_data = LoadData::new(url);
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::LoadUrl(pipeline_id, load_data)).unwrap();
//TODO: Now we ought to wait until we get a load event
Ok(WebDriverResponse::Void)
@ -110,6 +117,32 @@ impl Handler {
let handle = self.session.as_ref().unwrap().id.to_string();
Ok(WebDriverResponse::Generic(ValueResponse::new(handle.to_json())))
}
fn handle_execute_script(&self, parameters: &JavascriptCommandParameters) -> WebDriverResult<WebDriverResponse> {
// TODO: This isn't really right because it always runs the script in the
// root window
let pipeline_id = self.get_root_pipeline();
let func_body = &parameters.script;
let args = &parameters.args;
let args_string = "";
// This is pretty ugly; we really want something that acts like
// new Function() and then takes the resulting function and executes
// it with a vec of arguments.
let script = format!("(function() {{ {} }})({})", func_body, args_string);
let (sender, reciever) = channel();
let ConstellationChan(ref const_chan) = self.constellation_chan;
const_chan.send(ConstellationMsg::WebDriverCommandMsg(pipeline_id,
WebDriverScriptCommand::EvaluateJS(script, sender))).unwrap();
match reciever.recv().unwrap() {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))),
Err(_) => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
"Unsupported return type"))
}
}
}
impl WebDriverHandler for Handler {
@ -119,6 +152,7 @@ impl WebDriverHandler for Handler {
WebDriverCommand::NewSession => self.handle_new_session(),
WebDriverCommand::Get(ref parameters) => self.handle_get(parameters),
WebDriverCommand::GetWindowHandle => self.handle_get_window_handle(),
WebDriverCommand::ExecuteScript(ref x) => self.handle_execute_script(x),
_ => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation,
"Command not implemented"))
}

Просмотреть файл

@ -0,0 +1,11 @@
[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"

Просмотреть файл

@ -0,0 +1,36 @@
/* 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/. */
#![crate_name = "webdriver_traits"]
#![crate_type = "rlib"]
extern crate "rustc-serialize" as rustc_serialize;
use rustc_serialize::json::{Json, ToJson};
use std::sync::mpsc::Sender;
pub enum WebDriverScriptCommand {
EvaluateJS(String, Sender<Result<EvaluateJSReply, ()>>)
}
pub enum EvaluateJSReply {
VoidValue,
NullValue,
BooleanValue(bool),
NumberValue(f64),
StringValue(String),
// TODO: ObjectValue and WebElementValue
}
impl ToJson for EvaluateJSReply {
fn to_json(&self) -> Json {
match self {
&EvaluateJSReply::VoidValue => Json::Null,
&EvaluateJSReply::NullValue => Json::Null,
&EvaluateJSReply::BooleanValue(ref x) => x.to_json(),
&EvaluateJSReply::NumberValue(ref x) => x.to_json(),
&EvaluateJSReply::StringValue(ref x) => x.to_json()
}
}
}

15
servo/ports/cef/Cargo.lock сгенерированный
Просмотреть файл

@ -124,7 +124,7 @@ dependencies = [
"time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_server 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -651,6 +651,7 @@ dependencies = [
"style 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -834,6 +835,7 @@ dependencies = [
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"uuid 0.1.11 (git+https://github.com/rust-lang/uuid)",
"webdriver_traits 0.0.1",
]
[[package]]
@ -847,6 +849,7 @@ dependencies = [
"net_traits 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -1022,7 +1025,7 @@ dependencies = [
[[package]]
name = "webdriver"
version = "0.0.1"
source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd"
source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de"
dependencies = [
"hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1041,6 +1044,14 @@ dependencies = [
"util 0.0.1",
"uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.0.1 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

15
servo/ports/gonk/Cargo.lock сгенерированный
Просмотреть файл

@ -119,7 +119,7 @@ dependencies = [
"time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_server 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -634,6 +634,7 @@ dependencies = [
"style 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -826,6 +827,7 @@ dependencies = [
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"uuid 0.1.11 (git+https://github.com/rust-lang/uuid)",
"webdriver_traits 0.0.1",
]
[[package]]
@ -839,6 +841,7 @@ dependencies = [
"net_traits 0.0.1",
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
"webdriver_traits 0.0.1",
]
[[package]]
@ -1013,7 +1016,7 @@ dependencies = [
[[package]]
name = "webdriver"
version = "0.0.1"
source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd"
source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de"
dependencies = [
"hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1032,6 +1035,14 @@ dependencies = [
"util 0.0.1",
"uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"webdriver 0.0.1 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]