libservo: Move WebDriver messages to the embedder crate (#35602)

This is the first step toward moving the WebDriver implementation to
servoshell. This move will make it possible to start testing the
embedding API with WebDriver. See [this zulip thread][a] for more details.

While WebDriver will be able to use a lot of API commands to do what it
is doing now, there will still need to be some "cheat codes" for more
gnarly access to `ScriptThread` details. That's why we likely won't be
able to remove all WebDriver-specific messages from the API -- but maybe
they will be useful for embedders somehow.

A couple messages have to change as they depended on `script_traits`
types, particularly those that used `WindowSizeData` and `LoadData`. I
think this helps to encapsulate the WebDriver commands a bit more
though.

[a]: https://servo.zulipchat.com/#narrow/channel/437943-embedding/topic/webdriver.20as.20embedding.20api.20playgound

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-02-24 14:57:28 +01:00 committed by GitHub
parent 41c2422a66
commit 6062995636
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 125 additions and 124 deletions

4
Cargo.lock generated
View file

@ -1852,6 +1852,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"base", "base",
"cfg-if", "cfg-if",
"cookie 0.18.1",
"crossbeam-channel", "crossbeam-channel",
"euclid", "euclid",
"http 1.2.0", "http 1.2.0",
@ -1862,10 +1863,13 @@ dependencies = [
"malloc_size_of_derive", "malloc_size_of_derive",
"num-derive", "num-derive",
"num-traits", "num-traits",
"pixels",
"serde", "serde",
"servo_malloc_size_of", "servo_malloc_size_of",
"servo_url", "servo_url",
"style_traits",
"url", "url",
"webdriver",
"webrender_api", "webrender_api",
"webxr-api", "webxr-api",
] ]

View file

