Move ScriptToConstellationMsg to constellation_traits (#36364)

This is the last big change necessary to create the
`constellation_traits` crate. This moves the data structure for messages
that originate from the `ScriptThread` and are sent to the
`Contellation` to `constellation_traits`, effectively splitting
`script_traits` in half. Before, `script_traits` was responsible for
exposing the API of both the `ScriptThread` and the `Constellation` to
the rest of Servo.

- Data structures that are used by `ScriptToConstellationMsg` are moved
  to `constellation_traits`. The dependency graph looks a bit like this:
  `script_layout_interface` depends on `script_traits` depends on
  `constellation_traits` depends on `embedder_traits`.
- Data structures that are used in the embedding layer
  (`UntrustedNodeAddress`, `CompositorHitTestResult`, `TouchEventResult`
  and `AnimationState`) are moved to embedder_traits, to avoid a
  dependency cycle between `webrender_traits` and
  `constellation_traits`.
- Types dealing with MessagePorts and serialization are moved to
  `constellation_traits::message_port`.

Testing: This is covered by existing tests as it just moves types
around.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-04-06 00:13:29 +02:00 committed by GitHub
parent a67409fb25
commit 6031a12fd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 1224 additions and 1222 deletions

View file

@ -8,12 +8,13 @@ use std::fmt::{Debug, Error, Formatter};
use base::id::{PipelineId, WebViewId};
use crossbeam_channel::{Receiver, Sender};
use embedder_traits::{EventLoopWaker, MouseButton, MouseButtonAction};
use embedder_traits::{
AnimationState, EventLoopWaker, MouseButton, MouseButtonAction, TouchEventResult,
};
use euclid::Rect;
use ipc_channel::ipc::IpcSender;
use log::warn;
use pixels::Image;
use script_traits::{AnimationState, TouchEventResult};
use strum_macros::IntoStaticStr;
use style_traits::CSSPixel;
use webrender_api::DocumentId;

View file

@ -11,16 +11,30 @@ rust-version.workspace = true
name = "constellation_traits"
path = "lib.rs"
[features]
bluetooth = []
webgpu = ["wgpu-core"]
[dependencies]
base = { workspace = true }
bitflags = { workspace = true }
canvas_traits = { workspace = true }
devtools_traits = { workspace = true }
embedder_traits = { workspace = true }
euclid = { workspace = true }
http = { workspace = true }
hyper_serde = { workspace = true }
ipc-channel = { workspace = true }
log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
net_traits = { workspace = true }
profile_traits = { workspace = true }
serde = { workspace = true }
servo_url = { path = "../../url" }
strum = { workspace = true }
strum_macros = { workspace = true }
stylo_traits = { workspace = true }
uuid = { workspace = true }
webgpu_traits = { workspace = true }
webrender_api = { workspace = true }
wgpu-core = { workspace = true, optional = true }

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Messages send from the ScriptThread to the Constellation.
use std::collections::{HashMap, VecDeque};
use std::fmt;
@ -11,15 +13,19 @@ use base::id::{
MessagePortRouterId, PipelineId, ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
};
use canvas_traits::canvas::{CanvasId, CanvasMsg};
use constellation_traits::{LogEntry, TraversalDirection};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{
EmbedderMsg, MediaSessionEvent, TouchEventType, TouchSequenceId, ViewportDetails,
AnimationState, EmbedderMsg, MediaSessionEvent, TouchEventResult, ViewportDetails,
};
use euclid::default::Size2D as UntypedSize2D;
use http::{HeaderMap, Method};
use ipc_channel::Error as IpcError;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use net_traits::CoreResourceMsg;
use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBody};
use net_traits::storage_thread::StorageType;
use net_traits::{CoreResourceMsg, ReferrerPolicy, ResourceThreads};
use profile_traits::mem::MemoryReportResult;
use profile_traits::{mem, time as profile_time};
use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl};
use strum_macros::IntoStaticStr;
@ -27,12 +33,420 @@ use strum_macros::IntoStaticStr;
use webgpu_traits::{WebGPU, WebGPUAdapterResponse};
use webrender_api::ImageKey;
use crate::mem::MemoryReportResult;
use crate::{
AnimationState, AuxiliaryWebViewCreationRequest, BroadcastMsg, DocumentState,
IFrameLoadInfoWithData, LoadData, MessagePortMsg, NavigationHistoryBehavior, PortMessageTask,
StructuredSerializedData, WindowSizeType, WorkerGlobalScopeInit, WorkerScriptLoadOrigin,
use crate::message_port::{
BroadcastMsg, MessagePortMsg, PortMessageTask, StructuredSerializedData,
};
use crate::{LogEntry, TraversalDirection, WindowSizeType};
/// A Script to Constellation channel.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ScriptToConstellationChan {
/// Sender for communicating with constellation thread.
pub sender: IpcSender<(PipelineId, ScriptToConstellationMessage)>,
/// Used to identify the origin of the message.
pub pipeline_id: PipelineId,
}
impl ScriptToConstellationChan {
/// Send ScriptMsg and attach the pipeline_id to the message.
pub fn send(&self, msg: ScriptToConstellationMessage) -> Result<(), IpcError> {
self.sender.send((self.pipeline_id, msg))
}
}
/// The origin where a given load was initiated.
/// Useful for origin checks, for example before evaluation a JS URL.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum LoadOrigin {
/// A load originating in the constellation.
Constellation,
/// A load originating in webdriver.
WebDriver,
/// A load originating in script.
Script(ImmutableOrigin),
}
/// can be passed to `LoadUrl` to load a page with GET/POST
/// parameters or headers
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LoadData {
/// The origin where the load started.
pub load_origin: LoadOrigin,
/// The URL.
pub url: ServoUrl,
/// The creator pipeline id if this is an about:blank load.
pub creator_pipeline_id: Option<PipelineId>,
/// The method.
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
pub method: Method,
/// The headers.
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
pub headers: HeaderMap,
/// The data that will be used as the body of the request.
pub data: Option<RequestBody>,
/// The result of evaluating a javascript scheme url.
pub js_eval_result: Option<JsEvalResult>,
/// The referrer.
pub referrer: Referrer,
/// The referrer policy.
pub referrer_policy: ReferrerPolicy,
/// The source to use instead of a network response for a srcdoc document.
pub srcdoc: String,
/// The inherited context is Secure, None if not inherited
pub inherited_secure_context: Option<bool>,
/// The inherited policy for upgrading insecure requests; None if not inherited.
pub inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
/// Whether the page's ancestors have potentially trustworthy origin
pub has_trustworthy_ancestor_origin: bool,
/// Servo internal: if crash details are present, trigger a crash error page with these details.
pub crash: Option<String>,
}
/// The result of evaluating a javascript scheme url.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum JsEvalResult {
/// The js evaluation had a non-string result, 204 status code.
/// <https://html.spec.whatwg.org/multipage/#navigate> 12.11
NoContent,
/// The js evaluation had a string result.
Ok(Vec<u8>),
}
impl LoadData {
/// Create a new `LoadData` object.
#[allow(clippy::too_many_arguments)]
pub fn new(
load_origin: LoadOrigin,
url: ServoUrl,
creator_pipeline_id: Option<PipelineId>,
referrer: Referrer,
referrer_policy: ReferrerPolicy,
inherited_secure_context: Option<bool>,
inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
has_trustworthy_ancestor_origin: bool,
) -> LoadData {
LoadData {
load_origin,
url,
creator_pipeline_id,
method: Method::GET,
headers: HeaderMap::new(),
data: None,
js_eval_result: None,
referrer,
referrer_policy,
srcdoc: "".to_string(),
inherited_secure_context,
crash: None,
inherited_insecure_requests_policy,
has_trustworthy_ancestor_origin,
}
}
}
/// <https://html.spec.whatwg.org/multipage/#navigation-supporting-concepts:navigationhistorybehavior>
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub enum NavigationHistoryBehavior {
/// The default value, which will be converted very early in the navigate algorithm into "push"
/// or "replace". Usually it becomes "push", but under certain circumstances it becomes
/// "replace" instead.
#[default]
Auto,
/// A regular navigation which adds a new session history entry, and will clear the forward
/// session history.
Push,
/// A navigation that will replace the active session history entry.
Replace,
}
/// Entities required to spawn service workers
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ScopeThings {
/// script resource url
pub script_url: ServoUrl,
/// network load origin of the resource
pub worker_load_origin: WorkerScriptLoadOrigin,
/// base resources required to create worker global scopes
pub init: WorkerGlobalScopeInit,
/// the port to receive devtools message from
pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// service worker id
pub worker_id: WorkerId,
}
/// Message that gets passed to service worker scope on postMessage
#[derive(Debug, Deserialize, Serialize)]
pub struct DOMMessage {
/// The origin of the message
pub origin: ImmutableOrigin,
/// The payload of the message
pub data: StructuredSerializedData,
}
/// Channels to allow service worker manager to communicate with constellation and resource thread
#[derive(Deserialize, Serialize)]
pub struct SWManagerSenders {
/// Sender of messages to the constellation.
pub swmanager_sender: IpcSender<SWManagerMsg>,
/// Sender for communicating with resource thread.
pub resource_sender: IpcSender<CoreResourceMsg>,
/// Sender of messages to the manager.
pub own_sender: IpcSender<ServiceWorkerMsg>,
/// Receiver of messages from the constellation.
pub receiver: IpcReceiver<ServiceWorkerMsg>,
}
/// Messages sent to Service Worker Manager thread
#[derive(Debug, Deserialize, Serialize)]
pub enum ServiceWorkerMsg {
/// Timeout message sent by active service workers
Timeout(ServoUrl),
/// Message sent by constellation to forward to a running service worker
ForwardDOMMessage(DOMMessage, ServoUrl),
/// <https://w3c.github.io/ServiceWorker/#schedule-job-algorithm>
ScheduleJob(Job),
/// Exit the service worker manager
Exit,
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
/// <https://w3c.github.io/ServiceWorker/#dfn-job-type>
pub enum JobType {
/// <https://w3c.github.io/ServiceWorker/#register>
Register,
/// <https://w3c.github.io/ServiceWorker/#unregister-algorithm>
Unregister,
/// <https://w3c.github.io/ServiceWorker/#update-algorithm>
Update,
}
#[derive(Debug, Deserialize, Serialize)]
/// The kind of error the job promise should be rejected with.
pub enum JobError {
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
TypeError,
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
SecurityError,
}
#[derive(Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
/// Messages sent from Job algorithms steps running in the SW manager,
/// in order to resolve or reject the job promise.
pub enum JobResult {
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
RejectPromise(JobError),
/// <https://w3c.github.io/ServiceWorker/#resolve-job-promise>
ResolvePromise(Job, JobResultValue),
}
#[derive(Debug, Deserialize, Serialize)]
/// Jobs are resolved with the help of various values.
pub enum JobResultValue {
/// Data representing a serviceworker registration.
Registration {
/// The Id of the registration.
id: ServiceWorkerRegistrationId,
/// The installing worker, if any.
installing_worker: Option<ServiceWorkerId>,
/// The waiting worker, if any.
waiting_worker: Option<ServiceWorkerId>,
/// The active worker, if any.
active_worker: Option<ServiceWorkerId>,
},
}
#[derive(Debug, Deserialize, Serialize)]
/// <https://w3c.github.io/ServiceWorker/#dfn-job>
pub struct Job {
/// <https://w3c.github.io/ServiceWorker/#dfn-job-type>
pub job_type: JobType,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-scope-url>
pub scope_url: ServoUrl,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-script-url>
pub script_url: ServoUrl,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-client>
pub client: IpcSender<JobResult>,
/// <https://w3c.github.io/ServiceWorker/#job-referrer>
pub referrer: ServoUrl,
/// Various data needed to process job.
pub scope_things: Option<ScopeThings>,
}
impl Job {
/// <https://w3c.github.io/ServiceWorker/#create-job-algorithm>
pub fn create_job(
job_type: JobType,
scope_url: ServoUrl,
script_url: ServoUrl,
client: IpcSender<JobResult>,
referrer: ServoUrl,
scope_things: Option<ScopeThings>,
) -> Job {
Job {
job_type,
scope_url,
script_url,
client,
referrer,
scope_things,
}
}
}
impl PartialEq for Job {
/// Equality criteria as described in <https://w3c.github.io/ServiceWorker/#dfn-job-equivalent>
fn eq(&self, other: &Self) -> bool {
// TODO: match on job type, take worker type and `update_via_cache_mode` into account.
let same_job = self.job_type == other.job_type;
if same_job {
match self.job_type {
JobType::Register | JobType::Update => {
self.scope_url == other.scope_url && self.script_url == other.script_url
},
JobType::Unregister => self.scope_url == other.scope_url,
}
} else {
false
}
}
}
/// Messages outgoing from the Service Worker Manager thread to constellation
#[derive(Debug, Deserialize, Serialize)]
pub enum SWManagerMsg {
/// Placeholder to keep the enum,
/// as it will be needed when implementing
/// <https://github.com/servo/servo/issues/24660>
PostMessageToClient,
}
/// Used to determine if a script has any pending asynchronous activity.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum DocumentState {
/// The document has been loaded and is idle.
Idle,
/// The document is either loading or waiting on an event.
Pending,
}
/// This trait allows creating a `ServiceWorkerManager` without depending on the `script`
/// crate.
pub trait ServiceWorkerManagerFactory {
/// Create a `ServiceWorkerManager`.
fn create(sw_senders: SWManagerSenders, origin: ImmutableOrigin);
}
/// Whether the sandbox attribute is present for an iframe element
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum IFrameSandboxState {
/// Sandbox attribute is present
IFrameSandboxed,
/// Sandbox attribute is not present
IFrameUnsandboxed,
}
/// Specifies the information required to load an auxiliary browsing context.
#[derive(Debug, Deserialize, Serialize)]
pub struct AuxiliaryWebViewCreationRequest {
/// Load data containing the url to load
pub load_data: LoadData,
/// The webview that caused this request.
pub opener_webview_id: WebViewId,
/// The pipeline opener browsing context.
pub opener_pipeline_id: PipelineId,
/// Sender for the constellations response to our request.
pub response_sender: IpcSender<Option<AuxiliaryWebViewCreationResponse>>,
}
/// Constellations response to auxiliary browsing context creation requests.
#[derive(Debug, Deserialize, Serialize)]
pub struct AuxiliaryWebViewCreationResponse {
/// The new webview ID.
pub new_webview_id: WebViewId,
/// The new pipeline ID.
pub new_pipeline_id: PipelineId,
}
/// Specifies the information required to load an iframe.
#[derive(Debug, Deserialize, Serialize)]
pub struct IFrameLoadInfo {
/// Pipeline ID of the parent of this iframe
pub parent_pipeline_id: PipelineId,
/// The ID for this iframe's nested browsing context.
pub browsing_context_id: BrowsingContextId,
/// The ID for the top-level ancestor browsing context of this iframe's nested browsing context.
pub webview_id: WebViewId,
/// The new pipeline ID that the iframe has generated.
pub new_pipeline_id: PipelineId,
/// Whether this iframe should be considered private
pub is_private: bool,
/// Whether this iframe should be considered secure
pub inherited_secure_context: Option<bool>,
/// Whether this load should replace the current entry (reload). If true, the current
/// entry will be replaced instead of a new entry being added.
pub history_handling: NavigationHistoryBehavior,
}
/// Specifies the information required to load a URL in an iframe.
#[derive(Debug, Deserialize, Serialize)]
pub struct IFrameLoadInfoWithData {
/// The information required to load an iframe.
pub info: IFrameLoadInfo,
/// Load data containing the url to load
pub load_data: LoadData,
/// The old pipeline ID for this iframe, if a page was previously loaded.
pub old_pipeline_id: Option<PipelineId>,
/// Sandbox type of this iframe
pub sandbox: IFrameSandboxState,
/// The initial viewport size for this iframe.
pub viewport_details: ViewportDetails,
}
/// Resources required by workerglobalscopes
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkerGlobalScopeInit {
/// Chan to a resource thread
pub resource_threads: ResourceThreads,
/// Chan to the memory profiler
pub mem_profiler_chan: mem::ProfilerChan,
/// Chan to the time profiler
pub time_profiler_chan: profile_time::ProfilerChan,
/// To devtools sender
pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// From devtools sender
pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
/// Messages to send to constellation
pub script_to_constellation_chan: ScriptToConstellationChan,
/// The worker id
pub worker_id: WorkerId,
/// The pipeline id
pub pipeline_id: PipelineId,
/// The origin
pub origin: ImmutableOrigin,
/// The creation URL
pub creation_url: Option<ServoUrl>,
/// True if secure context
pub inherited_secure_context: Option<bool>,
}
/// Common entities representing a network load origin
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkerScriptLoadOrigin {
/// referrer url
pub referrer_url: Option<ServoUrl>,
/// the referrer policy which is used
pub referrer_policy: ReferrerPolicy,
/// the pipeline id of the entity requesting the load
pub pipeline_id: PipelineId,
}
/// An iframe sizing operation.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
@ -45,16 +459,7 @@ pub struct IFrameSizeMsg {
pub type_: WindowSizeType,
}
/// Whether the default action for a touch event was prevented by web content
#[derive(Debug, Deserialize, Serialize)]
pub enum TouchEventResult {
/// Allowed by web content
DefaultAllowed(TouchSequenceId, TouchEventType),
/// Prevented by web content
DefaultPrevented(TouchSequenceId, TouchEventType),
}
/// Messages sent from the `ScriptThread` to the `Constellation`.
/// Messages from the script to the constellation.
#[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum ScriptToConstellationMessage {
/// Request to complete the transfer of a set of ports to a router.
@ -225,165 +630,3 @@ impl fmt::Debug for ScriptToConstellationMessage {
write!(formatter, "ScriptMsg::{variant_string}")
}
}
/// Entities required to spawn service workers
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ScopeThings {
/// script resource url
pub script_url: ServoUrl,
/// network load origin of the resource
pub worker_load_origin: WorkerScriptLoadOrigin,
/// base resources required to create worker global scopes
pub init: WorkerGlobalScopeInit,
/// the port to receive devtools message from
pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// service worker id
pub worker_id: WorkerId,
}
/// Message that gets passed to service worker scope on postMessage
#[derive(Debug, Deserialize, Serialize)]
pub struct DOMMessage {
/// The origin of the message
pub origin: ImmutableOrigin,
/// The payload of the message
pub data: StructuredSerializedData,
}
/// Channels to allow service worker manager to communicate with constellation and resource thread
#[derive(Deserialize, Serialize)]
pub struct SWManagerSenders {
/// Sender of messages to the constellation.
pub swmanager_sender: IpcSender<SWManagerMsg>,
/// Sender for communicating with resource thread.
pub resource_sender: IpcSender<CoreResourceMsg>,
/// Sender of messages to the manager.
pub own_sender: IpcSender<ServiceWorkerMsg>,
/// Receiver of messages from the constellation.
pub receiver: IpcReceiver<ServiceWorkerMsg>,
}
/// Messages sent to Service Worker Manager thread
#[derive(Debug, Deserialize, Serialize)]
pub enum ServiceWorkerMsg {
/// Timeout message sent by active service workers
Timeout(ServoUrl),
/// Message sent by constellation to forward to a running service worker
ForwardDOMMessage(DOMMessage, ServoUrl),
/// <https://w3c.github.io/ServiceWorker/#schedule-job-algorithm>
ScheduleJob(Job),
/// Exit the service worker manager
Exit,
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
/// <https://w3c.github.io/ServiceWorker/#dfn-job-type>
pub enum JobType {
/// <https://w3c.github.io/ServiceWorker/#register>
Register,
/// <https://w3c.github.io/ServiceWorker/#unregister-algorithm>
Unregister,
/// <https://w3c.github.io/ServiceWorker/#update-algorithm>
Update,
}
#[derive(Debug, Deserialize, Serialize)]
/// The kind of error the job promise should be rejected with.
pub enum JobError {
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
TypeError,
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
SecurityError,
}
#[derive(Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
/// Messages sent from Job algorithms steps running in the SW manager,
/// in order to resolve or reject the job promise.
pub enum JobResult {
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
RejectPromise(JobError),
/// <https://w3c.github.io/ServiceWorker/#resolve-job-promise>
ResolvePromise(Job, JobResultValue),
}
#[derive(Debug, Deserialize, Serialize)]
/// Jobs are resolved with the help of various values.
pub enum JobResultValue {
/// Data representing a serviceworker registration.
Registration {
/// The Id of the registration.
id: ServiceWorkerRegistrationId,
/// The installing worker, if any.
installing_worker: Option<ServiceWorkerId>,
/// The waiting worker, if any.
waiting_worker: Option<ServiceWorkerId>,
/// The active worker, if any.
active_worker: Option<ServiceWorkerId>,
},
}
#[derive(Debug, Deserialize, Serialize)]
/// <https://w3c.github.io/ServiceWorker/#dfn-job>
pub struct Job {
/// <https://w3c.github.io/ServiceWorker/#dfn-job-type>
pub job_type: JobType,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-scope-url>
pub scope_url: ServoUrl,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-script-url>
pub script_url: ServoUrl,
/// <https://w3c.github.io/ServiceWorker/#dfn-job-client>
pub client: IpcSender<JobResult>,
/// <https://w3c.github.io/ServiceWorker/#job-referrer>
pub referrer: ServoUrl,
/// Various data needed to process job.
pub scope_things: Option<ScopeThings>,
}
impl Job {
/// <https://w3c.github.io/ServiceWorker/#create-job-algorithm>
pub fn create_job(
job_type: JobType,
scope_url: ServoUrl,
script_url: ServoUrl,
client: IpcSender<JobResult>,
referrer: ServoUrl,
scope_things: Option<ScopeThings>,
) -> Job {
Job {
job_type,
scope_url,
script_url,
client,
referrer,
scope_things,
}
}
}
impl PartialEq for Job {
/// Equality criteria as described in <https://w3c.github.io/ServiceWorker/#dfn-job-equivalent>
fn eq(&self, other: &Self) -> bool {
// TODO: match on job type, take worker type and `update_via_cache_mode` into account.
let same_job = self.job_type == other.job_type;
if same_job {
match self.job_type {
JobType::Register | JobType::Update => {
self.scope_url == other.scope_url && self.script_url == other.script_url
},
JobType::Unregister => self.scope_url == other.scope_url,
}
} else {
false
}
}
}
/// Messages outgoing from the Service Worker Manager thread to constellation
#[derive(Debug, Deserialize, Serialize)]
pub enum SWManagerMsg {
/// Placeholder to keep the enum,
/// as it will be needed when implementing
/// <https://github.com/servo/servo/issues/24660>
PostMessageToClient,
}

View file

@ -8,23 +8,27 @@
//! embedding/rendering layer all the way to script, thus it should have very minimal dependencies
//! on other parts of Servo.
mod from_script_message;
mod message_port;
use std::collections::HashMap;
use std::ffi::c_void;
use std::fmt;
use std::time::Duration;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{PipelineId, ScrollTreeNodeId, WebViewId};
use base::id::{PipelineId, WebViewId};
use bitflags::bitflags;
use embedder_traits::{
Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails, WebDriverCommandMsg,
CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
WebDriverCommandMsg,
};
use euclid::Vector2D;
pub use from_script_message::*;
use ipc_channel::ipc::IpcSender;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use message_port::*;
use serde::{Deserialize, Serialize};
use servo_url::ServoUrl;
use strum_macros::IntoStaticStr;
use webrender_api::ExternalScrollId;
@ -137,28 +141,6 @@ bitflags! {
}
}
/// The result of a hit test in the compositor.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CompositorHitTestResult {
/// The pipeline id of the resulting item.
pub pipeline_id: PipelineId,
/// The hit test point in the item's viewport.
pub point_in_viewport: euclid::default::Point2D<f32>,
/// The hit test point relative to the item itself.
pub point_relative_to_item: euclid::default::Point2D<f32>,
/// The node address of the hit test result.
pub node: UntrustedNodeAddress,
/// The cursor that should be used when hovering the item hit by the hit test.
pub cursor: Option<Cursor>,
/// The scroll tree node associated with this hit test item.
pub scroll_tree_node: ScrollTreeNodeId,
}
/// The scroll state of a stacking context.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ScrollState {
@ -168,43 +150,6 @@ pub struct ScrollState {
pub scroll_offset: Vector2D<f32, LayoutPixel>,
}
/// 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.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UntrustedNodeAddress(pub *const c_void);
malloc_size_of_is_0!(UntrustedNodeAddress);
#[allow(unsafe_code)]
unsafe impl Send for UntrustedNodeAddress {}
impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
fn from(o: style_traits::dom::OpaqueNode) -> Self {
UntrustedNodeAddress(o.0 as *const c_void)
}
}
impl Serialize for UntrustedNodeAddress {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
(self.0 as usize).serialize(s)
}
}
impl<'de> Deserialize<'de> for UntrustedNodeAddress {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
let value: usize = Deserialize::deserialize(d)?;
Ok(UntrustedNodeAddress::from_id(value))
}
}
impl UntrustedNodeAddress {
/// Creates an `UntrustedNodeAddress` from the given pointer address value.
#[inline]
pub fn from_id(id: usize) -> UntrustedNodeAddress {
UntrustedNodeAddress(id as *const c_void)
}
}
/// The direction of a history traversal
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum TraversalDirection {

View file

@ -0,0 +1,525 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! This module contains data structures used for message ports and serializing
//! DOM objects to send across them as per
//! <https://html.spec.whatwg.org/multipage/#serializable-objects>.
//! The implementations are here instead of in `script``, because these
//! types can be sent through the Constellation to other ScriptThreads,
//! and Constellation cannot depend directly on `script`.
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::path::PathBuf;
use base::id::{BlobId, DomPointId, MessagePortId};
use log::warn;
use malloc_size_of_derive::MallocSizeOf;
use net_traits::filemanager_thread::RelativePos;
use serde::{Deserialize, Serialize};
use servo_url::ImmutableOrigin;
use strum::{EnumIter, IntoEnumIterator};
use uuid::Uuid;
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
enum MessagePortState {
/// <https://html.spec.whatwg.org/multipage/#detached>
Detached,
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
/// The message-queue of this port is enabled,
/// the boolean represents awaiting completion of a transfer.
Enabled(bool),
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
/// The message-queue of this port is disabled,
/// the boolean represents awaiting completion of a transfer.
Disabled(bool),
}
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
/// The data and logic backing the DOM managed MessagePort.
pub struct MessagePortImpl {
/// The current state of the port.
state: MessagePortState,
/// <https://html.spec.whatwg.org/multipage/#entangle>
entangled_port: Option<MessagePortId>,
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
message_buffer: Option<VecDeque<PortMessageTask>>,
/// The UUID of this port.
message_port_id: MessagePortId,
}
impl MessagePortImpl {
/// Create a new messageport impl.
pub fn new(port_id: MessagePortId) -> MessagePortImpl {
MessagePortImpl {
state: MessagePortState::Disabled(false),
entangled_port: None,
message_buffer: None,
message_port_id: port_id,
}
}
/// Get the Id.
pub fn message_port_id(&self) -> &MessagePortId {
&self.message_port_id
}
/// Maybe get the Id of the entangled port.
pub fn entangled_port_id(&self) -> Option<MessagePortId> {
self.entangled_port
}
/// Entanged this port with another.
pub fn entangle(&mut self, other_id: MessagePortId) {
self.entangled_port = Some(other_id);
}
/// Is this port enabled?
pub fn enabled(&self) -> bool {
matches!(self.state, MessagePortState::Enabled(_))
}
/// Mark this port as having been shipped.
/// <https://html.spec.whatwg.org/multipage/#has-been-shipped>
pub fn set_has_been_shipped(&mut self) {
match self.state {
MessagePortState::Detached => {
panic!("Messageport set_has_been_shipped called in detached state")
},
MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(true),
MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(true),
}
}
/// Handle the completion of the transfer,
/// this is data received from the constellation.
pub fn complete_transfer(&mut self, mut tasks: VecDeque<PortMessageTask>) {
match self.state {
MessagePortState::Detached => return,
MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(false),
MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(false),
}
// Note: these are the tasks that were buffered while the transfer was ongoing,
// hence they need to execute first.
// The global will call `start` if we are enabled,
// which will add tasks on the event-loop to dispatch incoming messages.
match self.message_buffer {
Some(ref mut incoming_buffer) => {
while let Some(task) = tasks.pop_back() {
incoming_buffer.push_front(task);
}
},
None => self.message_buffer = Some(tasks),
}
}
/// A message was received from our entangled port,
/// returns an optional task to be dispatched.
pub fn handle_incoming(&mut self, task: PortMessageTask) -> Option<PortMessageTask> {
let should_dispatch = match self.state {
MessagePortState::Detached => return None,
MessagePortState::Enabled(in_transfer) => !in_transfer,
MessagePortState::Disabled(_) => false,
};
if should_dispatch {
Some(task)
} else {
match self.message_buffer {
Some(ref mut buffer) => {
buffer.push_back(task);
},
None => {
let mut queue = VecDeque::new();
queue.push_back(task);
self.message_buffer = Some(queue);
},
}
None
}
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
/// returns an optional queue of tasks that were buffered while the port was disabled.
pub fn start(&mut self) -> Option<VecDeque<PortMessageTask>> {
match self.state {
MessagePortState::Detached => return None,
MessagePortState::Enabled(_) => {},
MessagePortState::Disabled(in_transfer) => {
self.state = MessagePortState::Enabled(in_transfer);
},
}
if let MessagePortState::Enabled(true) = self.state {
return None;
}
self.message_buffer.take()
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
pub fn close(&mut self) {
// Step 1
self.state = MessagePortState::Detached;
}
}
/// A data-holder for serialized data and transferred objects.
/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)]
pub struct StructuredSerializedData {
/// Data serialized by SpiderMonkey.
pub serialized: Vec<u8>,
/// Serialized in a structured callback,
pub blobs: Option<HashMap<BlobId, BlobImpl>>,
/// Serialized point objects.
pub points: Option<HashMap<DomPointId, DomPoint>>,
/// Transferred objects.
pub ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
}
pub(crate) trait BroadcastClone
where
Self: Sized,
{
/// The ID type that uniquely identify each value.
type Id: Eq + std::hash::Hash + Copy;
/// Clone this value so that it can be reused with a broadcast channel.
/// Only return None if cloning is impossible.
fn clone_for_broadcast(&self) -> Option<Self>;
/// The field from which to clone values.
fn source(data: &StructuredSerializedData) -> &Option<HashMap<Self::Id, Self>>;
/// The field into which to place cloned values.
fn destination(data: &mut StructuredSerializedData) -> &mut Option<HashMap<Self::Id, Self>>;
}
/// All the DOM interfaces that can be serialized.
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum Serializable {
/// The `Blob` interface.
Blob,
/// The `DOMPoint` interface.
DomPoint,
/// The `DOMPointReadOnly` interface.
DomPointReadOnly,
}
impl Serializable {
fn clone_values(&self) -> fn(&StructuredSerializedData, &mut StructuredSerializedData) {
match self {
Serializable::Blob => StructuredSerializedData::clone_all_of_type::<BlobImpl>,
Serializable::DomPointReadOnly => {
StructuredSerializedData::clone_all_of_type::<DomPoint>
},
Serializable::DomPoint => StructuredSerializedData::clone_all_of_type::<DomPoint>,
}
}
}
/// All the DOM interfaces that can be transferred.
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum Transferrable {
/// The `MessagePort` interface.
MessagePort,
}
impl StructuredSerializedData {
fn is_empty(&self, val: Transferrable) -> bool {
fn is_field_empty<K, V>(field: &Option<HashMap<K, V>>) -> bool {
field.as_ref().is_some_and(|h| h.is_empty())
}
match val {
Transferrable::MessagePort => is_field_empty(&self.ports),
}
}
/// Clone all values of the same type stored in this StructuredSerializedData
/// into another instance.
fn clone_all_of_type<T: BroadcastClone>(&self, cloned: &mut StructuredSerializedData) {
let existing = T::source(self);
let Some(existing) = existing else { return };
let mut clones = HashMap::with_capacity(existing.len());
for (original_id, obj) in existing.iter() {
if let Some(clone) = obj.clone_for_broadcast() {
clones.insert(*original_id, clone);
}
}
*T::destination(cloned) = Some(clones);
}
/// Clone the serialized data for use with broadcast-channels.
pub fn clone_for_broadcast(&self) -> StructuredSerializedData {
for transferrable in Transferrable::iter() {
if !self.is_empty(transferrable) {
// Not panicking only because this is called from the constellation.
warn!(
"Attempt to broadcast structured serialized data including {:?} (should never happen).",
transferrable,
);
}
}
let serialized = self.serialized.clone();
let mut cloned = StructuredSerializedData {
serialized,
..Default::default()
};
for serializable in Serializable::iter() {
let clone_impl = serializable.clone_values();
clone_impl(self, &mut cloned);
}
cloned
}
}
/// A task on the <https://html.spec.whatwg.org/multipage/#port-message-queue>
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct PortMessageTask {
/// The origin of this task.
pub origin: ImmutableOrigin,
/// A data-holder for serialized data and transferred objects.
pub data: StructuredSerializedData,
}
/// Messages for communication between the constellation and a global managing ports.
#[derive(Debug, Deserialize, Serialize)]
pub enum MessagePortMsg {
/// Complete the transfer for a batch of ports.
CompleteTransfer(HashMap<MessagePortId, VecDeque<PortMessageTask>>),
/// Complete the transfer of a single port,
/// whose transfer was pending because it had been requested
/// while a previous failed transfer was being rolled-back.
CompletePendingTransfer(MessagePortId, VecDeque<PortMessageTask>),
/// Remove a port, the entangled one doesn't exists anymore.
RemoveMessagePort(MessagePortId),
/// Handle a new port-message-task.
NewTask(MessagePortId, PortMessageTask),
}
/// Message for communication between the constellation and a global managing broadcast channels.
#[derive(Debug, Deserialize, Serialize)]
pub struct BroadcastMsg {
/// The origin of this message.
pub origin: ImmutableOrigin,
/// The name of the channel.
pub channel_name: String,
/// A data-holder for serialized data.
pub data: StructuredSerializedData,
}
impl Clone for BroadcastMsg {
fn clone(&self) -> BroadcastMsg {
BroadcastMsg {
data: self.data.clone_for_broadcast(),
origin: self.origin.clone(),
channel_name: self.channel_name.clone(),
}
}
}
/// File-based blob
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FileBlob {
#[ignore_malloc_size_of = "Uuid are hard(not really)"]
id: Uuid,
#[ignore_malloc_size_of = "PathBuf are hard"]
name: Option<PathBuf>,
cache: RefCell<Option<Vec<u8>>>,
size: u64,
}
impl FileBlob {
/// Create a new file blob.
pub fn new(id: Uuid, name: Option<PathBuf>, cache: Option<Vec<u8>>, size: u64) -> FileBlob {
FileBlob {
id,
name,
cache: RefCell::new(cache),
size,
}
}
/// Get the size of the file.
pub fn get_size(&self) -> u64 {
self.size
}
/// Get the cached file data, if any.
pub fn get_cache(&self) -> Option<Vec<u8>> {
self.cache.borrow().clone()
}
/// Cache data.
pub fn cache_bytes(&self, bytes: Vec<u8>) {
*self.cache.borrow_mut() = Some(bytes);
}
/// Get the file id.
pub fn get_id(&self) -> Uuid {
self.id
}
}
impl BroadcastClone for BlobImpl {
type Id = BlobId;
fn source(
data: &StructuredSerializedData,
) -> &Option<std::collections::HashMap<Self::Id, Self>> {
&data.blobs
}
fn destination(
data: &mut StructuredSerializedData,
) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
&mut data.blobs
}
fn clone_for_broadcast(&self) -> Option<Self> {
let type_string = self.type_string();
if let BlobData::Memory(bytes) = self.blob_data() {
let blob_clone = BlobImpl::new_from_bytes(bytes.clone(), type_string);
// Note: we insert the blob at the original id,
// otherwise this will not match the storage key as serialized by SM in `serialized`.
// The clone has it's own new Id however.
return Some(blob_clone);
} else {
// Not panicking only because this is called from the constellation.
log::warn!("Serialized blob not in memory format(should never happen).");
}
None
}
}
/// The data backing a DOM Blob.
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct BlobImpl {
/// UUID of the blob.
blob_id: BlobId,
/// Content-type string
type_string: String,
/// Blob data-type.
blob_data: BlobData,
/// Sliced blobs referring to this one.
slices: Vec<BlobId>,
}
/// Different backends of Blob
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub enum BlobData {
/// File-based blob, whose content lives in the net process
File(FileBlob),
/// Memory-based blob, whose content lives in the script process
Memory(Vec<u8>),
/// Sliced blob, including parent blob-id and
/// relative positions of current slicing range,
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
/// either File-based or Memory-based
Sliced(BlobId, RelativePos),
}
impl BlobImpl {
/// Construct memory-backed BlobImpl
pub fn new_from_bytes(bytes: Vec<u8>, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::Memory(bytes);
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Construct file-backed BlobImpl from File ID
pub fn new_from_file(file_id: Uuid, name: PathBuf, size: u64, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::File(FileBlob {
id: file_id,
name: Some(name),
cache: RefCell::new(None),
size,
});
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Construct a BlobImpl from a slice of a parent.
pub fn new_sliced(rel_pos: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::Sliced(parent, rel_pos);
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Get a clone of the blob-id
pub fn blob_id(&self) -> BlobId {
self.blob_id
}
/// Get a clone of the type-string
pub fn type_string(&self) -> String {
self.type_string.clone()
}
/// Get a mutable ref to the data
pub fn blob_data(&self) -> &BlobData {
&self.blob_data
}
/// Get a mutable ref to the data
pub fn blob_data_mut(&mut self) -> &mut BlobData {
&mut self.blob_data
}
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
/// A serializable version of the DOMPoint/DOMPointReadOnly interface.
pub struct DomPoint {
/// The x coordinate.
pub x: f64,
/// The y coordinate.
pub y: f64,
/// The z coordinate.
pub z: f64,
/// The w coordinate.
pub w: f64,
}
impl BroadcastClone for DomPoint {
type Id = DomPointId;
fn source(
data: &StructuredSerializedData,
) -> &Option<std::collections::HashMap<Self::Id, Self>> {
&data.points
}
fn destination(
data: &mut StructuredSerializedData,
) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
&mut data.points
}
fn clone_for_broadcast(&self) -> Option<Self> {
Some(self.clone())
}
}

View file

@ -13,21 +13,23 @@ pub mod resources;
pub mod user_content_manager;
mod webdriver;
use std::ffi::c_void;
use std::fmt::{Debug, Error, Formatter};
use std::path::PathBuf;
use std::sync::Arc;
use base::id::{PipelineId, WebViewId};
use base::id::{PipelineId, ScrollTreeNodeId, WebViewId};
use crossbeam_channel::Sender;
use euclid::{Scale, Size2D};
use http::{HeaderMap, Method, StatusCode};
use ipc_channel::ipc::IpcSender;
pub use keyboard_types::{KeyboardEvent, Modifiers};
use log::warn;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use num_derive::FromPrimitive;
use pixels::Image;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_url::ServoUrl;
use strum_macros::IntoStaticStr;
use style_traits::CSSPixel;
@ -705,3 +707,85 @@ impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
Self::Option(value)
}
}
/// 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.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UntrustedNodeAddress(pub *const c_void);
malloc_size_of_is_0!(UntrustedNodeAddress);
#[allow(unsafe_code)]
unsafe impl Send for UntrustedNodeAddress {}
impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
fn from(o: style_traits::dom::OpaqueNode) -> Self {
UntrustedNodeAddress(o.0 as *const c_void)
}
}
impl Serialize for UntrustedNodeAddress {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
(self.0 as usize).serialize(s)
}
}
impl<'de> Deserialize<'de> for UntrustedNodeAddress {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
let value: usize = Deserialize::deserialize(d)?;
Ok(UntrustedNodeAddress::from_id(value))
}
}
impl UntrustedNodeAddress {
/// Creates an `UntrustedNodeAddress` from the given pointer address value.
#[inline]
pub fn from_id(id: usize) -> UntrustedNodeAddress {
UntrustedNodeAddress(id as *const c_void)
}
}
/// The result of a hit test in the compositor.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CompositorHitTestResult {
/// The pipeline id of the resulting item.
pub pipeline_id: PipelineId,
/// The hit test point in the item's viewport.
pub point_in_viewport: euclid::default::Point2D<f32>,
/// The hit test point relative to the item itself.
pub point_relative_to_item: euclid::default::Point2D<f32>,
/// The node address of the hit test result.
pub node: UntrustedNodeAddress,
/// The cursor that should be used when hovering the item hit by the hit test.
pub cursor: Option<Cursor>,
/// The scroll tree node associated with this hit test item.
pub scroll_tree_node: ScrollTreeNodeId,
}
/// Whether the default action for a touch event was prevented by web content
#[derive(Debug, Deserialize, Serialize)]
pub enum TouchEventResult {
/// Allowed by web content
DefaultAllowed(TouchSequenceId, TouchEventType),
/// Prevented by web content
DefaultPrevented(TouchSequenceId, TouchEventType),
}
/// For a given pipeline, whether any animations are currently running
/// and any animation callbacks are queued
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum AnimationState {
/// Animations are active but no callbacks are queued
AnimationsPresent,
/// Animations are active and callbacks are queued
AnimationCallbacksPresent,
/// No animations are active and no callbacks are queued
NoAnimationsPresent,
/// No animations are active but callbacks are queued
NoAnimationCallbacksPresent,
}

View file

@ -13,26 +13,21 @@ path = "lib.rs"
[features]
bluetooth = ["bluetooth_traits"]
webgpu = ["wgpu-core"]
webgpu = ["webgpu_traits"]
[dependencies]
background_hang_monitor_api = { workspace = true }
base = { workspace = true }
bitflags = { workspace = true }
bluetooth_traits = { workspace = true, optional = true }
canvas_traits = { workspace = true }
constellation_traits = { workspace = true }
cookie = { workspace = true }
crossbeam-channel = { workspace = true }
devtools_traits = { workspace = true }
embedder_traits = { workspace = true }
euclid = { workspace = true }
http = { workspace = true }
hyper_serde = { workspace = true }
ipc-channel = { workspace = true }
keyboard-types = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
media = { path = "../../media" }
@ -45,10 +40,7 @@ strum = { workspace = true, features = ["derive"] }
strum_macros = { workspace = true }
stylo_atoms = { workspace = true }
stylo_traits = { workspace = true }
uuid = { workspace = true }
webdriver = { workspace = true }
webgpu_traits = { workspace = true }
webgpu_traits = { workspace = true, optional = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
webxr-api = { workspace = true, features = ["ipc"] }
wgpu-core = { workspace = true, optional = true }

View file

@ -9,48 +9,38 @@
#![deny(missing_docs)]
#![deny(unsafe_code)]
mod script_msg;
pub mod serializable;
pub mod transferable;
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::sync::Arc;
use background_hang_monitor_api::BackgroundHangMonitorRegister;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{
BlobId, BrowsingContextId, DomPointId, HistoryStateId, MessagePortId, PipelineId,
PipelineNamespaceId, WebViewId,
};
use base::id::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId, WebViewId};
#[cfg(feature = "bluetooth")]
use bluetooth_traits::BluetoothRequest;
use canvas_traits::webgl::WebGLPipeline;
use constellation_traits::{
AnimationTickType, CompositorHitTestResult, ScrollState, WindowSizeType,
AnimationTickType, LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, ScrollState,
StructuredSerializedData, WindowSizeType,
};
use crossbeam_channel::{RecvTimeoutError, Sender};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::input_events::InputEvent;
use devtools_traits::ScriptToDevtoolsControlMsg;
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand};
use embedder_traits::{
CompositorHitTestResult, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
WebDriverScriptCommand,
};
use euclid::{Rect, Scale, Size2D, UnknownUnit};
use http::{HeaderMap, Method};
use ipc_channel::Error as IpcError;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use keyboard_types::Modifiers;
use log::warn;
use malloc_size_of_derive::MallocSizeOf;
use media::WindowGLContext;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBody};
use net_traits::storage_thread::StorageType;
use net_traits::{ReferrerPolicy, ResourceThreads};
use pixels::PixelFormat;
use profile_traits::{mem, time as profile_time};
use profile_traits::mem;
use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl};
use strum::{EnumIter, IntoEnumIterator};
use strum_macros::IntoStaticStr;
use style_traits::{CSSPixel, SpeculativePainter};
use stylo_atoms::Atom;
@ -60,111 +50,6 @@ use webrender_api::units::DevicePixel;
use webrender_api::{DocumentId, ImageKey};
use webrender_traits::CrossProcessCompositorApi;
pub use crate::script_msg::{
DOMMessage, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, SWManagerMsg,
SWManagerSenders, ScopeThings, ScriptToConstellationMessage, ServiceWorkerMsg,
TouchEventResult,
};
use crate::serializable::{BlobImpl, DomPoint};
use crate::transferable::MessagePortImpl;
/// The origin where a given load was initiated.
/// Useful for origin checks, for example before evaluation a JS URL.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum LoadOrigin {
/// A load originating in the constellation.
Constellation,
/// A load originating in webdriver.
WebDriver,
/// A load originating in script.
Script(ImmutableOrigin),
}
/// can be passed to `LoadUrl` to load a page with GET/POST
/// parameters or headers
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LoadData {
/// The origin where the load started.
pub load_origin: LoadOrigin,
/// The URL.
pub url: ServoUrl,
/// The creator pipeline id if this is an about:blank load.
pub creator_pipeline_id: Option<PipelineId>,
/// The method.
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
pub method: Method,
/// The headers.
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
pub headers: HeaderMap,
/// The data that will be used as the body of the request.
pub data: Option<RequestBody>,
/// The result of evaluating a javascript scheme url.
pub js_eval_result: Option<JsEvalResult>,
/// The referrer.
pub referrer: Referrer,
/// The referrer policy.
pub referrer_policy: ReferrerPolicy,
/// The source to use instead of a network response for a srcdoc document.
pub srcdoc: String,
/// The inherited context is Secure, None if not inherited
pub inherited_secure_context: Option<bool>,
/// The inherited policy for upgrading insecure requests; None if not inherited.
pub inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
/// Whether the page's ancestors have potentially trustworthy origin
pub has_trustworthy_ancestor_origin: bool,
/// Servo internal: if crash details are present, trigger a crash error page with these details.
pub crash: Option<String>,
}
/// The result of evaluating a javascript scheme url.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum JsEvalResult {
/// The js evaluation had a non-string result, 204 status code.
/// <https://html.spec.whatwg.org/multipage/#navigate> 12.11
NoContent,
/// The js evaluation had a string result.
Ok(Vec<u8>),
}
impl LoadData {
/// Create a new `LoadData` object.
#[allow(clippy::too_many_arguments)]
pub fn new(
load_origin: LoadOrigin,
url: ServoUrl,
creator_pipeline_id: Option<PipelineId>,
referrer: Referrer,
referrer_policy: ReferrerPolicy,
inherited_secure_context: Option<bool>,
inherited_insecure_requests_policy: Option<InsecureRequestsPolicy>,
has_trustworthy_ancestor_origin: bool,
) -> LoadData {
LoadData {
load_origin,
url,
creator_pipeline_id,
method: Method::GET,
headers: HeaderMap::new(),
data: None,
js_eval_result: None,
referrer,
referrer_policy,
srcdoc: "".to_string(),
inherited_secure_context,
crash: None,
inherited_insecure_requests_policy,
has_trustworthy_ancestor_origin,
}
}
}
/// The initial data required to create a new layout attached to an existing script thread.
#[derive(Debug, Deserialize, Serialize)]
pub struct NewLayoutInfo {
@ -194,21 +79,6 @@ pub enum DiscardBrowsingContext {
No,
}
/// <https://html.spec.whatwg.org/multipage/#navigation-supporting-concepts:navigationhistorybehavior>
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub enum NavigationHistoryBehavior {
/// The default value, which will be converted very early in the navigate algorithm into "push"
/// or "replace". Usually it becomes "push", but under certain circumstances it becomes
/// "replace" instead.
#[default]
Auto,
/// A regular navigation which adds a new session history entry, and will clear the forward
/// session history.
Push,
/// A navigation that will replace the active session history entry.
Replace,
}
/// Is a document fully active, active or inactive?
/// A document is active if it is the current active document in its session history,
/// it is fuly active if it is active and all of its ancestors are active,
@ -385,20 +255,6 @@ pub enum DocumentState {
Pending,
}
/// For a given pipeline, whether any animations are currently running
/// and any animation callbacks are queued
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum AnimationState {
/// Animations are active but no callbacks are queued
AnimationsPresent,
/// Animations are active and callbacks are queued
AnimationCallbacksPresent,
/// No animations are active and no callbacks are queued
NoAnimationsPresent,
/// No animations are active but callbacks are queued
NoAnimationCallbacksPresent,
}
/// Input events from the embedder that are sent via the `Constellation`` to the `ScriptThread`.
#[derive(Debug, Deserialize, Serialize)]
pub struct ConstellationInputEvent {
@ -472,117 +328,6 @@ pub struct InitialScriptState {
pub user_content_manager: UserContentManager,
}
/// This trait allows creating a `ServiceWorkerManager` without depending on the `script`
/// crate.
pub trait ServiceWorkerManagerFactory {
/// Create a `ServiceWorkerManager`.
fn create(sw_senders: SWManagerSenders, origin: ImmutableOrigin);
}
/// Whether the sandbox attribute is present for an iframe element
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum IFrameSandboxState {
/// Sandbox attribute is present
IFrameSandboxed,
/// Sandbox attribute is not present
IFrameUnsandboxed,
}
/// Specifies the information required to load an auxiliary browsing context.
#[derive(Debug, Deserialize, Serialize)]
pub struct AuxiliaryWebViewCreationRequest {
/// Load data containing the url to load
pub load_data: LoadData,
/// The webview that caused this request.
pub opener_webview_id: WebViewId,
/// The pipeline opener browsing context.
pub opener_pipeline_id: PipelineId,
/// Sender for the constellations response to our request.
pub response_sender: IpcSender<Option<AuxiliaryWebViewCreationResponse>>,
}
/// Constellations response to auxiliary browsing context creation requests.
#[derive(Debug, Deserialize, Serialize)]
pub struct AuxiliaryWebViewCreationResponse {
/// The new webview ID.
pub new_webview_id: WebViewId,
/// The new pipeline ID.
pub new_pipeline_id: PipelineId,
}
/// Specifies the information required to load an iframe.
#[derive(Debug, Deserialize, Serialize)]
pub struct IFrameLoadInfo {
/// Pipeline ID of the parent of this iframe
pub parent_pipeline_id: PipelineId,
/// The ID for this iframe's nested browsing context.
pub browsing_context_id: BrowsingContextId,
/// The ID for the top-level ancestor browsing context of this iframe's nested browsing context.
pub webview_id: WebViewId,
/// The new pipeline ID that the iframe has generated.
pub new_pipeline_id: PipelineId,
/// Whether this iframe should be considered private
pub is_private: bool,
/// Whether this iframe should be considered secure
pub inherited_secure_context: Option<bool>,
/// Whether this load should replace the current entry (reload). If true, the current
/// entry will be replaced instead of a new entry being added.
pub history_handling: NavigationHistoryBehavior,
}
/// Specifies the information required to load a URL in an iframe.
#[derive(Debug, Deserialize, Serialize)]
pub struct IFrameLoadInfoWithData {
/// The information required to load an iframe.
pub info: IFrameLoadInfo,
/// Load data containing the url to load
pub load_data: LoadData,
/// The old pipeline ID for this iframe, if a page was previously loaded.
pub old_pipeline_id: Option<PipelineId>,
/// Sandbox type of this iframe
pub sandbox: IFrameSandboxState,
/// The initial viewport size for this iframe.
pub viewport_details: ViewportDetails,
}
/// Resources required by workerglobalscopes
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkerGlobalScopeInit {
/// Chan to a resource thread
pub resource_threads: ResourceThreads,
/// Chan to the memory profiler
pub mem_profiler_chan: mem::ProfilerChan,
/// Chan to the time profiler
pub time_profiler_chan: profile_time::ProfilerChan,
/// To devtools sender
pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// From devtools sender
pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
/// Messages to send to constellation
pub script_to_constellation_chan: ScriptToConstellationChan,
/// The worker id
pub worker_id: WorkerId,
/// The pipeline id
pub pipeline_id: PipelineId,
/// The origin
pub origin: ImmutableOrigin,
/// The creation URL
pub creation_url: Option<ServoUrl>,
/// True if secure context
pub inherited_secure_context: Option<bool>,
}
/// Common entities representing a network load origin
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkerScriptLoadOrigin {
/// referrer url
pub referrer_url: Option<ServoUrl>,
/// the referrer policy which is used
pub referrer_policy: ReferrerPolicy,
/// the pipeline id of the entity requesting the load
pub pipeline_id: PipelineId,
}
/// Errors from executing a paint worklet
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum PaintWorkletError {
@ -634,177 +379,3 @@ pub struct DrawAPaintImageResult {
/// Drawing the image might have requested loading some image URLs.
pub missing_image_urls: Vec<ServoUrl>,
}
/// A Script to Constellation channel.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ScriptToConstellationChan {
/// Sender for communicating with constellation thread.
pub sender: IpcSender<(PipelineId, ScriptToConstellationMessage)>,
/// Used to identify the origin of the message.
pub pipeline_id: PipelineId,
}
impl ScriptToConstellationChan {
/// Send ScriptMsg and attach the pipeline_id to the message.
pub fn send(&self, msg: ScriptToConstellationMessage) -> Result<(), IpcError> {
self.sender.send((self.pipeline_id, msg))
}
}
/// A data-holder for serialized data and transferred objects.
/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)]
pub struct StructuredSerializedData {
/// Data serialized by SpiderMonkey.
pub serialized: Vec<u8>,
/// Serialized in a structured callback,
pub blobs: Option<HashMap<BlobId, BlobImpl>>,
/// Serialized point objects.
pub points: Option<HashMap<DomPointId, DomPoint>>,
/// Transferred objects.
pub ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
}
pub(crate) trait BroadcastClone
where
Self: Sized,
{
/// The ID type that uniquely identify each value.
type Id: Eq + std::hash::Hash + Copy;
/// Clone this value so that it can be reused with a broadcast channel.
/// Only return None if cloning is impossible.
fn clone_for_broadcast(&self) -> Option<Self>;
/// The field from which to clone values.
fn source(data: &StructuredSerializedData) -> &Option<HashMap<Self::Id, Self>>;
/// The field into which to place cloned values.
fn destination(data: &mut StructuredSerializedData) -> &mut Option<HashMap<Self::Id, Self>>;
}
/// All the DOM interfaces that can be serialized.
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum Serializable {
/// The `Blob` interface.
Blob,
/// The `DOMPoint` interface.
DomPoint,
/// The `DOMPointReadOnly` interface.
DomPointReadOnly,
}
impl Serializable {
fn clone_values(&self) -> fn(&StructuredSerializedData, &mut StructuredSerializedData) {
match self {
Serializable::Blob => StructuredSerializedData::clone_all_of_type::<BlobImpl>,
Serializable::DomPointReadOnly => {
StructuredSerializedData::clone_all_of_type::<DomPoint>
},
Serializable::DomPoint => StructuredSerializedData::clone_all_of_type::<DomPoint>,
}
}
}
/// All the DOM interfaces that can be transferred.
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum Transferrable {
/// The `MessagePort` interface.
MessagePort,
}
impl StructuredSerializedData {
fn is_empty(&self, val: Transferrable) -> bool {
fn is_field_empty<K, V>(field: &Option<HashMap<K, V>>) -> bool {
field.as_ref().is_some_and(|h| h.is_empty())
}
match val {
Transferrable::MessagePort => is_field_empty(&self.ports),
}
}
/// Clone all values of the same type stored in this StructuredSerializedData
/// into another instance.
fn clone_all_of_type<T: BroadcastClone>(&self, cloned: &mut StructuredSerializedData) {
let existing = T::source(self);
let Some(existing) = existing else { return };
let mut clones = HashMap::with_capacity(existing.len());
for (original_id, obj) in existing.iter() {
if let Some(clone) = obj.clone_for_broadcast() {
clones.insert(*original_id, clone);
}
}
*T::destination(cloned) = Some(clones);
}
/// Clone the serialized data for use with broadcast-channels.
pub fn clone_for_broadcast(&self) -> StructuredSerializedData {
for transferrable in Transferrable::iter() {
if !self.is_empty(transferrable) {
// Not panicking only because this is called from the constellation.
warn!(
"Attempt to broadcast structured serialized data including {:?} (should never happen).",
transferrable,
);
}
}
let serialized = self.serialized.clone();
let mut cloned = StructuredSerializedData {
serialized,
..Default::default()
};
for serializable in Serializable::iter() {
let clone_impl = serializable.clone_values();
clone_impl(self, &mut cloned);
}
cloned
}
}
/// A task on the <https://html.spec.whatwg.org/multipage/#port-message-queue>
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct PortMessageTask {
/// The origin of this task.
pub origin: ImmutableOrigin,
/// A data-holder for serialized data and transferred objects.
pub data: StructuredSerializedData,
}
/// Messages for communication between the constellation and a global managing ports.
#[derive(Debug, Deserialize, Serialize)]
pub enum MessagePortMsg {
/// Complete the transfer for a batch of ports.
CompleteTransfer(HashMap<MessagePortId, VecDeque<PortMessageTask>>),
/// Complete the transfer of a single port,
/// whose transfer was pending because it had been requested
/// while a previous failed transfer was being rolled-back.
CompletePendingTransfer(MessagePortId, VecDeque<PortMessageTask>),
/// Remove a port, the entangled one doesn't exists anymore.
RemoveMessagePort(MessagePortId),
/// Handle a new port-message-task.
NewTask(MessagePortId, PortMessageTask),
}
/// Message for communication between the constellation and a global managing broadcast channels.
#[derive(Debug, Deserialize, Serialize)]
pub struct BroadcastMsg {
/// The origin of this message.
pub origin: ImmutableOrigin,
/// The name of the channel.
pub channel_name: String,
/// A data-holder for serialized data.
pub data: StructuredSerializedData,
}
impl Clone for BroadcastMsg {
fn clone(&self) -> BroadcastMsg {
BroadcastMsg {
data: self.data.clone_for_broadcast(),
origin: self.origin.clone(),
channel_name: self.channel_name.clone(),
}
}
}

