aboutsummaryrefslogtreecommitdiffstats
path: root/components/webdriver_server/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/webdriver_server/lib.rs')
-rw-r--r--components/webdriver_server/lib.rs114
1 files changed, 83 insertions, 31 deletions
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index 5735594b058..0e3fa9058d6 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -10,11 +10,12 @@ mod actions;
mod capabilities;
use std::borrow::ToOwned;
+use std::cell::{Cell, RefCell};
use std::collections::{BTreeMap, HashMap};
use std::io::Cursor;
use std::net::{SocketAddr, SocketAddrV4};
use std::time::Duration;
-use std::{env, fmt, mem, process, thread};
+use std::{env, fmt, process, thread};
use base::id::{BrowsingContextId, WebViewId};
use base64::Engine;
@@ -23,8 +24,9 @@ use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use cookie::{CookieBuilder, Expiration};
use crossbeam_channel::{Receiver, Sender, after, select, unbounded};
use embedder_traits::{
- MouseButton, WebDriverCommandMsg, WebDriverCookieError, WebDriverFrameId, WebDriverJSError,
- WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverScriptCommand,
+ MouseButton, WebDriverCommandMsg, WebDriverCommandResponse, WebDriverCookieError,
+ WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus,
+ WebDriverMessageId, WebDriverScriptCommand,
};
use euclid::{Rect, Size2D};
use http::method::Method;
@@ -43,8 +45,8 @@ use servo_url::ServoUrl;
use style_traits::CSSPixel;
use uuid::Uuid;
use webdriver::actions::{
- ActionSequence, PointerDownAction, PointerMoveAction, PointerOrigin, PointerType,
- PointerUpAction,
+ ActionSequence, ActionsType, PointerAction, PointerActionItem, PointerActionParameters,
+ PointerDownAction, PointerMoveAction, PointerOrigin, PointerType, PointerUpAction,
};
use webdriver::capabilities::CapabilitiesMatching;
use webdriver::command::{
@@ -64,6 +66,26 @@ use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler};
use crate::actions::{InputSourceState, PointerInputState};
+#[derive(Default)]
+pub struct WebDriverMessageIdGenerator {
+ counter: Cell<usize>,
+}
+
+impl WebDriverMessageIdGenerator {
+ pub fn new() -> Self {
+ Self {
+ counter: Cell::new(0),
+ }
+ }
+
+ /// Returns a unique ID.
+ pub fn next(&self) -> WebDriverMessageId {
+ let id = self.counter.get();
+ self.counter.set(id + 1);
+ WebDriverMessageId(id)
+ }
+}
+
fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> {
vec![
(
@@ -145,10 +167,11 @@ pub struct WebDriverSession {
unhandled_prompt_behavior: String,
- // https://w3c.github.io/webdriver/#dfn-input-state-table
- input_state_table: HashMap<String, InputSourceState>,
- // https://w3c.github.io/webdriver/#dfn-input-cancel-list
- input_cancel_list: Vec<ActionSequence>,
+ /// <https://w3c.github.io/webdriver/#dfn-input-state-map>
+ input_state_table: RefCell<HashMap<String, InputSourceState>>,
+
+ /// <https://w3c.github.io/webdriver/#dfn-input-cancel-list>
+ input_cancel_list: RefCell<Vec<ActionSequence>>,
}
impl WebDriverSession {
@@ -172,8 +195,8 @@ impl WebDriverSession {
strict_file_interactability: false,
unhandled_prompt_behavior: "dismiss and notify".to_string(),
- input_state_table: HashMap::new(),
- input_cancel_list: Vec::new(),
+ input_state_table: RefCell::new(HashMap::new()),
+ input_cancel_list: RefCell::new(Vec::new()),
}
}
}
@@ -187,8 +210,22 @@ struct Handler {
/// for it to send us a load-status. Messages sent on it
/// will be forwarded to the load_status_receiver.
load_status_sender: IpcSender<WebDriverLoadStatus>,
+
session: Option<WebDriverSession>,
+
+ /// The channel for sending Webdriver messages to the constellation.
constellation_chan: Sender<EmbedderToConstellationMessage>,
+
+ /// The IPC sender which we can clone and pass along to the constellation
+ constellation_sender: IpcSender<WebDriverCommandResponse>,
+
+ /// Receiver notification from the constellation when a command is completed
+ constellation_receiver: IpcReceiver<WebDriverCommandResponse>,
+
+ id_generator: WebDriverMessageIdGenerator,
+
+ current_action_id: Cell<Option<WebDriverMessageId>>,
+
resize_timeout: u32,
}
@@ -409,11 +446,18 @@ impl Handler {
let (load_status_sender, receiver) = ipc::channel().unwrap();
let (sender, load_status_receiver) = unbounded();
ROUTER.route_ipc_receiver_to_crossbeam_sender(receiver, sender);
+
+ let (constellation_sender, constellation_receiver) = ipc::channel().unwrap();
+
Handler {
load_status_sender,
load_status_receiver,
session: None,
constellation_chan,
+ constellation_sender,
+ constellation_receiver,
+ id_generator: WebDriverMessageIdGenerator::new(),
+ current_action_id: Cell::new(None),
resize_timeout: 500,
}
}
@@ -1445,18 +1489,13 @@ impl Handler {
}
fn handle_release_actions(&mut self) -> WebDriverResult<WebDriverResponse> {
- let input_cancel_list = {
- let session = self.session_mut()?;
- session.input_cancel_list.reverse();
- mem::take(&mut session.input_cancel_list)
- };
-
+ let input_cancel_list = self.session().unwrap().input_cancel_list.borrow();
if let Err(error) = self.dispatch_actions(&input_cancel_list) {
return Err(WebDriverError::new(error, ""));
}
- let session = self.session_mut()?;
- session.input_state_table = HashMap::new();
+ let session = self.session()?;
+ session.input_state_table.borrow_mut().clear();
Ok(WebDriverResponse::Void)
}
@@ -1614,7 +1653,7 @@ impl Handler {
let id = Uuid::new_v4().to_string();
// Step 8.1
- self.session_mut()?.input_state_table.insert(
+ self.session_mut()?.input_state_table.borrow_mut().insert(
id.clone(),
InputSourceState::Pointer(PointerInputState::new(&PointerType::Mouse)),
);
@@ -1645,19 +1684,31 @@ impl Handler {
..Default::default()
};
- // Step 8.16 Dispatch a list of actions with input state,
- // actions, session's current browsing context, and actions options.
- if let Err(error) =
- self.dispatch_pointermove_action(&id, &pointer_move_action, 0)
- {
- return Err(WebDriverError::new(error, ""));
- }
+ let action_sequence = ActionSequence {
+ id: id.clone(),
+ actions: ActionsType::Pointer {
+ parameters: PointerActionParameters {
+ pointer_type: PointerType::Mouse,
+ },
+ actions: vec![
+ PointerActionItem::Pointer(PointerAction::Move(
+ pointer_move_action,
+ )),
+ PointerActionItem::Pointer(PointerAction::Down(
+ pointer_down_action,
+ )),
+ PointerActionItem::Pointer(PointerAction::Up(pointer_up_action)),
+ ],
+ },
+ };
- self.dispatch_pointerdown_action(&id, &pointer_down_action);
- self.dispatch_pointerup_action(&id, &pointer_up_action);
+ let _ = self.dispatch_actions(&[action_sequence]);
// Step 8.17 Remove an input source with input state and input id.
- self.session_mut()?.input_state_table.remove(&id);
+ self.session_mut()?
+ .input_state_table
+ .borrow_mut()
+ .remove(&id);
// Step 13
Ok(WebDriverResponse::Void)
@@ -1709,7 +1760,8 @@ impl Handler {
"Unexpected screenshot pixel format"
);
- let rgb = RgbaImage::from_raw(img.width, img.height, img.bytes().to_vec()).unwrap();
+ let rgb =
+ RgbaImage::from_raw(img.width, img.height, img.first_frame().bytes.to_vec()).unwrap();
let mut png_data = Cursor::new(Vec::new());
DynamicImage::ImageRgba8(rgb)
.write_to(&mut png_data, ImageFormat::Png)