@ -116,12 +116,11 @@ use devtools_traits::{
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, DevtoolsPageInfo, NavigationState, ChromeToDevtoolsControlMsg, DevtoolsControlMsg, DevtoolsPageInfo, NavigationState,
ScriptToDevtoolsControlMsg, ScriptToDevtoolsControlMsg,
}; };
use embedder_traits::input_events::MouseButtonAction;
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use embedder_traits::{ use embedder_traits::{
Cursor, EmbedderMsg, EmbedderProxy, ImeEvent, InputEvent, MediaSessionActionType, Cursor, EmbedderMsg, EmbedderProxy, ImeEvent, InputEvent, MediaSessionActionType,
MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonEvent, Theme, MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent,
TraversalDirection, Theme, TraversalDirection, WebDriverCommandMsg, WebDriverLoadStatus,
}; };
use euclid::default::Size2D as UntypedSize2D; use euclid::default::Size2D as UntypedSize2D;
use euclid::Size2D; use euclid::Size2D;
@ -139,14 +138,14 @@ use net_traits::{self, IpcSend, ReferrerPolicy, ResourceThreads};
use profile_traits::{mem, time}; use profile_traits::{mem, time};
use script_layout_interface::{LayoutFactory, ScriptThreadFactory}; use script_layout_interface::{LayoutFactory, ScriptThreadFactory};
use script_traits::{ use script_traits::{
webdriver_msg, AnimationState, AnimationTickType, AuxiliaryBrowsingContextLoadInfo, AnimationState, AnimationTickType, AuxiliaryBrowsingContextLoadInfo, BroadcastMsg,
BroadcastMsg, ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, DocumentState, ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, DocumentState,
IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, IFrameSizeMsg, Job, IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, IFrameSizeMsg, Job,
LayoutMsg as FromLayoutMsg, LoadData, LoadOrigin, LogEntry, MessagePortMsg, LayoutMsg as FromLayoutMsg, LoadData, LoadOrigin, LogEntry, MessagePortMsg,
NavigationHistoryBehavior, PortMessageTask, SWManagerMsg, SWManagerSenders, NavigationHistoryBehavior, PortMessageTask, SWManagerMsg, SWManagerSenders,
ScriptMsg as FromScriptMsg, ScriptThreadMessage, ScriptToConstellationChan, ScriptMsg as FromScriptMsg, ScriptThreadMessage, ScriptToConstellationChan,
ServiceWorkerManagerFactory, ServiceWorkerMsg, StructuredSerializedData, ServiceWorkerManagerFactory, ServiceWorkerMsg, StructuredSerializedData,
UpdatePipelineIdReason, WebDriverCommandMsg, WindowSizeData, WindowSizeType, UpdatePipelineIdReason, WindowSizeData, WindowSizeType,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_config::{opts, pref}; use servo_config::{opts, pref};
@ -531,8 +530,8 @@ pub struct InitialConstellationState {
/// Data needed for webdriver /// Data needed for webdriver
struct WebDriverData { struct WebDriverData {
load_channel: Option<(PipelineId, IpcSender<webdriver_msg::LoadStatus>)>, load_channel: Option<(PipelineId, IpcSender<WebDriverLoadStatus>)>,
resize_channel: Option<IpcSender<WindowSizeData>>, resize_channel: Option<IpcSender<Size2D<f32, CSSPixel>>>,
} }
impl WebDriverData { impl WebDriverData {
@ -2965,7 +2964,7 @@ where
&mut self, &mut self,
url: ServoUrl, url: ServoUrl,
top_level_browsing_context_id: TopLevelBrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId,
response_sender: Option<IpcSender<webdriver_msg::LoadStatus>>, response_sender: Option<IpcSender<WebDriverLoadStatus>>,
) { ) {
let window_size = self.window_size.initial_viewport; let window_size = self.window_size.initial_viewport;
let pipeline_id = PipelineId::new(); let pipeline_id = PipelineId::new();
@ -3667,7 +3666,7 @@ where
if let Some((expected_pipeline_id, ref reply_chan)) = self.webdriver.load_channel { if let Some((expected_pipeline_id, ref reply_chan)) = self.webdriver.load_channel {
debug!("Sending load for {:?} to WebDriver", expected_pipeline_id); debug!("Sending load for {:?} to WebDriver", expected_pipeline_id);
if expected_pipeline_id == pipeline_id { if expected_pipeline_id == pipeline_id {
let _ = reply_chan.send(webdriver_msg::LoadStatus::LoadComplete); let _ = reply_chan.send(WebDriverLoadStatus::Complete);
webdriver_reset = true; webdriver_reset = true;
} }
} }
@ -4425,7 +4424,7 @@ where
self.handle_focus_web_view(top_level_browsing_context_id); self.handle_focus_web_view(top_level_browsing_context_id);
}, },
WebDriverCommandMsg::GetWindowSize(_, response_sender) => { WebDriverCommandMsg::GetWindowSize(_, response_sender) => {
let _ = response_sender.send(self.window_size); let _ = response_sender.send(self.window_size.initial_viewport);
}, },
WebDriverCommandMsg::SetWindowSize( WebDriverCommandMsg::SetWindowSize(
top_level_browsing_context_id, top_level_browsing_context_id,
@ -4436,11 +4435,16 @@ where
self.embedder_proxy self.embedder_proxy
.send(EmbedderMsg::ResizeTo(top_level_browsing_context_id, size)); .send(EmbedderMsg::ResizeTo(top_level_browsing_context_id, size));
}, },
WebDriverCommandMsg::LoadUrl( WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, url, response_sender) => {
top_level_browsing_context_id, let load_data = LoadData::new(
load_data, LoadOrigin::WebDriver,
response_sender, url,
) => { None,
Referrer::NoReferrer,
ReferrerPolicy::EmptyString,
None,
None,
);
self.load_url_for_webdriver( self.load_url_for_webdriver(
top_level_browsing_context_id, top_level_browsing_context_id,
load_data, load_data,
@ -4699,7 +4703,7 @@ where
&mut self, &mut self,
top_level_browsing_context_id: TopLevelBrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId,
load_data: LoadData, load_data: LoadData,
response_sender: IpcSender<webdriver_msg::LoadStatus>, response_sender: IpcSender<WebDriverLoadStatus>,
history_handling: NavigationHistoryBehavior, history_handling: NavigationHistoryBehavior,
) { ) {
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
@ -4725,7 +4729,7 @@ where
); );
self.webdriver.load_channel = Some((new_pipeline_id, response_sender)); self.webdriver.load_channel = Some((new_pipeline_id, response_sender));
} else { } else {
let _ = response_sender.send(webdriver_msg::LoadStatus::LoadCanceled); let _ = response_sender.send(WebDriverLoadStatus::Canceled);
} }
} }
@ -5037,7 +5041,7 @@ where
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(response_sender) = self.webdriver.resize_channel.take() { if let Some(response_sender) = self.webdriver.resize_channel.take() {
let _ = response_sender.send(new_size); let _ = response_sender.send(new_size.initial_viewport);
} }
self.window_size = new_size; self.window_size = new_size;

