/* 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 traits in script used generically in the rest of Servo. //! The traits are here instead of in script so that these modules won't have //! to depend on script. #![deny(missing_docs)] #![deny(unsafe_code)] pub mod compositor; mod script_msg; pub mod serializable; pub mod transferable; pub mod webdriver_msg; use std::borrow::Cow; use std::collections::{HashMap, VecDeque}; use std::fmt; use std::sync::atomic::AtomicBool; use std::sync::Arc; use bitflags::bitflags; use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use compositor::ScrollTreeNodeId; use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use embedder_traits::Cursor; use euclid::default::Point2D; use euclid::{Length, Rect, Scale, Size2D, UnknownUnit, Vector2D}; use gfx_traits::Epoch; use http::{HeaderMap, Method}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::Error as IpcError; use keyboard_types::webdriver::Event as WebDriverInputEvent; use keyboard_types::{CompositionEvent, KeyboardEvent}; use libc::c_void; use log::warn; use malloc_size_of::malloc_size_of_is_0; use malloc_size_of_derive::MallocSizeOf; use media::WindowGLContext; use msg::constellation_msg::{ BackgroundHangMonitorRegister, BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId, TopLevelBrowsingContextId, }; use net_traits::image::base::Image; use net_traits::image_cache::ImageCache; use net_traits::request::{Referrer, RequestBody}; use net_traits::storage_thread::StorageType; use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads}; use pixels::PixelFormat; use profile_traits::{mem, time as profile_time}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use servo_atoms::Atom; use servo_url::{ImmutableOrigin, ServoUrl}; use style_traits::{CSSPixel, SpeculativePainter}; use webgpu::identity::WebGPUMsg; use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel, LayoutPoint, WorldPoint}; use webrender_api::{ BuiltDisplayList, BuiltDisplayListDescriptor, DocumentId, ExternalImageData, ExternalScrollId, HitTestFlags, ImageData, ImageDescriptor, ImageKey, PipelineId as WebRenderPipelineId, }; use crate::compositor::CompositorDisplayListInfo; pub use crate::script_msg::{ DOMMessage, EventResult, HistoryEntryReplacement, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, LayoutMsg, LogEntry, SWManagerMsg, SWManagerSenders, ScopeThings, ScriptMsg, ServiceWorkerMsg, }; use crate::serializable::{BlobData, BlobImpl}; use crate::transferable::MessagePortImpl; use crate::webdriver_msg::{LoadStatus, WebDriverScriptCommand}; /// 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 for UntrustedNodeAddress { fn from(o: style_traits::dom::OpaqueNode) -> Self { UntrustedNodeAddress(o.0 as *const c_void) } } impl Serialize for UntrustedNodeAddress { fn serialize(&self, s: S) -> Result { (self.0 as usize).serialize(s) } } impl<'de> Deserialize<'de> for UntrustedNodeAddress { fn deserialize>(d: D) -> Result { 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) } } /// Messages sent to the layout thread from the constellation and/or compositor. #[derive(Debug, Deserialize, Serialize)] pub enum LayoutControlMsg { /// Requests that this layout thread exit. ExitNow, /// Requests the current epoch (layout counter) from this layout. GetCurrentEpoch(IpcSender), /// Tells layout about the new scrolling offsets of each scrollable stacking context. SetScrollStates(Vec), /// Requests the current load state of Web fonts. `true` is returned if fonts are still loading /// and `false` is returned if all fonts have loaded. GetWebFontLoadState(IpcSender), /// Send the paint time for a specific epoch to the layout thread. PaintMetric(Epoch, u64), } /// 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, /// 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, /// The result of evaluating a javascript scheme url. pub js_eval_result: Option, /// The referrer. pub referrer: Referrer, /// The referrer policy. pub referrer_policy: Option, /// 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, /// Servo internal: if crash details are present, trigger a crash error page with these details. pub crash: Option, } /// 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. /// 12.11 NoContent, /// The js evaluation had a string result. Ok(Vec), } impl LoadData { /// Create a new `LoadData` object. pub fn new( load_origin: LoadOrigin, url: ServoUrl, creator_pipeline_id: Option, referrer: Referrer, referrer_policy: Option, inherited_secure_context: Option, ) -> LoadData { LoadData { load_origin, url: url, creator_pipeline_id: creator_pipeline_id, method: Method::GET, headers: HeaderMap::new(), data: None, js_eval_result: None, referrer: referrer, referrer_policy: referrer_policy, srcdoc: "".to_string(), inherited_secure_context, crash: None, } } } /// The initial data required to create a new layout attached to an existing script thread. #[derive(Debug, Deserialize, Serialize)] pub struct NewLayoutInfo { /// The ID of the parent pipeline and frame type, if any. /// If `None`, this is a root pipeline. pub parent_info: Option, /// Id of the newly-created pipeline. pub new_pipeline_id: PipelineId, /// Id of the browsing context associated with this pipeline. pub browsing_context_id: BrowsingContextId, /// Id of the top-level browsing context associated with this pipeline. pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// Id of the opener, if any pub opener: Option, /// Network request data which will be initiated by the script thread. pub load_data: LoadData, /// Information about the initial window size. pub window_size: WindowSizeData, /// A port on which layout can receive messages from the pipeline. pub pipeline_port: IpcReceiver, } /// When a pipeline is closed, should its browsing context be discarded too? #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum DiscardBrowsingContext { /// Discard the browsing context Yes, /// Don't discard the browsing context No, } /// 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, /// and it is inactive otherwise. /// /// * /// * #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum DocumentActivity { /// An inactive document Inactive, /// An active but not fully active document Active, /// A fully active document FullyActive, } /// Type of recorded progressive web metric #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum ProgressiveWebMetricType { /// Time to first Paint FirstPaint, /// Time to first contentful paint FirstContentfulPaint, /// Time to interactive TimeToInteractive, } /// The reason why the pipeline id of an iframe is being updated. #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum UpdatePipelineIdReason { /// The pipeline id is being updated due to a navigation. Navigation, /// The pipeline id is being updated due to a history traversal. Traversal, } /// Messages sent from the constellation or layout to the script thread. #[derive(Deserialize, Serialize)] pub enum ConstellationControlMsg { /// Takes the associated window proxy out of "delaying-load-events-mode", /// used if a scheduled navigated was refused by the embedder. /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode StopDelayingLoadEventsMode(PipelineId), /// Sends the final response to script thread for fetching after all redirections /// have been resolved NavigationResponse(PipelineId, FetchResponseMsg), /// Gives a channel and ID to a layout thread, as well as the ID of that layout's parent AttachLayout(NewLayoutInfo), /// Window resized. Sends a DOM event eventually, but first we combine events. Resize(PipelineId, WindowSizeData, WindowSizeType), /// Notifies script that window has been resized but to not take immediate action. ResizeInactive(PipelineId, WindowSizeData), /// Window switched from fullscreen mode. ExitFullScreen(PipelineId), /// Notifies the script that the document associated with this pipeline should 'unload'. UnloadDocument(PipelineId), /// Notifies the script that a pipeline should be closed. ExitPipeline(PipelineId, DiscardBrowsingContext), /// Notifies the script that the whole thread should be closed. ExitScriptThread, /// Sends a DOM event. SendEvent(PipelineId, CompositorEvent), /// Notifies script of the viewport. Viewport(PipelineId, Rect), /// Notifies script of a new set of scroll offsets. SetScrollState( PipelineId, Vec<(UntrustedNodeAddress, Vector2D)>, ), /// Requests that the script thread immediately send the constellation the title of a pipeline. GetTitle(PipelineId), /// Notifies script thread of a change to one of its document's activity SetDocumentActivity(PipelineId, DocumentActivity), /// Notifies script thread whether frame is visible ChangeFrameVisibilityStatus(PipelineId, bool), /// Notifies script thread that frame visibility change is complete /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context NotifyVisibilityChange(PipelineId, BrowsingContextId, bool), /// Notifies script thread that a url should be loaded in this iframe. /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context NavigateIframe( PipelineId, BrowsingContextId, LoadData, HistoryEntryReplacement, ), /// Post a message to a given window. PostMessage { /// The target of the message. target: PipelineId, /// The source of the message. source: PipelineId, /// The top level browsing context associated with the source pipeline. source_browsing_context: TopLevelBrowsingContextId, /// The expected origin of the target. target_origin: Option, /// The source origin of the message. /// https://html.spec.whatwg.org/multipage/#dom-messageevent-origin source_origin: ImmutableOrigin, /// The data to be posted. data: StructuredSerializedData, }, /// Updates the current pipeline ID of a given iframe. /// First PipelineId is for the parent, second is the new PipelineId for the frame. UpdatePipelineId( PipelineId, BrowsingContextId, TopLevelBrowsingContextId, PipelineId, UpdatePipelineIdReason, ), /// Updates the history state and url of a given pipeline. UpdateHistoryState(PipelineId, Option, ServoUrl), /// Removes inaccesible history states. RemoveHistoryStates(PipelineId, Vec), /// Set an iframe to be focused. Used when an element in an iframe gains focus. /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context FocusIFrame(PipelineId, BrowsingContextId), /// Passes a webdriver command to the script thread for execution WebDriverScriptCommand(PipelineId, WebDriverScriptCommand), /// Notifies script thread that all animations are done TickAllAnimations(PipelineId, AnimationTickType), /// Notifies the script thread that a new Web font has been loaded, and thus the page should be /// reflowed. WebFontLoaded(PipelineId), /// Cause a `load` event to be dispatched at the appropriate iframe element. DispatchIFrameLoadEvent { /// The frame that has been marked as loaded. target: BrowsingContextId, /// The pipeline that contains a frame loading the target pipeline. parent: PipelineId, /// The pipeline that has completed loading. child: PipelineId, }, /// Cause a `storage` event to be dispatched at the appropriate window. /// The strings are key, old value and new value. DispatchStorageEvent( PipelineId, StorageType, ServoUrl, Option, Option, Option, ), /// Report an error from a CSS parser for the given pipeline ReportCSSError(PipelineId, String, u32, u32, String), /// Reload the given page. Reload(PipelineId), /// Notifies the script thread about a new recorded paint metric. PaintMetric(PipelineId, ProgressiveWebMetricType, u64), /// Notifies the media session about a user requested media session action. MediaSessionAction(PipelineId, MediaSessionActionType), /// Notifies script thread that WebGPU server has started SetWebGPUPort(IpcReceiver), } impl fmt::Debug for ConstellationControlMsg { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { use self::ConstellationControlMsg::*; let variant = match *self { StopDelayingLoadEventsMode(..) => "StopDelayingLoadsEventMode", NavigationResponse(..) => "NavigationResponse", AttachLayout(..) => "AttachLayout", Resize(..) => "Resize", ResizeInactive(..) => "ResizeInactive", UnloadDocument(..) => "UnloadDocument", ExitPipeline(..) => "ExitPipeline", ExitScriptThread => "ExitScriptThread", SendEvent(..) => "SendEvent", Viewport(..) => "Viewport", SetScrollState(..) => "SetScrollState", GetTitle(..) => "GetTitle", SetDocumentActivity(..) => "SetDocumentActivity", ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus", NotifyVisibilityChange(..) => "NotifyVisibilityChange", NavigateIframe(..) => "NavigateIframe", PostMessage { .. } => "PostMessage", UpdatePipelineId(..) => "UpdatePipelineId", UpdateHistoryState(..) => "UpdateHistoryState", RemoveHistoryStates(..) => "RemoveHistoryStates", FocusIFrame(..) => "FocusIFrame", WebDriverScriptCommand(..) => "WebDriverScriptCommand", TickAllAnimations(..) => "TickAllAnimations", WebFontLoaded(..) => "WebFontLoaded", DispatchIFrameLoadEvent { .. } => "DispatchIFrameLoadEvent", DispatchStorageEvent(..) => "DispatchStorageEvent", ReportCSSError(..) => "ReportCSSError", Reload(..) => "Reload", PaintMetric(..) => "PaintMetric", ExitFullScreen(..) => "ExitFullScreen", MediaSessionAction(..) => "MediaSessionAction", SetWebGPUPort(..) => "SetWebGPUPort", }; write!(formatter, "ConstellationControlMsg::{}", variant) } } /// 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, } /// 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, } /// The type of input represented by a multi-touch event. #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum TouchEventType { /// A new touch point came in contact with the screen. Down, /// An existing touch point changed location. Move, /// A touch point was removed from the screen. Up, /// The system stopped tracking a touch point. Cancel, } /// An opaque identifier for a touch point. /// /// #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct TouchId(pub i32); /// The mouse button involved in the event. #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum MouseButton { /// The left mouse button. Left = 1, /// The right mouse button. Right = 2, /// The middle mouse button. Middle = 4, } /// The types of mouse events #[derive(Debug, Deserialize, MallocSizeOf, Serialize)] pub enum MouseEventType { /// Mouse button clicked Click, /// Mouse button down MouseDown, /// Mouse button up MouseUp, } /// Mode to measure WheelDelta floats in #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub enum WheelMode { /// Delta values are specified in pixels DeltaPixel = 0x00, /// Delta values are specified in lines DeltaLine = 0x01, /// Delta values are specified in pages DeltaPage = 0x02, } /// The Wheel event deltas in every direction #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct WheelDelta { /// Delta in the left/right direction pub x: f64, /// Delta in the up/down direction pub y: f64, /// Delta in the direction going into/out of the screen pub z: f64, /// Mode to measure the floats in pub mode: WheelMode, } /// Events from the compositor that the script thread needs to know about #[derive(Debug, Deserialize, Serialize)] pub enum CompositorEvent { /// The window was resized. ResizeEvent(WindowSizeData, WindowSizeType), /// A mouse button state changed. MouseButtonEvent( MouseEventType, MouseButton, Point2D, Option, Option>, // Bitmask of MouseButton values representing the currently pressed buttons u16, ), /// The mouse was moved over a point (or was moved out of the recognizable region). MouseMoveEvent( Point2D, Option, // Bitmask of MouseButton values representing the currently pressed buttons u16, ), /// A touch event was generated with a touch ID and location. TouchEvent( TouchEventType, TouchId, Point2D, Option, ), /// A wheel event was generated with a delta in the X, Y, and/or Z directions WheelEvent(WheelDelta, Point2D, Option), /// A key was pressed. KeyboardEvent(KeyboardEvent), /// An event from the IME is dispatched. CompositionEvent(CompositionEvent), /// Virtual keyboard was dismissed IMEDismissedEvent, } /// Requests a TimerEvent-Message be sent after the given duration. #[derive(Debug, Deserialize, Serialize)] pub struct TimerEventRequest( pub IpcSender, pub TimerSource, pub TimerEventId, pub MsDuration, ); /// The message used to send a request to the timer scheduler. #[derive(Debug, Deserialize, Serialize)] pub struct TimerSchedulerMsg(pub TimerEventRequest); /// Notifies the script thread to fire due timers. /// `TimerSource` must be `FromWindow` when dispatched to `ScriptThread` and /// must be `FromWorker` when dispatched to a `DedicatedGlobalWorkerScope` #[derive(Debug, Deserialize, Serialize)] pub struct TimerEvent(pub TimerSource, pub TimerEventId); /// Describes the thread that requested the TimerEvent. #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)] pub enum TimerSource { /// The event was requested from a window (ScriptThread). FromWindow(PipelineId), /// The event was requested from a worker (DedicatedGlobalWorkerScope). FromWorker, } /// The id to be used for a `TimerEvent` is defined by the corresponding `TimerEventRequest`. #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub struct TimerEventId(pub u32); /// Unit of measurement. #[derive(Clone, Copy, MallocSizeOf)] pub enum Milliseconds {} /// Unit of measurement. #[derive(Clone, Copy, MallocSizeOf)] pub enum Nanoseconds {} /// Amount of milliseconds. pub type MsDuration = Length; /// Amount of nanoseconds. pub type NsDuration = Length; /// Returns the duration since an unspecified epoch measured in ms. pub fn precise_time_ms() -> MsDuration { Length::new(time::precise_time_ns() / (1000 * 1000)) } /// Data needed to construct a script thread. /// /// NB: *DO NOT* add any Senders or Receivers here! pcwalton will have to rewrite your code if you /// do! Use IPC senders and receivers instead. pub struct InitialScriptState { /// The ID of the pipeline with which this script thread is associated. pub id: PipelineId, /// The subpage ID of this pipeline to create in its pipeline parent. /// If `None`, this is the root. pub parent_info: Option, /// The ID of the browsing context this script is part of. pub browsing_context_id: BrowsingContextId, /// The ID of the top-level browsing context this script is part of. pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// The ID of the opener, if any. pub opener: Option, /// Loading into a Secure Context pub inherited_secure_context: Option, /// A channel with which messages can be sent to us (the script thread). pub control_chan: IpcSender, /// A port on which messages sent by the constellation to script can be received. pub control_port: IpcReceiver, /// A channel on which messages can be sent to the constellation from script. pub script_to_constellation_chan: ScriptToConstellationChan, /// A handle to register script-(and associated layout-)threads for hang monitoring. pub background_hang_monitor_register: Box, /// A sender for the layout thread to communicate to the constellation. pub layout_to_constellation_chan: IpcSender, /// A channel to schedule timer events. pub scheduler_chan: IpcSender, /// A channel to the resource manager thread. pub resource_threads: ResourceThreads, /// A channel to the bluetooth thread. pub bluetooth_thread: IpcSender, /// The image cache for this script thread. pub image_cache: Arc, /// A channel to the time profiler thread. pub time_profiler_chan: profile_traits::time::ProfilerChan, /// A channel to the memory profiler thread. pub mem_profiler_chan: mem::ProfilerChan, /// A channel to the developer tools, if applicable. pub devtools_chan: Option>, /// Information about the initial window size. pub window_size: WindowSizeData, /// The ID of the pipeline namespace for this script thread. pub pipeline_namespace_id: PipelineNamespaceId, /// A ping will be sent on this channel once the script thread shuts down. pub content_process_shutdown_chan: Sender<()>, /// A channel to the WebGL thread used in this pipeline. pub webgl_chan: Option, /// The XR device registry pub webxr_registry: webxr_api::Registry, /// The Webrender document ID associated with this thread. pub webrender_document: DocumentId, /// FIXME(victor): The Webrender API sender in this constellation's pipeline pub webrender_api_sender: WebrenderIpcSender, /// Flag to indicate if the layout thread is busy handling a request. pub layout_is_busy: Arc, /// Application window's GL Context for Media player pub player_context: WindowGLContext, } /// This trait allows creating a `ScriptThread` without depending on the `script` /// crate. pub trait ScriptThreadFactory { /// Type of message sent from script to layout. type Message; /// Create a `ScriptThread`. fn create( state: InitialScriptState, load_data: LoadData, user_agent: Cow<'static, str>, ) -> (Sender, Receiver); } /// 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 AuxiliaryBrowsingContextLoadInfo { /// Load data containing the url to load pub load_data: LoadData, /// The pipeline opener browsing context. pub opener_pipeline_id: PipelineId, /// The new top-level ID for the auxiliary. pub new_top_level_browsing_context_id: TopLevelBrowsingContextId, /// The new browsing context ID. pub new_browsing_context_id: BrowsingContextId, /// The new pipeline ID for the auxiliary. 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 top_level_browsing_context_id: TopLevelBrowsingContextId, /// 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, /// Wether this load should replace the current entry (reload). If true, the current /// entry will be replaced instead of a new entry being added. pub replace: HistoryEntryReplacement, } /// 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, /// Sandbox type of this iframe pub sandbox: IFrameSandboxState, /// The initial viewport size for this iframe. pub window_size: WindowSizeData, } bitflags! { #[derive(Deserialize, Serialize)] /// Specifies if rAF should be triggered and/or CSS Animations and Transitions. pub struct AnimationTickType: u8 { /// Trigger a call to requestAnimationFrame. const REQUEST_ANIMATION_FRAME = 0b001; /// Trigger restyles for CSS Animations and Transitions. const CSS_ANIMATIONS_AND_TRANSITIONS = 0b010; } } /// The scroll state of a stacking context. #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ScrollState { /// The ID of the scroll root. pub scroll_id: ExternalScrollId, /// The scrolling offset of this stacking context. pub scroll_offset: Vector2D, } /// Data about the window size. #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct WindowSizeData { /// The size of the initial layout viewport, before parsing an /// pub initial_viewport: Size2D, /// The resolution of the window in dppx, not including any "pinch zoom" factor. pub device_pixel_ratio: Scale, } /// The type of window size change. #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub enum WindowSizeType { /// Initial load. Initial, /// Window resize. Resize, } /// Messages to the constellation originating from the WebDriver server. #[derive(Debug, Deserialize, Serialize)] pub enum WebDriverCommandMsg { /// Get the window size. GetWindowSize(TopLevelBrowsingContextId, IpcSender), /// Load a URL in the top-level browsing context with the given ID. LoadUrl(TopLevelBrowsingContextId, LoadData, IpcSender), /// Refresh the top-level browsing context with the given ID. Refresh(TopLevelBrowsingContextId, IpcSender), /// Pass a webdriver command to the script thread of the current pipeline /// of a browsing context. ScriptCommand(BrowsingContextId, WebDriverScriptCommand), /// Act as if keys were pressed in the browsing context with the given ID. SendKeys(BrowsingContextId, Vec), /// Act as if keys were pressed or release in the browsing context with the given ID. KeyboardAction(BrowsingContextId, KeyboardEvent), /// Act as if the mouse was clicked in the browsing context with the given ID. MouseButtonAction(MouseEventType, MouseButton, f32, f32), /// Act as if the mouse was moved in the browsing context with the given ID. MouseMoveAction(f32, f32), /// Set the window size. SetWindowSize( TopLevelBrowsingContextId, DeviceIntSize, IpcSender, ), /// Take a screenshot of the window. TakeScreenshot( TopLevelBrowsingContextId, Option>, IpcSender>, ), } /// 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>, /// From devtools sender pub from_devtools_sender: Option>, /// Messages to send to constellation pub script_to_constellation_chan: ScriptToConstellationChan, /// Message to send to the scheduler pub scheduler_chan: IpcSender, /// 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, /// True if headless mode pub is_headless: bool, /// An optional string allowing the user agnet to be set for testing. pub user_agent: Cow<'static, str>, /// True if secure context pub inherited_secure_context: Option, } /// Common entities representing a network load origin #[derive(Clone, Debug, Deserialize, Serialize)] pub struct WorkerScriptLoadOrigin { /// referrer url pub referrer_url: Option, /// the referrer policy which is used pub referrer_policy: Option, /// 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 { /// Execution timed out. Timeout, /// No such worklet. WorkletNotFound, } impl From for PaintWorkletError { fn from(_: RecvTimeoutError) -> PaintWorkletError { PaintWorkletError::Timeout } } /// Execute paint code in the worklet thread pool. pub trait Painter: SpeculativePainter { /// fn draw_a_paint_image( &self, size: Size2D, zoom: Scale, properties: Vec<(Atom, String)>, arguments: Vec, ) -> Result; } impl fmt::Debug for dyn Painter { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_tuple("Painter") .field(&format_args!("..")) .finish() } } /// The result of executing paint code: the image together with any image URLs that need to be loaded. /// /// TODO: this should return a WR display list. #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct DrawAPaintImageResult { /// The image height pub width: u32, /// The image width pub height: u32, /// The image format pub format: PixelFormat, /// The image drawn, or None if an invalid paint image was drawn pub image_key: Option, /// Drawing the image might have requested loading some image URLs. pub missing_image_urls: Vec, } /// A Script to Constellation channel. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ScriptToConstellationChan { /// Sender for communicating with constellation thread. pub sender: IpcSender<(PipelineId, ScriptMsg)>, /// 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: ScriptMsg) -> Result<(), IpcError> { self.sender.send((self.pipeline_id, msg)) } } /// A data-holder for serialized data and transferred objects. /// #[derive(Debug, Deserialize, MallocSizeOf, Serialize)] pub struct StructuredSerializedData { /// Data serialized by SpiderMonkey. pub serialized: Vec, /// Serialized in a structured callback, pub blobs: Option>, /// Transferred objects. pub ports: Option>, } impl StructuredSerializedData { /// Clone the serialized data for use with broadcast-channels. pub fn clone_for_broadcast(&self) -> StructuredSerializedData { let serialized = self.serialized.clone(); let blobs = if let Some(blobs) = self.blobs.as_ref() { let mut blob_clones = HashMap::with_capacity(blobs.len()); for (original_id, blob) in blobs.iter() { let type_string = blob.type_string(); if let BlobData::Memory(ref bytes) = blob.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. blob_clones.insert(original_id.clone(), blob_clone); } else { // Not panicking only because this is called from the constellation. warn!("Serialized blob not in memory format(should never happen)."); } } Some(blob_clones) } else { None }; if self.ports.is_some() { // Not panicking only because this is called from the constellation. warn!("Attempt to broadcast structured serialized data including ports(should never happen)."); } StructuredSerializedData { serialized, blobs, // Ports cannot be broadcast. ports: None, } } } /// 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>), /// 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), /// 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(), } } } /// The type of MediaSession action. /// https://w3c.github.io/mediasession/#enumdef-mediasessionaction #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum MediaSessionActionType { /// The action intent is to resume playback. Play, /// The action intent is to pause the currently active playback. Pause, /// The action intent is to move the playback time backward by a short period (i.e. a few /// seconds). SeekBackward, /// The action intent is to move the playback time forward by a short period (i.e. a few /// seconds). SeekForward, /// The action intent is to either start the current playback from the beginning if the /// playback has a notion, of beginning, or move to the previous item in the playlist if the /// playback has a notion of playlist. PreviousTrack, /// The action is to move to the playback to the next item in the playlist if the playback has /// a notion of playlist. NextTrack, /// The action intent is to skip the advertisement that is currently playing. SkipAd, /// The action intent is to stop the playback and clear the state if appropriate. Stop, /// The action intent is to move the playback time to a specific time. SeekTo, } impl From for MediaSessionActionType { fn from(value: i32) -> MediaSessionActionType { match value { 1 => MediaSessionActionType::Play, 2 => MediaSessionActionType::Pause, 3 => MediaSessionActionType::SeekBackward, 4 => MediaSessionActionType::SeekForward, 5 => MediaSessionActionType::PreviousTrack, 6 => MediaSessionActionType::NextTrack, 7 => MediaSessionActionType::SkipAd, 8 => MediaSessionActionType::Stop, 9 => MediaSessionActionType::SeekTo, _ => panic!("Unknown MediaSessionActionType"), } } } /// 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, /// The hit test point relative to the item itself. pub point_relative_to_item: euclid::default::Point2D, /// 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, /// The scroll tree node associated with this hit test item. pub scroll_tree_node: ScrollTreeNodeId, } /// The set of WebRender operations that can be initiated by the content process. #[derive(Deserialize, Serialize)] pub enum ScriptToCompositorMsg { /// Inform WebRender of the existence of this pipeline. SendInitialTransaction(WebRenderPipelineId), /// Perform a scroll operation. SendScrollNode(LayoutPoint, ExternalScrollId), /// Inform WebRender of a new display list for the given pipeline. SendDisplayList { /// The [CompositorDisplayListInfo] that describes the display list being sent. display_list_info: CompositorDisplayListInfo, /// A descriptor of this display list used to construct this display list from raw data. display_list_descriptor: BuiltDisplayListDescriptor, /// An [ipc::IpcBytesReceiver] used to send the raw data of the display list. display_list_receiver: ipc::IpcBytesReceiver, }, /// Perform a hit test operation. The result will be returned via /// the provided channel sender. HitTest( Option, WorldPoint, HitTestFlags, IpcSender>, ), /// Create a new image key. The result will be returned via the /// provided channel sender. GenerateImageKey(IpcSender), /// Perform a resource update operation. UpdateImages(Vec), } #[derive(Clone, Deserialize, Serialize)] /// A mechanism to communicate with the parent process' WebRender instance. pub struct WebrenderIpcSender(IpcSender); impl WebrenderIpcSender { /// Create a new WebrenderIpcSender object that wraps the provided channel sender. pub fn new(sender: IpcSender) -> Self { Self(sender) } /// Inform WebRender of the existence of this pipeline. pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) { if let Err(e) = self .0 .send(ScriptToCompositorMsg::SendInitialTransaction(pipeline)) { warn!("Error sending initial transaction: {}", e); } } /// Perform a scroll operation. pub fn send_scroll_node(&self, point: LayoutPoint, scroll_id: ExternalScrollId) { if let Err(e) = self .0 .send(ScriptToCompositorMsg::SendScrollNode(point, scroll_id)) { warn!("Error sending scroll node: {}", e); } } /// Inform WebRender of a new display list for the given pipeline. pub fn send_display_list( &self, display_list_info: CompositorDisplayListInfo, list: BuiltDisplayList, ) { let (display_list_data, display_list_descriptor) = list.into_data(); let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap(); if let Err(e) = self.0.send(ScriptToCompositorMsg::SendDisplayList { display_list_info, display_list_descriptor, display_list_receiver, }) { warn!("Error sending display list: {}", e); } if let Err(e) = display_list_sender.send(&display_list_data) { warn!("Error sending display data: {}", e); } } /// Perform a hit test operation. Blocks until the operation is complete and /// and a result is available. pub fn hit_test( &self, pipeline: Option, point: WorldPoint, flags: HitTestFlags, ) -> Vec { let (sender, receiver) = ipc::channel().unwrap(); self.0 .send(ScriptToCompositorMsg::HitTest( pipeline, point, flags, sender, )) .expect("error sending hit test"); receiver.recv().expect("error receiving hit test result") } /// Create a new image key. Blocks until the key is available. pub fn generate_image_key(&self) -> Result { let (sender, receiver) = ipc::channel().unwrap(); self.0 .send(ScriptToCompositorMsg::GenerateImageKey(sender)) .map_err(|_| ())?; receiver.recv().map_err(|_| ()) } /// Perform a resource update operation. pub fn update_images(&self, updates: Vec) { let mut senders = Vec::new(); // Convert `ImageUpdate` to `SerializedImageUpdate` because `ImageData` may contain large // byes. With this conversion, we send `IpcBytesReceiver` instead and use it to send the // actual bytes. let updates = updates .into_iter() .map(|update| match update { ImageUpdate::AddImage(k, d, data) => { let data = match data { ImageData::Raw(r) => { let (sender, receiver) = ipc::bytes_channel().unwrap(); senders.push((sender, r)); SerializedImageData::Raw(receiver) }, ImageData::External(e) => SerializedImageData::External(e), }; SerializedImageUpdate::AddImage(k, d, data) }, ImageUpdate::DeleteImage(k) => SerializedImageUpdate::DeleteImage(k), ImageUpdate::UpdateImage(k, d, data) => { let data = match data { ImageData::Raw(r) => { let (sender, receiver) = ipc::bytes_channel().unwrap(); senders.push((sender, r)); SerializedImageData::Raw(receiver) }, ImageData::External(e) => SerializedImageData::External(e), }; SerializedImageUpdate::UpdateImage(k, d, data) }, }) .collect(); if let Err(e) = self.0.send(ScriptToCompositorMsg::UpdateImages(updates)) { warn!("error sending image updates: {}", e); } senders.into_iter().for_each(|(tx, data)| { if let Err(e) = tx.send(&*data) { warn!("error sending image data: {}", e); } }); } } #[derive(Deserialize, Serialize)] /// Serializable image updates that must be performed by WebRender. pub enum ImageUpdate { /// Register a new image. AddImage(ImageKey, ImageDescriptor, ImageData), /// Delete a previously registered image registration. DeleteImage(ImageKey), /// Update an existing image registration. UpdateImage(ImageKey, ImageDescriptor, ImageData), } #[derive(Deserialize, Serialize)] /// Serialized `ImageUpdate`. pub enum SerializedImageUpdate { /// Register a new image. AddImage(ImageKey, ImageDescriptor, SerializedImageData), /// Delete a previously registered image registration. DeleteImage(ImageKey), /// Update an existing image registration. UpdateImage(ImageKey, ImageDescriptor, SerializedImageData), } #[derive(Debug, Deserialize, Serialize)] /// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too /// slow. pub enum SerializedImageData { /// A simple series of bytes, provided by the embedding and owned by WebRender. /// The format is stored out-of-band, currently in ImageDescriptor. Raw(ipc::IpcBytesReceiver), /// An image owned by the embedding, and referenced by WebRender. This may /// take the form of a texture or a heap-allocated buffer. External(ExternalImageData), } impl SerializedImageData { /// Convert to ``ImageData`. pub fn to_image_data(&self) -> Result { match self { SerializedImageData::Raw(rx) => rx.recv().map(|data| ImageData::new(data)), SerializedImageData::External(image) => Ok(ImageData::External(image.clone())), } } }