diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-04-06 00:13:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-05 22:13:29 +0000 |
commit | 6031a12fd1fa4aee8368e0b3dc0cb792caac56bc (patch) | |
tree | cc91327012041a24bd1b71c7768660a2efbe862f /components/shared | |
parent | a67409fb253b3cb6dd1adbaf9d3cad47941f4993 (diff) | |
download | servo-6031a12fd1fa4aee8368e0b3dc0cb792caac56bc.tar.gz servo-6031a12fd1fa4aee8368e0b3dc0cb792caac56bc.zip |
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>
Diffstat (limited to 'components/shared')
-rw-r--r-- | components/shared/compositing/lib.rs | 5 | ||||
-rw-r--r-- | components/shared/constellation/Cargo.toml | 16 | ||||
-rw-r--r-- | components/shared/constellation/from_script_message.rs (renamed from components/shared/script/script_msg.rs) | 605 | ||||
-rw-r--r-- | components/shared/constellation/lib.rs | 73 | ||||
-rw-r--r-- | components/shared/constellation/message_port.rs | 525 | ||||
-rw-r--r-- | components/shared/embedder/lib.rs | 88 | ||||
-rw-r--r-- | components/shared/script/Cargo.toml | 12 | ||||
-rw-r--r-- | components/shared/script/lib.rs | 449 | ||||
-rw-r--r-- | components/shared/script/serializable.rs | 217 | ||||
-rw-r--r-- | components/shared/script/transferable.rs | 161 | ||||
-rw-r--r-- | components/shared/script_layout/lib.rs | 6 | ||||
-rw-r--r-- | components/shared/webrender/Cargo.toml | 1 | ||||
-rw-r--r-- | components/shared/webrender/lib.rs | 3 |
13 files changed, 1078 insertions, 1083 deletions
diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 738619ffc31..9c13afb8dc3 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -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; diff --git a/components/shared/constellation/Cargo.toml b/components/shared/constellation/Cargo.toml index 10ee64d0b42..53a4307df60 100644 --- a/components/shared/constellation/Cargo.toml +++ b/components/shared/constellation/Cargo.toml @@ -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 } diff --git a/components/shared/script/script_msg.rs b/components/shared/constellation/from_script_message.rs index 30244c9b46a..bccb3059e24 100644 --- a/components/shared/script/script_msg.rs +++ b/components/shared/constellation/from_script_message.rs @@ -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 constellation’s response to our request. + pub response_sender: IpcSender<Option<AuxiliaryWebViewCreationResponse>>, +} + +/// Constellation’s 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, -} diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs index 22de84c4711..627741a40fb 100644 --- a/components/shared/constellation/lib.rs +++ b/components/shared/constellation/lib.rs @@ -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 { diff --git a/components/shared/constellation/message_port.rs b/components/shared/constellation/message_port.rs new file mode 100644 index 00000000000..36c6213bf80 --- /dev/null +++ b/components/shared/constellation/message_port.rs @@ -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()) + } +} diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 67ccd9887ae..85dd4bf3af9 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -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, +} diff --git a/components/shared/script/Cargo.toml b/components/shared/script/Cargo.toml index dda1371817f..49efbadc165 100644 --- a/components/shared/script/Cargo.toml +++ b/components/shared/script/Cargo.toml @@ -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 } diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 91e4ca33dc4..1a35f4f7486 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -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 constellation’s response to our request. - pub response_sender: IpcSender<Option<AuxiliaryWebViewCreationResponse>>, -} - -/// Constellation’s 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(), - } - } -} diff --git a/components/shared/script/serializable.rs b/components/shared/script/serializable.rs deleted file mode 100644 index 5d89c622bee..00000000000 --- a/components/shared/script/serializable.rs +++ /dev/null @@ -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()) - } -} diff --git a/components/shared/script/transferable.rs b/components/shared/script/transferable.rs deleted file mode 100644 index 8344dd493b0..00000000000 --- a/components/shared/script/transferable.rs +++ /dev/null @@ -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; - } -} diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 66ddb3a55fa..6d686d75f03 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -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}; diff --git a/components/shared/webrender/Cargo.toml b/components/shared/webrender/Cargo.toml index 6ecaa7cdee3..b437174307d 100644 --- a/components/shared/webrender/Cargo.toml +++ b/components/shared/webrender/Cargo.toml @@ -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 } diff --git a/components/shared/webrender/lib.rs b/components/shared/webrender/lib.rs index c91931f0954..3438aeb28ef 100644 --- a/components/shared/webrender/lib.rs +++ b/components/shared/webrender/lib.rs @@ -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; |