View file

@ -25,7 +25,10 @@ use crossbeam_channel::{unbounded, Sender};
use cssparser::{Parser, ParserInput, SourceLocation}; use cssparser::{Parser, ParserInput, SourceLocation};
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, PromptDefinition, PromptOrigin, PromptResult, Theme}; use embedder_traits::{
EmbedderMsg, PromptDefinition, PromptOrigin, PromptResult, Theme, WebDriverJSError,
WebDriverJSResult,
};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
use fonts::FontContext; use fonts::FontContext;
@ -56,7 +59,6 @@ use script_layout_interface::{
combine_id_with_fragment_type, FragmentType, Layout, PendingImageState, QueryMsg, Reflow, combine_id_with_fragment_type, FragmentType, Layout, PendingImageState, QueryMsg, Reflow,
ReflowGoal, ReflowRequest, TrustedNodeAddress, ReflowGoal, ReflowRequest, TrustedNodeAddress,
}; };
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use script_traits::{ use script_traits::{
DocumentState, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptMsg, ScriptThreadMessage, DocumentState, LoadData, LoadOrigin, NavigationHistoryBehavior, ScriptMsg, ScriptThreadMessage,
ScriptToConstellationChan, ScrollState, StructuredSerializedData, WindowSizeData, ScriptToConstellationChan, ScrollState, StructuredSerializedData, WindowSizeData,

View file

@ -45,7 +45,9 @@ use devtools_traits::{
CSSError, DevtoolScriptControlMsg, DevtoolsPageInfo, NavigationState, CSSError, DevtoolScriptControlMsg, DevtoolsPageInfo, NavigationState,
ScriptToDevtoolsControlMsg, WorkerId, ScriptToDevtoolsControlMsg, WorkerId,
}; };
use embedder_traits::{EmbedderMsg, InputEvent, MediaSessionActionType, Theme}; use embedder_traits::{
EmbedderMsg, InputEvent, MediaSessionActionType, Theme, WebDriverScriptCommand,
};
use euclid::default::Rect; use euclid::default::Rect;
use fonts::{FontContext, SystemFontServiceProxy}; use fonts::{FontContext, SystemFontServiceProxy};
use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader};
@ -77,7 +79,6 @@ use profile_traits::time_profile;
use script_layout_interface::{ use script_layout_interface::{
node_id_from_scroll_id, LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory, node_id_from_scroll_id, LayoutConfig, LayoutFactory, ReflowGoal, ScriptThreadFactory,
}; };
use script_traits::webdriver_msg::WebDriverScriptCommand;
use script_traits::{ use script_traits::{
ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, EventResult, ConstellationInputEvent, DiscardBrowsingContext, DocumentActivity, EventResult,
InitialScriptState, JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, InitialScriptState, JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior,

View file

@ -8,6 +8,9 @@ use std::ffi::CString;
use base::id::{BrowsingContextId, PipelineId}; use base::id::{BrowsingContextId, PipelineId};
use cookie::Cookie; use cookie::Cookie;
use embedder_traits::{
WebDriverCookieError, WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue,
};
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
@ -21,9 +24,6 @@ use js::rust::{HandleObject, HandleValue, IdVector};
use net_traits::CookieSource::{NonHTTP, HTTP}; use net_traits::CookieSource::{NonHTTP, HTTP};
use net_traits::CoreResourceMsg::{DeleteCookies, GetCookiesDataForUrl, SetCookieForUrl}; use net_traits::CoreResourceMsg::{DeleteCookies, GetCookiesDataForUrl, SetCookieForUrl};
use net_traits::IpcSend; use net_traits::IpcSend;
use script_traits::webdriver_msg::{
WebDriverCookieError, WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue,
};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use webdriver::common::{WebElement, WebFrame, WebWindow}; use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus; use webdriver::error::ErrorStatus;

View file

@ -8,11 +8,11 @@ use std::time::Duration;
use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId, WebViewId}; use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId, WebViewId};
use base::Epoch; use base::Epoch;
use embedder_traits::{Cursor, InputEvent, MediaSessionActionType, Theme, TraversalDirection}; use embedder_traits::{
use ipc_channel::ipc::IpcSender; Cursor, InputEvent, MediaSessionActionType, Theme, TraversalDirection, WebDriverCommandMsg,
use script_traits::{
AnimationTickType, LogEntry, WebDriverCommandMsg, WindowSizeData, WindowSizeType,
}; };
use ipc_channel::ipc::IpcSender;
use script_traits::{AnimationTickType, LogEntry, WindowSizeData, WindowSizeType};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use webrender_traits::CompositorHitTestResult; use webrender_traits::CompositorHitTestResult;

