mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
libservo: Allow embedders to execute JavaScript scripts via the API (#35720)
This change adds a new `WebView` API `evaluate_javascript()`, which allows embedders to execute JavaScript code and wait for a reply asynchronously. Ongoing script execution is tracked by a libservo `JavaScriptEvaluator` struct, which maps an id to the callback passed to the `evaluate_javascript()` method. The id is used to track the script and its execution through the other parts of Servo. Testing: This changes includes `WebView` unit tests. --------- Signed-off-by: Narfinger <Narfinger@users.noreply.github.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
91c4c7b998
commit
991be359a3
12 changed files with 391 additions and 18 deletions
|
@ -15,8 +15,8 @@ use base::id::{
|
|||
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
||||
use embedder_traits::{
|
||||
AnimationState, EmbedderMsg, FocusSequenceNumber, MediaSessionEvent, TouchEventResult,
|
||||
ViewportDetails,
|
||||
AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
|
||||
JavaScriptEvaluationId, MediaSessionEvent, TouchEventResult, ViewportDetails,
|
||||
};
|
||||
use euclid::default::Size2D as UntypedSize2D;
|
||||
use http::{HeaderMap, Method};
|
||||
|
@ -644,6 +644,11 @@ pub enum ScriptToConstellationMessage {
|
|||
IFrameSizes(Vec<IFrameSizeMsg>),
|
||||
/// Request results from the memory reporter.
|
||||
ReportMemory(IpcSender<MemoryReportResult>),
|
||||
/// Return the result of the evaluated JavaScript with the given [`JavaScriptEvaluationId`].
|
||||
FinishJavaScriptEvaluation(
|
||||
JavaScriptEvaluationId,
|
||||
Result<JSValue, JavaScriptEvaluationError>,
|
||||
),
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScriptToConstellationMessage {
|
||||
|
|
|
@ -19,8 +19,8 @@ use base::Epoch;
|
|||
use base::cross_process_instant::CrossProcessInstant;
|
||||
use base::id::{MessagePortId, PipelineId, WebViewId};
|
||||
use embedder_traits::{
|
||||
CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
|
||||
WebDriverCommandMsg,
|
||||
CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
|
||||
Theme, ViewportDetails, WebDriverCommandMsg,
|
||||
};
|
||||
use euclid::Vector2D;
|
||||
pub use from_script_message::*;
|
||||
|
@ -92,6 +92,9 @@ pub enum EmbedderToConstellationMessage {
|
|||
SetScrollStates(PipelineId, Vec<ScrollState>),
|
||||
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
|
||||
PaintMetric(PipelineId, PaintMetricEvent),
|
||||
/// Evaluate a JavaScript string in the context of a `WebView`. When execution is complete or an
|
||||
/// error is encountered, a correpsonding message will be sent to the embedding layer.
|
||||
EvaluateJavaScript(WebViewId, JavaScriptEvaluationId, String),
|
||||
}
|
||||
|
||||
/// A description of a paint metric that is sent from the Servo renderer to the
|
||||
|
|
|
@ -13,8 +13,10 @@ pub mod resources;
|
|||
pub mod user_content_manager;
|
||||
mod webdriver;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_void;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -372,6 +374,12 @@ pub enum EmbedderMsg {
|
|||
DeviceIntRect,
|
||||
IpcSender<Option<usize>>,
|
||||
),
|
||||
/// Inform the embedding layer that a JavaScript evaluation has
|
||||
/// finished with the given result.
|
||||
FinishJavaScriptEvaluation(
|
||||
JavaScriptEvaluationId,
|
||||
Result<JSValue, JavaScriptEvaluationError>,
|
||||
),
|
||||
}
|
||||
|
||||
impl Debug for EmbedderMsg {
|
||||
|
@ -857,3 +865,59 @@ impl Display for FocusSequenceNumber {
|
|||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for a particular JavaScript evaluation that is used to track the
|
||||
/// evaluation from the embedding layer to the script layer and then back.
|
||||
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct JavaScriptEvaluationId(pub usize);
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub enum JSValue {
|
||||
Undefined,
|
||||
Null,
|
||||
Boolean(bool),
|
||||
Number(f64),
|
||||
String(String),
|
||||
Element(String),
|
||||
Frame(String),
|
||||
Window(String),
|
||||
Array(Vec<JSValue>),
|
||||
Object(HashMap<String, JSValue>),
|
||||
}
|
||||
|
||||
impl From<&WebDriverJSValue> for JSValue {
|
||||
fn from(value: &WebDriverJSValue) -> Self {
|
||||
match value {
|
||||
WebDriverJSValue::Undefined => Self::Undefined,
|
||||
WebDriverJSValue::Null => Self::Null,
|
||||
WebDriverJSValue::Boolean(value) => Self::Boolean(*value),
|
||||
WebDriverJSValue::Int(value) => Self::Number(*value as f64),
|
||||
WebDriverJSValue::Number(value) => Self::Number(*value),
|
||||
WebDriverJSValue::String(value) => Self::String(value.clone()),
|
||||
WebDriverJSValue::Element(web_element) => Self::Element(web_element.0.clone()),
|
||||
WebDriverJSValue::Frame(web_frame) => Self::Frame(web_frame.0.clone()),
|
||||
WebDriverJSValue::Window(web_window) => Self::Window(web_window.0.clone()),
|
||||
WebDriverJSValue::ArrayLike(vector) => {
|
||||
Self::Array(vector.iter().map(Into::into).collect())
|
||||
},
|
||||
WebDriverJSValue::Object(map) => Self::Object(
|
||||
map.iter()
|
||||
.map(|(key, value)| (key.clone(), value.into()))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub enum JavaScriptEvaluationError {
|
||||
/// An internal Servo error prevented the JavaSript evaluation from completing properly.
|
||||
/// This indicates a bug in Servo.
|
||||
InternalError,
|
||||
/// The `WebView` on which this evaluation request was triggered is not ready. This might
|
||||
/// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
|
||||
WebViewNotReady,
|
||||
/// The script executed successfully, but Servo could not serialize the JavaScript return
|
||||
/// value into a [`JSValue`].
|
||||
SerializationError,
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ use crossbeam_channel::{RecvTimeoutError, Sender};
|
|||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use embedder_traits::user_content_manager::UserContentManager;
|
||||
use embedder_traits::{
|
||||
CompositorHitTestResult, FocusSequenceNumber, InputEvent, MediaSessionActionType, Theme,
|
||||
ViewportDetails, WebDriverScriptCommand,
|
||||
CompositorHitTestResult, FocusSequenceNumber, InputEvent, JavaScriptEvaluationId,
|
||||
MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand,
|
||||
};
|
||||
use euclid::{Rect, Scale, Size2D, UnknownUnit};
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
|
@ -245,6 +245,9 @@ pub enum ScriptThreadMessage {
|
|||
/// The compositor scrolled and is updating the scroll states of the nodes in the given
|
||||
/// pipeline via the Constellation.
|
||||
SetScrollStates(PipelineId, Vec<ScrollState>),
|
||||
/// Evaluate the given JavaScript and return a result via a corresponding message
|
||||
/// to the Constellation.
|
||||
EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScriptThreadMessage {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue