aboutsummaryrefslogtreecommitdiffstats
path: root/components/shared/script/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/shared/script/lib.rs')
-rw-r--r--components/shared/script/lib.rs1314
1 files changed, 1314 insertions, 0 deletions
diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs
new file mode 100644
index 00000000000..77782255a4c
--- /dev/null
+++ b/components/shared/script/lib.rs
@@ -0,0 +1,1314 @@
+/* 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<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)
+ }
+}
+
+/// 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<Epoch>),
+ /// Tells layout about the new scrolling offsets of each scrollable stacking context.
+ SetScrollStates(Vec<ScrollState>),
+ /// 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<bool>),
+ /// 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<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: Option<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>,
+
+ /// 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.
+ pub fn new(
+ load_origin: LoadOrigin,
+ url: ServoUrl,
+ creator_pipeline_id: Option<PipelineId>,
+ referrer: Referrer,
+ referrer_policy: Option<ReferrerPolicy>,
+ inherited_secure_context: Option<bool>,
+ ) -> 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<PipelineId>,
+ /// 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<BrowsingContextId>,
+ /// 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<LayoutControlMsg>,
+}
+
+/// 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.
+///
+/// * <https://html.spec.whatwg.org/multipage/#active-document>
+/// * <https://html.spec.whatwg.org/multipage/#fully-active>
+#[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<f32, UnknownUnit>),
+ /// Notifies script of a new set of scroll offsets.
+ SetScrollState(
+ PipelineId,
+ Vec<(UntrustedNodeAddress, Vector2D<f32, LayoutPixel>)>,
+ ),
+ /// 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<ImmutableOrigin>,
+ /// 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<HistoryStateId>, ServoUrl),
+ /// Removes inaccesible history states.
+ RemoveHistoryStates(PipelineId, Vec<HistoryStateId>),
+ /// 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<String>,
+ Option<String>,
+ Option<String>,
+ ),
+ /// 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<WebGPUMsg>),
+}
+
+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.
+///
+/// <http://w3c.github.io/touch-events/#widl-Touch-identifier>
+#[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<f32>,
+ Option<UntrustedNodeAddress>,
+ Option<Point2D<f32>>,
+ // 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<f32>,
+ Option<UntrustedNodeAddress>,
+ // 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<f32>,
+ Option<UntrustedNodeAddress>,
+ ),
+ /// A wheel event was generated with a delta in the X, Y, and/or Z directions
+ WheelEvent(WheelDelta, Point2D<f32>, Option<UntrustedNodeAddress>),
+ /// 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<TimerEvent>,
+ 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<u64, Milliseconds>;
+/// Amount of nanoseconds.
+pub type NsDuration = Length<u64, Nanoseconds>;
+
+/// 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<PipelineId>,
+ /// 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<BrowsingContextId>,
+ /// Loading into a Secure Context
+ pub inherited_secure_context: Option<bool>,
+ /// A channel with which messages can be sent to us (the script thread).
+ pub control_chan: IpcSender<ConstellationControlMsg>,
+ /// A port on which messages sent by the constellation to script can be received.
+ pub control_port: IpcReceiver<ConstellationControlMsg>,
+ /// 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<dyn BackgroundHangMonitorRegister>,
+ /// A sender for the layout thread to communicate to the constellation.
+ pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
+ /// A channel to schedule timer events.
+ pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
+ /// A channel to the resource manager thread.
+ pub resource_threads: ResourceThreads,
+ /// A channel to the bluetooth thread.
+ pub bluetooth_thread: IpcSender<BluetoothRequest>,
+ /// The image cache for this script thread.
+ pub image_cache: Arc<dyn ImageCache>,
+ /// 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<IpcSender<ScriptToDevtoolsControlMsg>>,
+ /// 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<WebGLPipeline>,
+ /// 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<AtomicBool>,
+ /// 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<Self::Message>, Receiver<Self::Message>);
+}
+
+/// 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<bool>,
+ /// 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<PipelineId>,
+ /// 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<f32, LayoutPixel>,
+}
+
+/// 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
+ /// <http://www.w3.org/TR/css-device-adapt/#initial-viewport>
+ pub initial_viewport: Size2D<f32, CSSPixel>,
+
+ /// The resolution of the window in dppx, not including any "pinch zoom" factor.
+ pub device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>,
+}
+
+/// 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<WindowSizeData>),
+ /// Load a URL in the top-level browsing context with the given ID.
+ LoadUrl(TopLevelBrowsingContextId, LoadData, IpcSender<LoadStatus>),
+ /// Refresh the top-level browsing context with the given ID.
+ Refresh(TopLevelBrowsingContextId, IpcSender<LoadStatus>),
+ /// Pass a webdriver command to the script thread of the current pipeline
+ /// of a browsing context.
+ ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
+ /// Act as if keys were pressed in the browsing context with the given ID.
+ SendKeys(BrowsingContextId, Vec<WebDriverInputEvent>),
+ /// Act as if keys were pressed or release in the browsing context with the given ID.
+ KeyboardAction(BrowsingContextId, KeyboardEvent),
+ /// Act as if the mouse was clicked in the browsing context with the given ID.
+ MouseButtonAction(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<WindowSizeData>,
+ ),
+ /// Take a screenshot of the window.
+ TakeScreenshot(
+ TopLevelBrowsingContextId,
+ Option<Rect<f32, CSSPixel>>,
+ IpcSender<Option<Image>>,
+ ),
+}
+
+/// 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,
+ /// Message to send to the scheduler
+ pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
+ /// 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 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<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: Option<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 {
+ /// Execution timed out.
+ Timeout,
+ /// No such worklet.
+ WorkletNotFound,
+}
+
+impl From<RecvTimeoutError> for PaintWorkletError {
+ fn from(_: RecvTimeoutError) -> PaintWorkletError {
+ PaintWorkletError::Timeout
+ }
+}
+
+/// Execute paint code in the worklet thread pool.
+pub trait Painter: SpeculativePainter {
+ /// <https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image>
+ fn draw_a_paint_image(
+ &self,
+ size: Size2D<f32, CSSPixel>,
+ zoom: Scale<f32, CSSPixel, DevicePixel>,
+ properties: Vec<(Atom, String)>,
+ arguments: Vec<String>,
+ ) -> Result<DrawAPaintImageResult, PaintWorkletError>;
+}
+
+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. <https://github.com/servo/servo/issues/17497>
+#[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<ImageKey>,
+ /// 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, 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.
+/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
+#[derive(Debug, 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>>,
+ /// Transferred objects.
+ pub ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
+}
+
+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<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(),
+ }
+ }
+}
+
+/// 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<i32> 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<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 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<WebRenderPipelineId>,
+ WorldPoint,
+ HitTestFlags,
+ IpcSender<Vec<CompositorHitTestResult>>,
+ ),
+ /// Create a new image key. The result will be returned via the
+ /// provided channel sender.
+ GenerateImageKey(IpcSender<ImageKey>),
+ /// Perform a resource update operation.
+ UpdateImages(Vec<SerializedImageUpdate>),
+}
+
+#[derive(Clone, Deserialize, Serialize)]
+/// A mechanism to communicate with the parent process' WebRender instance.
+pub struct WebrenderIpcSender(IpcSender<ScriptToCompositorMsg>);
+
+impl WebrenderIpcSender {
+ /// Create a new WebrenderIpcSender object that wraps the provided channel sender.
+ pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> 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<WebRenderPipelineId>,
+ point: WorldPoint,
+ flags: HitTestFlags,
+ ) -> Vec<CompositorHitTestResult> {
+ 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<ImageKey, ()> {
+ 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<ImageUpdate>) {
+ 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<ImageData, ipc::IpcError> {
+ match self {
+ SerializedImageData::Raw(rx) => rx.recv().map(|data| ImageData::new(data)),
+ SerializedImageData::External(image) => Ok(ImageData::External(image.clone())),
+ }
+ }
+}