View file

@ -17,6 +17,7 @@ webxr = ["dep:webxr-api"]
[dependencies] [dependencies]
base = { workspace = true } base = { workspace = true }
cfg-if = { workspace = true } cfg-if = { workspace = true }
cookie = { workspace = true }
crossbeam-channel = { workspace = true } crossbeam-channel = { workspace = true }
euclid = { workspace = true } euclid = { workspace = true }
http = { workspace = true } http = { workspace = true }
@ -28,8 +29,11 @@ num-derive = "0.4"
malloc_size_of = { workspace = true } malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true } malloc_size_of_derive = { workspace = true }
num-traits = { workspace = true } num-traits = { workspace = true }
pixels = { path = "../../pixels" }
serde = { workspace = true } serde = { workspace = true }
servo_url = { path = "../../url" } servo_url = { path = "../../url" }
style_traits = { workspace = true }
url = { workspace = true } url = { workspace = true }
webdriver = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }
webxr-api = { workspace = true, features = ["ipc"], optional = true } webxr-api = { workspace = true, features = ["ipc"], optional = true }

View file

@ -4,6 +4,7 @@
pub mod input_events; pub mod input_events;
pub mod resources; pub mod resources;
mod webdriver;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::path::PathBuf; use std::path::PathBuf;
@ -22,6 +23,7 @@ use url::Url;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
pub use crate::input_events::*; pub use crate::input_events::*;
pub use crate::webdriver::*;
/// Tracks whether Servo isn't shutting down, is in the process of shutting down, /// Tracks whether Servo isn't shutting down, is in the process of shutting down,
/// or has finished shutting down. /// or has finished shutting down.

View file