View file

@ -1,217 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! This module contains implementations in script that are serializable,
//! as per <https://html.spec.whatwg.org/multipage/#serializable-objects>.
//! The implementations are here instead of in script
//! so that the other modules involved in the serialization don't have
//! to depend on script.
use std::cell::RefCell;
use std::path::PathBuf;
use base::id::{BlobId, DomPointId};
use malloc_size_of_derive::MallocSizeOf;
use net_traits::filemanager_thread::RelativePos;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// File-based blob
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FileBlob {
#[ignore_malloc_size_of = "Uuid are hard(not really)"]
id: Uuid,
#[ignore_malloc_size_of = "PathBuf are hard"]
name: Option<PathBuf>,
cache: RefCell<Option<Vec<u8>>>,
size: u64,
}
impl FileBlob {
/// Create a new file blob.
pub fn new(id: Uuid, name: Option<PathBuf>, cache: Option<Vec<u8>>, size: u64) -> FileBlob {
FileBlob {
id,
name,
cache: RefCell::new(cache),
size,
}
}
/// Get the size of the file.
pub fn get_size(&self) -> u64 {
self.size
}
/// Get the cached file data, if any.
pub fn get_cache(&self) -> Option<Vec<u8>> {
self.cache.borrow().clone()
}
/// Cache data.
pub fn cache_bytes(&self, bytes: Vec<u8>) {
*self.cache.borrow_mut() = Some(bytes);
}
/// Get the file id.
pub fn get_id(&self) -> Uuid {
self.id
}
}
impl crate::BroadcastClone for BlobImpl {
type Id = BlobId;
fn source(
data: &crate::StructuredSerializedData,
) -> &Option<std::collections::HashMap<Self::Id, Self>> {
&data.blobs
}
fn destination(
data: &mut crate::StructuredSerializedData,
) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
&mut data.blobs
}
fn clone_for_broadcast(&self) -> Option<Self> {
let type_string = self.type_string();
if let BlobData::Memory(bytes) = self.blob_data() {
let blob_clone = BlobImpl::new_from_bytes(bytes.clone(), type_string);
// Note: we insert the blob at the original id,
// otherwise this will not match the storage key as serialized by SM in `serialized`.
// The clone has it's own new Id however.
return Some(blob_clone);
} else {
// Not panicking only because this is called from the constellation.
log::warn!("Serialized blob not in memory format(should never happen).");
}
None
}
}
/// The data backing a DOM Blob.
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct BlobImpl {
/// UUID of the blob.
blob_id: BlobId,
/// Content-type string
type_string: String,
/// Blob data-type.
blob_data: BlobData,
/// Sliced blobs referring to this one.
slices: Vec<BlobId>,
}
/// Different backends of Blob
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub enum BlobData {
/// File-based blob, whose content lives in the net process
File(FileBlob),
/// Memory-based blob, whose content lives in the script process
Memory(Vec<u8>),
/// Sliced blob, including parent blob-id and
/// relative positions of current slicing range,
/// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
/// either File-based or Memory-based
Sliced(BlobId, RelativePos),
}
impl BlobImpl {
/// Construct memory-backed BlobImpl
pub fn new_from_bytes(bytes: Vec<u8>, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::Memory(bytes);
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Construct file-backed BlobImpl from File ID
pub fn new_from_file(file_id: Uuid, name: PathBuf, size: u64, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::File(FileBlob {
id: file_id,
name: Some(name),
cache: RefCell::new(None),
size,
});
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Construct a BlobImpl from a slice of a parent.
pub fn new_sliced(rel_pos: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
let blob_data = BlobData::Sliced(parent, rel_pos);
BlobImpl {
blob_id,
type_string,
blob_data,
slices: vec![],
}
}
/// Get a clone of the blob-id
pub fn blob_id(&self) -> BlobId {
self.blob_id
}
/// Get a clone of the type-string
pub fn type_string(&self) -> String {
self.type_string.clone()
}
/// Get a mutable ref to the data
pub fn blob_data(&self) -> &BlobData {
&self.blob_data
}
/// Get a mutable ref to the data
pub fn blob_data_mut(&mut self) -> &mut BlobData {
&mut self.blob_data
}
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
/// A serializable version of the DOMPoint/DOMPointReadOnly interface.
pub struct DomPoint {
/// The x coordinate.
pub x: f64,
/// The y coordinate.
pub y: f64,
/// The z coordinate.
pub z: f64,
/// The w coordinate.
pub w: f64,
}
impl crate::BroadcastClone for DomPoint {
type Id = DomPointId;
fn source(
data: &crate::StructuredSerializedData,
) -> &Option<std::collections::HashMap<Self::Id, Self>> {
&data.points
}
fn destination(
data: &mut crate::StructuredSerializedData,
) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
&mut data.points
}
fn clone_for_broadcast(&self) -> Option<Self> {
Some(self.clone())
}
}

View file

@ -1,161 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! This module contains implementations in script that are transferable.
//! The implementations are here instead of in script
//! so that the other modules involved in the transfer don't have
//! to depend on script.
use std::collections::VecDeque;
use base::id::MessagePortId;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize};
use crate::PortMessageTask;
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
enum MessagePortState {
/// <https://html.spec.whatwg.org/multipage/#detached>
Detached,
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
/// The message-queue of this port is enabled,
/// the boolean represents awaiting completion of a transfer.
Enabled(bool),
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
/// The message-queue of this port is disabled,
/// the boolean represents awaiting completion of a transfer.
Disabled(bool),
}
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
/// The data and logic backing the DOM managed MessagePort.
pub struct MessagePortImpl {
/// The current state of the port.
state: MessagePortState,
/// <https://html.spec.whatwg.org/multipage/#entangle>
entangled_port: Option<MessagePortId>,
/// <https://html.spec.whatwg.org/multipage/#port-message-queue>
message_buffer: Option<VecDeque<PortMessageTask>>,
/// The UUID of this port.
message_port_id: MessagePortId,
}
impl MessagePortImpl {
/// Create a new messageport impl.
pub fn new(port_id: MessagePortId) -> MessagePortImpl {
MessagePortImpl {
state: MessagePortState::Disabled(false),
entangled_port: None,
message_buffer: None,
message_port_id: port_id,
}
}
/// Get the Id.
pub fn message_port_id(&self) -> &MessagePortId {
&self.message_port_id
}
/// Maybe get the Id of the entangled port.
pub fn entangled_port_id(&self) -> Option<MessagePortId> {
self.entangled_port
}
/// Entanged this port with another.
pub fn entangle(&mut self, other_id: MessagePortId) {
self.entangled_port = Some(other_id);
}
/// Is this port enabled?
pub fn enabled(&self) -> bool {
matches!(self.state, MessagePortState::Enabled(_))
}
/// Mark this port as having been shipped.
/// <https://html.spec.whatwg.org/multipage/#has-been-shipped>
pub fn set_has_been_shipped(&mut self) {
match self.state {
MessagePortState::Detached => {
panic!("Messageport set_has_been_shipped called in detached state")
},
MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(true),
MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(true),
}
}
/// Handle the completion of the transfer,
/// this is data received from the constellation.
pub fn complete_transfer(&mut self, mut tasks: VecDeque<PortMessageTask>) {
match self.state {
MessagePortState::Detached => return,
MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(false),
MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(false),
}
// Note: these are the tasks that were buffered while the transfer was ongoing,
// hence they need to execute first.
// The global will call `start` if we are enabled,
// which will add tasks on the event-loop to dispatch incoming messages.
match self.message_buffer {
Some(ref mut incoming_buffer) => {
while let Some(task) = tasks.pop_back() {
incoming_buffer.push_front(task);
}
},
None => self.message_buffer = Some(tasks),
}
}
/// A message was received from our entangled port,
/// returns an optional task to be dispatched.
pub fn handle_incoming(&mut self, task: PortMessageTask) -> Option<PortMessageTask> {
let should_dispatch = match self.state {
MessagePortState::Detached => return None,
MessagePortState::Enabled(in_transfer) => !in_transfer,
MessagePortState::Disabled(_) => false,
};
if should_dispatch {
Some(task)
} else {
match self.message_buffer {
Some(ref mut buffer) => {
buffer.push_back(task);
},
None => {
let mut queue = VecDeque::new();
queue.push_back(task);
self.message_buffer = Some(queue);
},
}
None
}
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
/// returns an optional queue of tasks that were buffered while the port was disabled.
pub fn start(&mut self) -> Option<VecDeque<PortMessageTask>> {
match self.state {
MessagePortState::Detached => return None,
MessagePortState::Enabled(_) => {},
MessagePortState::Disabled(in_transfer) => {
self.state = MessagePortState::Enabled(in_transfer);
},
}
if let MessagePortState::Enabled(true) = self.state {
return None;
}
self.message_buffer.take()
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
pub fn close(&mut self) {
// Step 1
self.state = MessagePortState::Detached;
}
}

View file

@ -18,8 +18,8 @@ use app_units::Au;
use atomic_refcell::AtomicRefCell;
use base::Epoch;
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use constellation_traits::{ScrollState, UntrustedNodeAddress};
use embedder_traits::ViewportDetails;
use constellation_traits::{LoadData, ScrollState};
use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
use euclid::default::{Point2D, Rect};
use fnv::FnvHashMap;
use fonts::{FontContext, SystemFontServiceProxy};
@ -31,7 +31,7 @@ use net_traits::image_cache::{ImageCache, PendingImageId};
use pixels::Image;
use profile_traits::mem::Report;
use profile_traits::time;
use script_traits::{InitialScriptState, LoadData, Painter, ScriptThreadMessage};
use script_traits::{InitialScriptState, Painter, ScriptThreadMessage};
use serde::{Deserialize, Serialize};
use servo_arc::Arc as ServoArc;
use servo_url::{ImmutableOrigin, ServoUrl};

View file

@ -17,7 +17,6 @@ no-wgl = ["surfman/sm-angle-default"]
[dependencies]
base = { workspace = true }
constellation_traits = { workspace = true }
dpi = { version = "0.1" }
embedder_traits = { workspace = true }
euclid = { workspace = true }

View file

@ -12,9 +12,8 @@ use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use base::id::WebViewId;
use constellation_traits::CompositorHitTestResult;
use display_list::CompositorDisplayListInfo;
use embedder_traits::ScreenGeometry;
use embedder_traits::{CompositorHitTestResult, ScreenGeometry};
use euclid::default::Size2D as UntypedSize2D;
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use log::warn;