@ -6,15 +6,66 @@
use std::collections::HashMap; use std::collections::HashMap;
use base::id::BrowsingContextId; use base::id::{BrowsingContextId, WebViewId};
use cookie::Cookie; use cookie::Cookie;
use euclid::default::Rect; use euclid::default::Rect as UntypedRect;
use euclid::{Rect, Size2D};
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use keyboard_types::webdriver::Event as WebDriverInputEvent;
use keyboard_types::KeyboardEvent;
use pixels::Image;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use style_traits::CSSPixel;
use webdriver::common::{WebElement, WebFrame, WebWindow}; use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus; use webdriver::error::ErrorStatus;
use webrender_api::units::DeviceIntSize;
use crate::{MouseButton, MouseButtonAction};
/// Messages to the constellation originating from the WebDriver server.
#[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverCommandMsg {
/// Get the window size.
GetWindowSize(WebViewId, IpcSender<Size2D<f32, CSSPixel>>),
/// Load a URL in the top-level browsing context with the given ID.
LoadUrl(WebViewId, ServoUrl, IpcSender<WebDriverLoadStatus>),
/// Refresh the top-level browsing context with the given ID.
Refresh(WebViewId, IpcSender<WebDriverLoadStatus>),
/// Pass a webdriver command to the script thread of the current pipeline
/// of a browsing context.
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
/// Act as if keys were pressed in the browsing context with the given ID.
SendKeys(BrowsingContextId, Vec<WebDriverInputEvent>),
/// Act as if keys were pressed or release in the browsing context with the given ID.
KeyboardAction(BrowsingContextId, KeyboardEvent),
/// Act as if the mouse was clicked in the browsing context with the given ID.
MouseButtonAction(MouseButtonAction, MouseButton, f32, f32),
/// Act as if the mouse was moved in the browsing context with the given ID.
MouseMoveAction(f32, f32),
/// Set the window size.
SetWindowSize(WebViewId, DeviceIntSize, IpcSender<Size2D<f32, CSSPixel>>),
/// Take a screenshot of the window.
TakeScreenshot(
WebViewId,
Option<Rect<f32, CSSPixel>>,
IpcSender<Option<Image>>,
),
/// Create a new webview that loads about:blank. The constellation will use
/// the provided channels to return the top level browsing context id
/// associated with the new webview, and a notification when the initial
/// load is complete.
NewWebView(
WebViewId,
IpcSender<WebViewId>,
IpcSender<WebDriverLoadStatus>,
),
/// Close the webview associated with the provided id.
CloseWebView(WebViewId),
/// Focus the webview associated with the provided id.
FocusWebView(WebViewId),
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverScriptCommand { pub enum WebDriverScriptCommand {
@ -75,11 +126,11 @@ pub enum WebDriverScriptCommand {
IpcSender<Result<WebDriverJSValue, ErrorStatus>>, IpcSender<Result<WebDriverJSValue, ErrorStatus>>,
), ),
GetElementCSS(String, String, IpcSender<Result<String, ErrorStatus>>), GetElementCSS(String, String, IpcSender<Result<String, ErrorStatus>>),
GetElementRect(String, IpcSender<Result<Rect<f64>, ErrorStatus>>), GetElementRect(String, IpcSender<Result<UntypedRect<f64>, ErrorStatus>>),
GetElementTagName(String, IpcSender<Result<String, ErrorStatus>>), GetElementTagName(String, IpcSender<Result<String, ErrorStatus>>),
GetElementText(String, IpcSender<Result<String, ErrorStatus>>), GetElementText(String, IpcSender<Result<String, ErrorStatus>>),
GetElementInViewCenterPoint(String, IpcSender<Result<Option<(i64, i64)>, ErrorStatus>>), GetElementInViewCenterPoint(String, IpcSender<Result<Option<(i64, i64)>, ErrorStatus>>),
GetBoundingClientRect(String, IpcSender<Result<Rect<f32>, ErrorStatus>>), GetBoundingClientRect(String, IpcSender<Result<UntypedRect<f32>, ErrorStatus>>),
GetBrowsingContextId( GetBrowsingContextId(
WebDriverFrameId, WebDriverFrameId,
IpcSender<Result<BrowsingContextId, ErrorStatus>>, IpcSender<Result<BrowsingContextId, ErrorStatus>>,
@ -133,8 +184,8 @@ pub enum WebDriverFrameId {
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum LoadStatus { pub enum WebDriverLoadStatus {
LoadComplete, Complete,
LoadTimeout, Timeout,
LoadCanceled, Canceled,
} }

View file

@ -12,7 +12,6 @@
mod script_msg; mod script_msg;
pub mod serializable; pub mod serializable;
pub mod transferable; pub mod transferable;
pub mod webdriver_msg;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
@ -23,7 +22,7 @@ use background_hang_monitor_api::BackgroundHangMonitorRegister;
use base::cross_process_instant::CrossProcessInstant; use base::cross_process_instant::CrossProcessInstant;
use base::id::{ use base::id::{
BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId, BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId,
TopLevelBrowsingContextId, WebViewId, TopLevelBrowsingContextId,
}; };
use base::Epoch; use base::Epoch;
use bitflags::bitflags; use bitflags::bitflags;
@ -33,13 +32,11 @@ use canvas_traits::webgl::WebGLPipeline;
use crossbeam_channel::{RecvTimeoutError, Sender}; use crossbeam_channel::{RecvTimeoutError, Sender};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::input_events::InputEvent; use embedder_traits::input_events::InputEvent;
use embedder_traits::{MediaSessionActionType, MouseButton, MouseButtonAction, Theme}; use embedder_traits::{MediaSessionActionType, Theme, WebDriverScriptCommand};
use euclid::{Rect, Scale, Size2D, UnknownUnit, Vector2D}; use euclid::{Rect, Scale, Size2D, UnknownUnit, Vector2D};
use http::{HeaderMap, Method}; use http::{HeaderMap, Method};
use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::Error as IpcError; use ipc_channel::Error as IpcError;
use keyboard_types::webdriver::Event as WebDriverInputEvent;
use keyboard_types::KeyboardEvent;
use libc::c_void; use libc::c_void;
use log::warn; use log::warn;
use malloc_size_of::malloc_size_of_is_0; use malloc_size_of::malloc_size_of_is_0;
@ -49,7 +46,7 @@ use net_traits::image_cache::ImageCache;
use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBody}; use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBody};
use net_traits::storage_thread::StorageType; use net_traits::storage_thread::StorageType;
use net_traits::{ReferrerPolicy, ResourceThreads}; use net_traits::{ReferrerPolicy, ResourceThreads};
use pixels::{Image, PixelFormat}; use pixels::PixelFormat;
use profile_traits::{mem, time as profile_time}; use profile_traits::{mem, time as profile_time};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_atoms::Atom; use servo_atoms::Atom;
@ -57,7 +54,7 @@ use servo_url::{ImmutableOrigin, ServoUrl};
use style_traits::{CSSPixel, SpeculativePainter}; use style_traits::{CSSPixel, SpeculativePainter};
#[cfg(feature = "webgpu")] #[cfg(feature = "webgpu")]
use webgpu::WebGPUMsg; use webgpu::WebGPUMsg;
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; use webrender_api::units::{DevicePixel, LayoutPixel};
use webrender_api::{DocumentId, ExternalScrollId, ImageKey}; use webrender_api::{DocumentId, ExternalScrollId, ImageKey};
use webrender_traits::{ use webrender_traits::{
CompositorHitTestResult, CrossProcessCompositorApi, CompositorHitTestResult, CrossProcessCompositorApi,
@ -70,7 +67,6 @@ pub use crate::script_msg::{
}; };
use crate::serializable::{BlobData, BlobImpl}; use crate::serializable::{BlobData, BlobImpl};
use crate::transferable::MessagePortImpl; use crate::transferable::MessagePortImpl;
use crate::webdriver_msg::{LoadStatus, WebDriverScriptCommand};
/// The address of a node. Layout sends these back. They must be validated via /// The address of a node. Layout sends these back. They must be validated via
/// `from_untrusted_node_address` before they can be used, because we do not trust layout. /// `from_untrusted_node_address` before they can be used, because we do not trust layout.
@ -652,53 +648,6 @@ pub enum WindowSizeType {
Resize, Resize,
} }
/// Messages to the constellation originating from the WebDriver server.
#[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverCommandMsg {
/// Get the window size.
GetWindowSize(TopLevelBrowsingContextId, IpcSender<WindowSizeData>),
/// Load a URL in the top-level browsing context with the given ID.
LoadUrl(TopLevelBrowsingContextId, LoadData, IpcSender<LoadStatus>),
/// Refresh the top-level browsing context with the given ID.
Refresh(TopLevelBrowsingContextId, IpcSender<LoadStatus>),
/// Pass a webdriver command to the script thread of the current pipeline
/// of a browsing context.
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
/// Act as if keys were pressed in the browsing context with the given ID.
SendKeys(BrowsingContextId, Vec<WebDriverInputEvent>),
/// Act as if keys were pressed or release in the browsing context with the given ID.
KeyboardAction(BrowsingContextId, KeyboardEvent),
/// Act as if the mouse was clicked in the browsing context with the given ID.
MouseButtonAction(MouseButtonAction, MouseButton, f32, f32),
/// Act as if the mouse was moved in the browsing context with the given ID.
MouseMoveAction(f32, f32),
/// Set the window size.
SetWindowSize(
TopLevelBrowsingContextId,
DeviceIntSize,
IpcSender<WindowSizeData>,
),
/// Take a screenshot of the window.
TakeScreenshot(
TopLevelBrowsingContextId,
Option<Rect<f32, CSSPixel>>,
IpcSender<Option<Image>>,
),
/// Create a new webview that loads about:blank. The constellation will use
/// the provided channels to return the top level browsing context id
/// associated with the new webview, and a notification when the initial
/// load is complete.
NewWebView(
WebViewId,
IpcSender<TopLevelBrowsingContextId>,
IpcSender<LoadStatus>,
),
/// Close the webview associated with the provided id.
CloseWebView(TopLevelBrowsingContextId),
/// Focus the webview associated with the provided id.
FocusWebView(TopLevelBrowsingContextId),
}
/// Resources required by workerglobalscopes /// Resources required by workerglobalscopes
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkerGlobalScopeInit { pub struct WorkerGlobalScopeInit {

View file

@ -7,11 +7,9 @@ use std::time::{Duration, Instant};
use std::{cmp, thread}; use std::{cmp, thread};
use compositing_traits::ConstellationMsg; use compositing_traits::ConstellationMsg;
use embedder_traits::MouseButtonAction; use embedder_traits::{MouseButtonAction, WebDriverCommandMsg, WebDriverScriptCommand};
use ipc_channel::ipc; use ipc_channel::ipc;
use keyboard_types::webdriver::KeyInputState; use keyboard_types::webdriver::KeyInputState;
use script_traits::webdriver_msg::WebDriverScriptCommand;
use script_traits::WebDriverCommandMsg;
use webdriver::actions::{ use webdriver::actions::{
ActionSequence, ActionsType, GeneralAction, KeyAction, KeyActionItem, KeyDownAction, ActionSequence, ActionsType, GeneralAction, KeyAction, KeyActionItem, KeyDownAction,
KeyUpAction, NullActionItem, PointerAction, PointerActionItem, PointerActionParameters, KeyUpAction, NullActionItem, PointerAction, PointerActionItem, PointerActionParameters,
@ -398,8 +396,8 @@ impl Handler {
.unwrap(); .unwrap();
// Steps 7 - 8 // Steps 7 - 8
let viewport = receiver.recv().unwrap().initial_viewport; let viewport_size = receiver.recv().unwrap();
if x < 0 || x as f32 > viewport.width || y < 0 || y as f32 > viewport.height { if x < 0 || x as f32 > viewport_size.width || y < 0 || y as f32 > viewport_size.height {
return Err(ErrorStatus::MoveTargetOutOfBounds); return Err(ErrorStatus::MoveTargetOutOfBounds);
} }

View file

@ -22,7 +22,11 @@ use capabilities::ServoCapabilities;
use compositing_traits::ConstellationMsg; use compositing_traits::ConstellationMsg;
use cookie::{CookieBuilder, Expiration}; use cookie::{CookieBuilder, Expiration};
use crossbeam_channel::{after, select, unbounded, Receiver, Sender}; use crossbeam_channel::{after, select, unbounded, Receiver, Sender};
use embedder_traits::TraversalDirection; use embedder_traits::{
TraversalDirection, WebDriverCommandMsg, WebDriverCookieError, WebDriverFrameId,
WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus,
WebDriverScriptCommand,
};
use euclid::{Rect, Size2D}; use euclid::{Rect, Size2D};
use http::method::Method; use http::method::Method;
use image::{DynamicImage, ImageFormat, RgbaImage}; use image::{DynamicImage, ImageFormat, RgbaImage};
@ -30,14 +34,7 @@ use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use keyboard_types::webdriver::send_keys; use keyboard_types::webdriver::send_keys;
use log::{debug, info}; use log::{debug, info};
use net_traits::request::Referrer;
use net_traits::ReferrerPolicy;
use pixels::PixelFormat; use pixels::PixelFormat;
use script_traits::webdriver_msg::{
LoadStatus, WebDriverCookieError, WebDriverFrameId, WebDriverJSError, WebDriverJSResult,
WebDriverJSValue, WebDriverScriptCommand,
};
use script_traits::{LoadData, LoadOrigin, WebDriverCommandMsg};
use serde::de::{Deserializer, MapAccess, Visitor}; use serde::de::{Deserializer, MapAccess, Visitor};
use serde::ser::Serializer; use serde::ser::Serializer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -189,11 +186,11 @@ struct Handler {
/// The threaded receiver on which we can block for a load-status. /// The threaded receiver on which we can block for a load-status.
/// It will receive messages sent on the load_status_sender, /// It will receive messages sent on the load_status_sender,
/// and forwarded by the IPC router. /// and forwarded by the IPC router.
load_status_receiver: Receiver<LoadStatus>, load_status_receiver: Receiver<WebDriverLoadStatus>,
/// The IPC sender which we can clone and pass along to the constellation, /// The IPC sender which we can clone and pass along to the constellation,
/// for it to send us a load-status. Messages sent on it /// for it to send us a load-status. Messages sent on it
/// will be forwarded to the load_status_receiver. /// will be forwarded to the load_status_receiver.
load_status_sender: IpcSender<LoadStatus>, load_status_sender: IpcSender<WebDriverLoadStatus>,
session: Option<WebDriverSession>, session: Option<WebDriverSession>,
constellation_chan: Sender<ConstellationMsg>, constellation_chan: Sender<ConstellationMsg>,
resize_timeout: u32, resize_timeout: u32,
@ -662,18 +659,9 @@ impl Handler {
let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id; let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let load_data = LoadData::new(
LoadOrigin::WebDriver,
url,
None,
Referrer::NoReferrer,
ReferrerPolicy::EmptyString,
None,
None,
);
let cmd_msg = WebDriverCommandMsg::LoadUrl( let cmd_msg = WebDriverCommandMsg::LoadUrl(
top_level_browsing_context_id, top_level_browsing_context_id,
load_data, url,
self.load_status_sender.clone(), self.load_status_sender.clone(),
); );
self.constellation_chan self.constellation_chan
@ -717,12 +705,11 @@ impl Handler {
.unwrap(); .unwrap();
let window_size = receiver.recv().unwrap(); let window_size = receiver.recv().unwrap();
let vp = window_size.initial_viewport;
let window_size_response = WindowRectResponse { let window_size_response = WindowRectResponse {
x: 0, x: 0,
y: 0, y: 0,
width: vp.width as i32, width: window_size.width as i32,
height: vp.height as i32, height: window_size.height as i32,
}; };
Ok(WebDriverResponse::WindowRect(window_size_response)) Ok(WebDriverResponse::WindowRect(window_size_response))
} }
@ -766,12 +753,11 @@ impl Handler {
}); });
let window_size = receiver.recv().unwrap(); let window_size = receiver.recv().unwrap();
let vp = window_size.initial_viewport;
let window_size_response = WindowRectResponse { let window_size_response = WindowRectResponse {
x: 0, x: 0,
y: 0, y: 0,
width: vp.width as i32, width: window_size.width as i32,
height: vp.height as i32, height: window_size.height as i32,
}; };
Ok(WebDriverResponse::WindowRect(window_size_response)) Ok(WebDriverResponse::WindowRect(window_size_response))
} }