aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/compositing/compositor.rs193
-rw-r--r--components/compositing/lib.rs2
-rw-r--r--components/compositing/webview_manager.rs4
-rw-r--r--components/compositing/webview_renderer.rs (renamed from components/compositing/webview.rs)25
-rw-r--r--components/layout/dom.rs2
-rw-r--r--components/script/document_loader.rs14
-rw-r--r--components/script/dom/attr.rs2
-rw-r--r--components/script/dom/bindings/constructor.rs2
-rw-r--r--components/script/dom/bindings/utils.rs13
-rw-r--r--components/script/dom/bindings/xmlname.rs2
-rw-r--r--components/script/dom/create.rs2
-rw-r--r--components/script/dom/customelementregistry.rs2
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs9
-rw-r--r--components/script/dom/document.rs2
-rw-r--r--components/script/dom/domimplementation.rs2
-rw-r--r--components/script/dom/domtokenlist.rs2
-rw-r--r--components/script/dom/element.rs54
-rw-r--r--components/script/dom/globalscope.rs36
-rw-r--r--components/script/dom/htmlaudioelement.rs2
-rw-r--r--components/script/dom/htmlbaseelement.rs2
-rw-r--r--components/script/dom/htmlbodyelement.rs2
-rw-r--r--components/script/dom/htmlbuttonelement.rs2
-rw-r--r--components/script/dom/htmlcanvaselement.rs2
-rw-r--r--components/script/dom/htmldialogelement.rs2
-rw-r--r--components/script/dom/htmlelement.rs2
-rw-r--r--components/script/dom/htmlfontelement.rs2
-rw-r--r--components/script/dom/htmlformelement.rs2
-rw-r--r--components/script/dom/htmlheadelement.rs2
-rw-r--r--components/script/dom/htmlhrelement.rs2
-rw-r--r--components/script/dom/htmlhyperlinkelementutils.rs2
-rw-r--r--components/script/dom/htmliframeelement.rs2
-rw-r--r--components/script/dom/htmlimageelement.rs2
-rw-r--r--components/script/dom/htmlinputelement.rs2
-rw-r--r--components/script/dom/htmllabelelement.rs2
-rw-r--r--components/script/dom/htmllinkelement.rs2
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/htmlmetaelement.rs2
-rw-r--r--components/script/dom/htmlobjectelement.rs2
-rw-r--r--components/script/dom/htmloptionelement.rs2
-rw-r--r--components/script/dom/htmlscriptelement.rs6
-rw-r--r--components/script/dom/htmlslotelement.rs2
-rw-r--r--components/script/dom/htmltablecellelement.rs2
-rw-r--r--components/script/dom/htmltablecolelement.rs2
-rw-r--r--components/script/dom/htmltableelement.rs2
-rw-r--r--components/script/dom/htmltablerowelement.rs2
-rw-r--r--components/script/dom/htmltablesectionelement.rs2
-rw-r--r--components/script/dom/htmltemplateelement.rs2
-rw-r--r--components/script/dom/htmltextareaelement.rs2
-rw-r--r--components/script/dom/htmlvideoelement.rs8
-rw-r--r--components/script/dom/macros.rs26
-rw-r--r--components/script/dom/messageport.rs11
-rw-r--r--components/script/dom/mutationobserver.rs2
-rw-r--r--components/script/dom/node.rs2
-rw-r--r--components/script/dom/readablestream.rs15
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs6
-rw-r--r--components/script/dom/servoparser/async_html.rs4
-rw-r--r--components/script/dom/servoparser/html.rs2
-rw-r--r--components/script/dom/servoparser/mod.rs33
-rw-r--r--components/script/dom/svgelement.rs2
-rw-r--r--components/script/dom/svgsvgelement.rs2
-rw-r--r--components/script/dom/trustedscripturl.rs9
-rw-r--r--components/script/dom/trustedtypepolicy.rs7
-rw-r--r--components/script/dom/trustedtypepolicyfactory.rs122
-rw-r--r--components/script/dom/workerglobalscope.rs6
-rw-r--r--components/script/dom/workletglobalscope.rs12
-rw-r--r--components/script/layout_dom/element.rs2
-rw-r--r--components/script/layout_dom/node.rs2
-rw-r--r--components/script/links.rs2
-rw-r--r--components/script/script_module.rs5
-rw-r--r--components/script/script_thread.rs64
-rw-r--r--components/script/security_manager.rs10
-rw-r--r--components/script/xpath/eval.rs2
-rw-r--r--components/script_bindings/codegen/Bindings.conf2
-rw-r--r--components/script_bindings/codegen/CodegenRust.py13
-rw-r--r--components/script_bindings/import.rs9
-rw-r--r--components/script_bindings/root.rs2
-rw-r--r--components/script_bindings/utils.rs106
-rw-r--r--components/script_bindings/webidls/HTMLScriptElement.webidl4
-rw-r--r--components/script_bindings/webidls/Window.webidl2
-rw-r--r--components/servo/webview.rs4
-rw-r--r--components/shared/compositing/lib.rs2
-rw-r--r--components/shared/constellation/from_script_message.rs6
-rw-r--r--components/shared/constellation/lib.rs35
-rw-r--r--components/shared/constellation/message_port.rs566
-rw-r--r--components/shared/constellation/structured_data/mod.rs91
-rw-r--r--components/shared/constellation/structured_data/serializable.rs314
-rw-r--r--components/shared/constellation/structured_data/transferable.rs172
-rw-r--r--components/shared/embedder/input_events.rs2
88 files changed, 1252 insertions, 866 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 098b22a2b68..4550188a7fa 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -19,7 +19,7 @@ use bitflags::bitflags;
use compositing_traits::display_list::{CompositorDisplayListInfo, HitTestInfo, ScrollTree};
use compositing_traits::rendering_context::RenderingContext;
use compositing_traits::{
- CompositionPipeline, CompositorMsg, ImageUpdate, RendererWebView, SendableFrameTree,
+ CompositionPipeline, CompositorMsg, ImageUpdate, SendableFrameTree, WebViewTrait,
};
use constellation_traits::{AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent};
use crossbeam_channel::{Receiver, Sender};
@@ -54,8 +54,8 @@ use webrender_api::{
};
use crate::InitialCompositorState;
-use crate::webview::{UnknownWebView, WebView};
use crate::webview_manager::WebViewManager;
+use crate::webview_renderer::{UnknownWebView, WebViewRenderer};
#[derive(Debug, PartialEq)]
enum UnableToComposite {
@@ -133,8 +133,8 @@ pub struct IOCompositor {
/// Data that is shared by all WebView renderers.
global: Rc<RefCell<ServoRenderer>>,
- /// Our top-level browsing contexts.
- webviews: WebViewManager<WebView>,
+ /// Our [`WebViewRenderer`]s, one for every `WebView`.
+ webview_renderers: WebViewManager<WebViewRenderer>,
/// Tracks whether or not the view needs to be repainted.
needs_repaint: Cell<RepaintReason>,
@@ -424,7 +424,7 @@ impl IOCompositor {
cursor: Cursor::None,
cursor_pos: DevicePoint::new(0.0, 0.0),
})),
- webviews: WebViewManager::default(),
+ webview_renderers: WebViewManager::default(),
needs_repaint: Cell::default(),
ready_to_save_state: ReadyState::Unknown,
webrender: Some(state.webrender),
@@ -544,9 +544,9 @@ impl IOCompositor {
animation_state,
) => {
let mut throttled = true;
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- throttled =
- webview.change_running_animations_state(pipeline_id, animation_state);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ throttled = webview_renderer
+ .change_running_animations_state(pipeline_id, animation_state);
}
// These operations should eventually happen per-WebView, but they are global now as rendering
@@ -557,8 +557,8 @@ impl IOCompositor {
if !throttled && animation_state == AnimationState::AnimationCallbacksPresent {
// We need to fetch the WebView again in order to avoid a double borrow.
- if let Some(webview) = self.webviews.get(webview_id) {
- webview.tick_animations_for_pipeline(pipeline_id, self);
+ if let Some(webview_renderer) = self.webview_renderers.get(webview_id) {
+ webview_renderer.tick_animations_for_pipeline(pipeline_id, self);
}
}
},
@@ -572,11 +572,11 @@ impl IOCompositor {
},
CompositorMsg::TouchEventProcessed(webview_id, result) => {
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
warn!("Handling input event for unknown webview: {webview_id}");
return;
};
- webview.on_touch_event_processed(result);
+ webview_renderer.on_touch_event_processed(result);
},
CompositorMsg::CreatePng(webview_id, page_rect, reply) => {
@@ -604,8 +604,8 @@ impl IOCompositor {
},
CompositorMsg::SetThrottled(webview_id, pipeline_id, throttled) => {
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.set_throttled(pipeline_id, throttled);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.set_throttled(pipeline_id, throttled);
self.process_animations(true);
}
},
@@ -615,8 +615,8 @@ impl IOCompositor {
"Compositor got pipeline exited: {:?} {:?}",
webview_id, pipeline_id
);
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.remove_pipeline(pipeline_id);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.remove_pipeline(pipeline_id);
}
let _ = sender.send(());
},
@@ -648,13 +648,13 @@ impl IOCompositor {
},
CompositorMsg::WebDriverMouseButtonEvent(webview_id, action, button, x, y) => {
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
warn!("Handling input event for unknown webview: {webview_id}");
return;
};
- let dppx = webview.device_pixels_per_page_pixel();
+ let dppx = webview_renderer.device_pixels_per_page_pixel();
let point = dppx.transform_point(Point2D::new(x, y));
- webview.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent {
+ webview_renderer.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent {
point,
action,
button,
@@ -662,13 +662,14 @@ impl IOCompositor {
},
CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y) => {
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
warn!("Handling input event for unknown webview: {webview_id}");
return;
};
- let dppx = webview.device_pixels_per_page_pixel();
+ let dppx = webview_renderer.device_pixels_per_page_pixel();
let point = dppx.transform_point(Point2D::new(x, y));
- webview.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
+ webview_renderer
+ .dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
},
CompositorMsg::SendInitialTransaction(pipeline) => {
@@ -679,12 +680,13 @@ impl IOCompositor {
},
CompositorMsg::SendScrollNode(webview_id, pipeline_id, point, external_scroll_id) => {
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
return;
};
let pipeline_id = pipeline_id.into();
- let Some(pipeline_details) = webview.pipelines.get_mut(&pipeline_id) else {
+ let Some(pipeline_details) = webview_renderer.pipelines.get_mut(&pipeline_id)
+ else {
return;
};
@@ -771,12 +773,12 @@ impl IOCompositor {
)
.entered();
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
return warn!("Could not find WebView for incoming display list");
};
let pipeline_id = display_list_info.pipeline_id;
- let details = webview.ensure_pipeline_details(pipeline_id.into());
+ let details = webview_renderer.ensure_pipeline_details(pipeline_id.into());
details.most_recent_display_list_epoch = Some(display_list_info.epoch);
details.hit_test_items = display_list_info.hit_test_info;
details.install_new_scroll_tree(display_list_info.scroll_tree);
@@ -900,9 +902,11 @@ impl IOCompositor {
},
CompositorMsg::GetClientWindowRect(webview_id, response_sender) => {
let client_window_rect = self
- .webviews
+ .webview_renderers
.get(webview_id)
- .map(|webview| webview.client_window_rect(self.rendering_context.size2d()))
+ .map(|webview_renderer| {
+ webview_renderer.client_window_rect(self.rendering_context.size2d())
+ })
.unwrap_or_default();
if let Err(error) = response_sender.send(client_window_rect) {
warn!("Sending response to get client window failed ({error:?}).");
@@ -910,9 +914,9 @@ impl IOCompositor {
},
CompositorMsg::GetScreenSize(webview_id, response_sender) => {
let screen_size = self
- .webviews
+ .webview_renderers
.get(webview_id)
- .map(WebView::screen_size)
+ .map(WebViewRenderer::screen_size)
.unwrap_or_default();
if let Err(error) = response_sender.send(screen_size) {
warn!("Sending response to get screen size failed ({error:?}).");
@@ -920,9 +924,9 @@ impl IOCompositor {
},
CompositorMsg::GetAvailableScreenSize(webview_id, response_sender) => {
let available_screen_size = self
- .webviews
+ .webview_renderers
.get(webview_id)
- .map(WebView::available_screen_size)
+ .map(WebViewRenderer::available_screen_size)
.unwrap_or_default();
if let Err(error) = response_sender.send(available_screen_size) {
warn!("Sending response to get screen size failed ({error:?}).");
@@ -947,8 +951,8 @@ impl IOCompositor {
"Compositor got pipeline exited: {:?} {:?}",
webview_id, pipeline_id
);
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.remove_pipeline(pipeline_id);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.remove_pipeline(pipeline_id);
}
let _ = sender.send(());
},
@@ -1040,12 +1044,12 @@ impl IOCompositor {
let root_clip_id = builder.define_clip_rect(root_reference_frame, viewport_rect);
let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
- for (_, webview) in self.webviews.painting_order() {
- let Some(pipeline_id) = webview.root_pipeline_id else {
+ for (_, webview_renderer) in self.webview_renderers.painting_order() {
+ let Some(pipeline_id) = webview_renderer.root_pipeline_id else {
continue;
};
- let device_pixels_per_page_pixel = webview.device_pixels_per_page_pixel().0;
+ let device_pixels_per_page_pixel = webview_renderer.device_pixels_per_page_pixel().0;
let webview_reference_frame = builder.push_reference_frame(
LayoutPoint::zero(),
root_reference_frame,
@@ -1063,7 +1067,7 @@ impl IOCompositor {
SpatialTreeItemKey::new(0, 0),
);
- let scaled_webview_rect = webview.rect / device_pixels_per_page_pixel;
+ let scaled_webview_rect = webview_renderer.rect / device_pixels_per_page_pixel;
builder.push_iframe(
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
@@ -1094,8 +1098,8 @@ impl IOCompositor {
/// TODO(mrobinson): Could we only send offsets for the branch being modified
/// and not the entire scene?
fn update_transaction_with_all_scroll_offsets(&self, transaction: &mut Transaction) {
- for webview in self.webviews.iter() {
- for details in webview.pipelines.values() {
+ for webview_renderer in self.webview_renderers.iter() {
+ for details in webview_renderer.pipelines.values() {
for node in details.scroll_tree.nodes.iter() {
let (Some(offset), Some(external_id)) = (node.offset(), node.external_id())
else {
@@ -1117,34 +1121,36 @@ impl IOCompositor {
pub fn add_webview(
&mut self,
- webview: Box<dyn RendererWebView>,
+ webview: Box<dyn WebViewTrait>,
viewport_details: ViewportDetails,
) {
- self.webviews.entry(webview.id()).or_insert(WebView::new(
- self.global.clone(),
- webview,
- viewport_details,
- ));
+ self.webview_renderers
+ .entry(webview.id())
+ .or_insert(WebViewRenderer::new(
+ self.global.clone(),
+ webview,
+ viewport_details,
+ ));
}
fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) {
debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
let webview_id = frame_tree.pipeline.webview_id;
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
warn!(
"Attempted to set frame tree on unknown WebView (perhaps closed?): {webview_id:?}"
);
return;
};
- webview.set_frame_tree(frame_tree);
+ webview_renderer.set_frame_tree(frame_tree);
self.send_root_pipeline_display_list();
}
fn remove_webview(&mut self, webview_id: WebViewId) {
debug!("{}: Removing", webview_id);
- if self.webviews.remove(webview_id).is_err() {
+ if self.webview_renderers.remove(webview_id).is_err() {
warn!("{webview_id}: Removing unknown webview");
return;
};
@@ -1160,15 +1166,15 @@ impl IOCompositor {
debug!("{webview_id}: Showing webview; hide_others={hide_others}");
let painting_order_changed = if hide_others {
let result = self
- .webviews
+ .webview_renderers
.painting_order()
.map(|(&id, _)| id)
.ne(once(webview_id));
- self.webviews.hide_all();
- self.webviews.show(webview_id)?;
+ self.webview_renderers.hide_all();
+ self.webview_renderers.show(webview_id)?;
result
} else {
- self.webviews.show(webview_id)?
+ self.webview_renderers.show(webview_id)?
};
if painting_order_changed {
self.send_root_pipeline_display_list();
@@ -1178,7 +1184,7 @@ impl IOCompositor {
pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
debug!("{webview_id}: Hiding webview");
- if self.webviews.hide(webview_id)? {
+ if self.webview_renderers.hide(webview_id)? {
self.send_root_pipeline_display_list();
}
Ok(())
@@ -1192,15 +1198,15 @@ impl IOCompositor {
debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
let painting_order_changed = if hide_others {
let result = self
- .webviews
+ .webview_renderers
.painting_order()
.map(|(&id, _)| id)
.ne(once(webview_id));
- self.webviews.hide_all();
- self.webviews.raise_to_top(webview_id)?;
+ self.webview_renderers.hide_all();
+ self.webview_renderers.raise_to_top(webview_id)?;
result
} else {
- self.webviews.raise_to_top(webview_id)?
+ self.webview_renderers.raise_to_top(webview_id)?
};
if painting_order_changed {
self.send_root_pipeline_display_list();
@@ -1212,10 +1218,10 @@ impl IOCompositor {
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
return;
}
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
return;
};
- if !webview.set_rect(rect) {
+ if !webview_renderer.set_rect(rect) {
return;
}
@@ -1231,10 +1237,10 @@ impl IOCompositor {
if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown {
return;
}
- let Some(webview) = self.webviews.get_mut(webview_id) else {
+ let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else {
return;
};
- if !webview.set_hidpi_scale_factor(new_scale_factor) {
+ if !webview_renderer.set_hidpi_scale_factor(new_scale_factor) {
return;
}
@@ -1277,8 +1283,8 @@ impl IOCompositor {
}
self.last_animation_tick = Instant::now();
- for webview in self.webviews.iter() {
- webview.tick_all_animations(self);
+ for webview_renderer in self.webview_renderers.iter() {
+ webview_renderer.tick_all_animations(self);
}
}
@@ -1287,8 +1293,8 @@ impl IOCompositor {
return;
}
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.set_page_zoom(1.0);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.set_page_zoom(1.0);
}
self.send_root_pipeline_display_list();
}
@@ -1298,8 +1304,8 @@ impl IOCompositor {
return;
}
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.set_page_zoom(magnification);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.set_page_zoom(magnification);
}
self.send_root_pipeline_display_list();
}
@@ -1311,21 +1317,24 @@ impl IOCompositor {
.pipeline_to_webview_map
.get(&pipeline_id)
.cloned()?;
- self.webviews.get(webview_id)?.pipelines.get(&pipeline_id)
+ self.webview_renderers
+ .get(webview_id)?
+ .pipelines
+ .get(&pipeline_id)
}
// Check if any pipelines currently have active animations or animation callbacks.
fn animations_or_animation_callbacks_running(&self) -> bool {
- self.webviews
+ self.webview_renderers
.iter()
- .any(WebView::animations_or_animation_callbacks_running)
+ .any(WebViewRenderer::animations_or_animation_callbacks_running)
}
/// Returns true if any animation callbacks (ie `requestAnimationFrame`) are waiting for a response.
fn animation_callbacks_running(&self) -> bool {
- self.webviews
+ self.webview_renderers
.iter()
- .any(WebView::animation_callbacks_running)
+ .any(WebViewRenderer::animation_callbacks_running)
}
/// Query the constellation to see if the current compositor
@@ -1341,7 +1350,11 @@ impl IOCompositor {
// This gets sent to the constellation for comparison with the current
// frame tree.
let mut pipeline_epochs = HashMap::new();
- for id in self.webviews.iter().flat_map(WebView::pipeline_ids) {
+ for id in self
+ .webview_renderers
+ .iter()
+ .flat_map(WebViewRenderer::pipeline_ids)
+ {
if let Some(WebRenderEpoch(epoch)) = self
.webrender
.as_ref()
@@ -1408,9 +1421,9 @@ impl IOCompositor {
let size = self.rendering_context.size2d().to_i32();
let rect = if let Some(rect) = page_rect {
let scale = self
- .webviews
+ .webview_renderers
.get(webview_id)
- .map(WebView::device_pixels_per_page_pixel)
+ .map(WebViewRenderer::device_pixels_per_page_pixel)
.unwrap_or_else(|| Scale::new(1.0));
let rect = scale.transform_rect(&rect);
@@ -1507,8 +1520,8 @@ impl IOCompositor {
fn send_pending_paint_metrics_messages_after_composite(&mut self) {
let paint_time = CrossProcessInstant::now();
let document_id = self.webrender_document();
- for webview_details in self.webviews.iter_mut() {
- for (pipeline_id, pipeline) in webview_details.pipelines.iter_mut() {
+ for webview_renderer in self.webview_renderers.iter_mut() {
+ for (pipeline_id, pipeline) in webview_renderer.pipelines.iter_mut() {
let Some(current_epoch) = self
.webrender
.as_ref()
@@ -1646,11 +1659,11 @@ impl IOCompositor {
if let Err(err) = self.rendering_context.make_current() {
warn!("Failed to make the rendering context current: {:?}", err);
}
- let mut webviews = take(&mut self.webviews);
- for webview in webviews.iter_mut() {
- webview.process_pending_scroll_events(self);
+ let mut webview_renderers = take(&mut self.webview_renderers);
+ for webview_renderer in webview_renderers.iter_mut() {
+ webview_renderer.process_pending_scroll_events(self);
}
- self.webviews = webviews;
+ self.webview_renderers = webview_renderers;
self.global.borrow().shutdown_state() != ShutdownState::FinishedShuttingDown
}
@@ -1735,8 +1748,8 @@ impl IOCompositor {
}
pub fn notify_input_event(&mut self, webview_id: WebViewId, event: InputEvent) {
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.notify_input_event(event);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.notify_input_event(event);
}
}
@@ -1747,20 +1760,20 @@ impl IOCompositor {
cursor: DeviceIntPoint,
event_type: TouchEventType,
) {
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.notify_scroll_event(scroll_location, cursor, event_type);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.notify_scroll_event(scroll_location, cursor, event_type);
}
}
pub fn on_vsync(&mut self, webview_id: WebViewId) {
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.on_vsync();
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.on_vsync();
}
}
pub fn set_pinch_zoom(&mut self, webview_id: WebViewId, magnification: f32) {
- if let Some(webview) = self.webviews.get_mut(webview_id) {
- webview.set_pinch_zoom(magnification);
+ if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) {
+ webview_renderer.set_pinch_zoom(magnification);
}
}
diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs
index 65bd18929e1..a66c61499e5 100644
--- a/components/compositing/lib.rs
+++ b/components/compositing/lib.rs
@@ -23,8 +23,8 @@ mod tracing;
mod compositor;
mod touch;
-pub mod webview;
pub mod webview_manager;
+pub mod webview_renderer;
/// Data used to construct a compositor.
pub struct InitialCompositorState {
diff --git a/components/compositing/webview_manager.rs b/components/compositing/webview_manager.rs
index 1f1ced3a468..42e9bfe1cb7 100644
--- a/components/compositing/webview_manager.rs
+++ b/components/compositing/webview_manager.rs
@@ -7,7 +7,7 @@ use std::collections::hash_map::{Entry, Values, ValuesMut};
use base::id::WebViewId;
-use crate::webview::UnknownWebView;
+use crate::webview_renderer::UnknownWebView;
#[derive(Debug)]
pub struct WebViewManager<WebView> {
@@ -117,8 +117,8 @@ mod test {
BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId, WebViewId,
};
- use crate::webview::UnknownWebView;
use crate::webview_manager::WebViewManager;
+ use crate::webview_renderer::UnknownWebView;
fn top_level_id(namespace_id: u32, index: u32) -> WebViewId {
WebViewId(BrowsingContextId {
diff --git a/components/compositing/webview.rs b/components/compositing/webview_renderer.rs
index cc6b030a05e..6ad77d46043 100644
--- a/components/compositing/webview.rs
+++ b/components/compositing/webview_renderer.rs
@@ -8,7 +8,7 @@ use std::collections::hash_map::Keys;
use std::rc::Rc;
use base::id::{PipelineId, WebViewId};
-use compositing_traits::{RendererWebView, SendableFrameTree};
+use compositing_traits::{SendableFrameTree, WebViewTrait};
use constellation_traits::{EmbedderToConstellationMessage, ScrollState, WindowSizeType};
use embedder_traits::{
AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction,
@@ -55,13 +55,16 @@ enum ScrollZoomEvent {
Scroll(ScrollEvent),
}
-pub(crate) struct WebView {
+/// A renderer for a libservo `WebView`. This is essentially the [`ServoRenderer`]'s interface to a
+/// libservo `WebView`, but the code here cannot depend on libservo in order to prevent circular
+/// dependencies, which is why we store a `dyn WebViewTrait` here instead of the `WebView` itself.
+pub(crate) struct WebViewRenderer {
/// The [`WebViewId`] of the `WebView` associated with this [`WebViewDetails`].
pub id: WebViewId,
/// The renderer's view of the embedding layer `WebView` as a trait implementation,
/// so that the renderer doesn't need to depend on the embedding layer. This avoids
/// a dependency cycle.
- pub renderer_webview: Box<dyn RendererWebView>,
+ pub webview: Box<dyn WebViewTrait>,
/// The root [`PipelineId`] of the currently displayed page in this WebView.
pub root_pipeline_id: Option<PipelineId>,
pub rect: DeviceRect,
@@ -85,7 +88,7 @@ pub(crate) struct WebView {
hidpi_scale_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
}
-impl Drop for WebView {
+impl Drop for WebViewRenderer {
fn drop(&mut self) {
self.global
.borrow_mut()
@@ -94,17 +97,17 @@ impl Drop for WebView {
}
}
-impl WebView {
+impl WebViewRenderer {
pub(crate) fn new(
global: Rc<RefCell<ServoRenderer>>,
- renderer_webview: Box<dyn RendererWebView>,
+ renderer_webview: Box<dyn WebViewTrait>,
viewport_details: ViewportDetails,
) -> Self {
let hidpi_scale_factor = viewport_details.hidpi_scale_factor;
let size = viewport_details.size * viewport_details.hidpi_scale_factor;
Self {
id: renderer_webview.id(),
- renderer_webview,
+ webview: renderer_webview,
root_pipeline_id: None,
rect: DeviceRect::from_origin_and_size(DevicePoint::origin(), size),
pipelines: Default::default(),
@@ -269,7 +272,7 @@ impl WebView {
};
let animating = self.pipelines.values().any(PipelineDetails::animating);
- self.renderer_webview.set_animating(animating);
+ self.webview.set_animating(animating);
throttled
}
@@ -954,7 +957,7 @@ impl WebView {
&self,
rendering_context_size: Size2D<u32, DevicePixel>,
) -> Box2D<i32, DeviceIndependentPixel> {
- let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
+ let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
let rect = DeviceIntRect::from_origin_and_size(
screen_geometry.offset,
rendering_context_size.to_i32(),
@@ -965,12 +968,12 @@ impl WebView {
}
pub(crate) fn screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
- let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
+ let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
(screen_geometry.size.to_f32() / self.hidpi_scale_factor).to_i32()
}
pub(crate) fn available_screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
- let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default();
+ let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
(screen_geometry.available_size.to_f32() / self.hidpi_scale_factor).to_i32()
}
}
diff --git a/components/layout/dom.rs b/components/layout/dom.rs
index 39cd74293c8..6db4dbccd41 100644
--- a/components/layout/dom.rs
+++ b/components/layout/dom.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use base::id::{BrowsingContextId, PipelineId};
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use pixels::Image;
use script_layout_interface::wrapper_traits::{
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs
index 422652272b6..33f51cd8517 100644
--- a/components/script/document_loader.rs
+++ b/components/script/document_loader.rs
@@ -50,10 +50,18 @@ impl LoadBlocker {
/// Remove this load from the associated document's list of blocking loads.
pub(crate) fn terminate(blocker: &DomRefCell<Option<LoadBlocker>>, can_gc: CanGc) {
- if let Some(this) = blocker.borrow().as_ref() {
- let load_data = this.load.clone().unwrap();
- this.doc.finish_load(load_data, can_gc);
+ let Some(load) = blocker
+ .borrow_mut()
+ .as_mut()
+ .and_then(|blocker| blocker.load.take())
+ else {
+ return;
+ };
+
+ if let Some(blocker) = blocker.borrow().as_ref() {
+ blocker.doc.finish_load(load, can_gc);
}
+
*blocker.borrow_mut() = None;
}
}
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 9b33213335e..52d0ca7e20c 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -8,7 +8,7 @@ use std::mem;
use devtools_traits::AttrInfo;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Namespace, Prefix, namespace_url, ns};
+use html5ever::{LocalName, Namespace, Prefix, ns};
use style::attr::{AttrIdentifier, AttrValue};
use style::values::GenericAtomIdent;
use stylo_atoms::Atom;
diff --git a/components/script/dom/bindings/constructor.rs b/components/script/dom/bindings/constructor.rs
index 138dd4520d0..141fb8c1391 100644
--- a/components/script/dom/bindings/constructor.rs
+++ b/components/script/dom/bindings/constructor.rs
@@ -5,7 +5,7 @@
use std::ptr;
use html5ever::interface::QualName;
-use html5ever::{LocalName, local_name, namespace_url, ns};
+use html5ever::{LocalName, local_name, ns};
use js::conversions::ToJSValConvertible;
use js::glue::{UnwrapObjectDynamic, UnwrapObjectStatic};
use js::jsapi::{CallArgs, CurrentGlobalOrNull, JSAutoRealm, JSObject};
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index f8edab1879d..ba7db745832 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -118,6 +118,19 @@ pub(crate) const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
};
+/// Eagerly define all relevant WebIDL interface constructors on the
+/// provided global object.
+pub(crate) fn define_all_exposed_interfaces(
+ global: &GlobalScope,
+ _in_realm: InRealm,
+ _can_gc: CanGc,
+) {
+ let cx = GlobalScope::get_cx();
+ for (_, interface) in &InterfaceObjectMap::MAP {
+ (interface.define)(cx, global.reflector().get_jsobject());
+ }
+}
+
impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
fn throw_dom_exception(
cx: SafeJSContext,
diff --git a/components/script/dom/bindings/xmlname.rs b/components/script/dom/bindings/xmlname.rs
index 31436278c12..af02569d9c4 100644
--- a/components/script/dom/bindings/xmlname.rs
+++ b/components/script/dom/bindings/xmlname.rs
@@ -4,7 +4,7 @@
//! Functions for validating and extracting qualified XML names.
-use html5ever::{LocalName, Namespace, Prefix, namespace_url, ns};
+use html5ever::{LocalName, Namespace, Prefix, ns};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::str::DOMString;
diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs
index c2e038eb66b..5722dc4f6ac 100644
--- a/components/script/dom/create.rs
+++ b/components/script/dom/create.rs
@@ -2,7 +2,7 @@
* 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/. */
-use html5ever::{LocalName, Prefix, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, QualName, local_name, ns};
use js::rust::HandleObject;
use servo_config::pref;
diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs
index 049e3c482a1..be672585529 100644
--- a/components/script/dom/customelementregistry.rs
+++ b/components/script/dom/customelementregistry.rs
@@ -9,7 +9,7 @@ use std::rc::Rc;
use std::{mem, ptr};
use dom_struct::dom_struct;
-use html5ever::{LocalName, Namespace, Prefix, namespace_url, ns};
+use html5ever::{LocalName, Namespace, Prefix, ns};
use js::conversions::ToJSValConvertible;
use js::glue::UnwrapObjectStatic;
use js::jsapi::{HandleValueArray, Heap, IsCallable, IsConstructor, JSAutoRealm, JSObject};
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index b014a85701b..972a9d90948 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -42,6 +42,7 @@ use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
+use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventtarget::EventTarget;
@@ -478,6 +479,7 @@ impl DedicatedWorkerGlobalScope {
Ok((metadata, bytes)) => (metadata, bytes),
};
scope.set_url(metadata.final_url);
+ scope.set_csp_list(GlobalScope::parse_csp_list_from_metadata(&metadata.headers));
global_scope.set_https_state(metadata.https_state);
let source = String::from_utf8_lossy(&bytes);
@@ -493,7 +495,12 @@ impl DedicatedWorkerGlobalScope {
{
let _ar = AutoWorkerReset::new(&global, worker.clone());
- let _ac = enter_realm(scope);
+ let realm = enter_realm(scope);
+ define_all_exposed_interfaces(
+ global.upcast(),
+ InRealm::entered(&realm),
+ CanGc::note(),
+ );
scope.execute_script(DOMString::from(source), CanGc::note());
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 0d39a12c15e..852a12fc7c5 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -37,7 +37,7 @@ use embedder_traits::{
};
use encoding_rs::{Encoding, UTF_8};
use euclid::default::{Point2D, Rect, Size2D};
-use html5ever::{LocalName, Namespace, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Namespace, QualName, local_name, ns};
use hyper_serde::Serde;
use ipc_channel::ipc;
use js::rust::{HandleObject, HandleValue};
diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs
index 521febc17fc..a6c95fad820 100644
--- a/components/script/dom/domimplementation.rs
+++ b/components/script/dom/domimplementation.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use script_traits::DocumentActivity;
use crate::document_loader::DocumentLoader;
diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs
index 8d479aba80d..83c3d09be23 100644
--- a/components/script/dom/domtokenlist.rs
+++ b/components/script/dom/domtokenlist.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, namespace_url, ns};
+use html5ever::{LocalName, ns};
use style::str::HTML_SPACE_CHARACTERS;
use stylo_atoms::Atom;
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 4aebe893bef..3a8ac8f0cd8 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -19,9 +19,7 @@ use embedder_traits::InputMethodType;
use euclid::default::{Rect, Size2D};
use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
-use html5ever::{
- LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, namespace_url, ns,
-};
+use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
use js::jsapi::Heap;
use js::jsval::JSVal;
use js::rust::HandleObject;
@@ -80,7 +78,7 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
use crate::dom::bindings::codegen::Bindings::WindowBinding::{
ScrollBehavior, ScrollToOptions, WindowMethods,
};
-use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
+use crate::dom::bindings::codegen::UnionTypes::{NodeOrString, TrustedScriptURLOrUSVString};
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
@@ -151,6 +149,7 @@ use crate::dom::raredata::ElementRareData;
use crate::dom::servoparser::ServoParser;
use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
use crate::dom::text::Text;
+use crate::dom::types::TrustedTypePolicyFactory;
use crate::dom::validation::Validatable;
use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -1930,6 +1929,53 @@ impl Element {
self.set_attribute(local_name, AttrValue::String(value.to_string()), can_gc);
}
+ pub(crate) fn get_trusted_type_url_attribute(
+ &self,
+ local_name: &LocalName,
+ ) -> TrustedScriptURLOrUSVString {
+ assert_eq!(*local_name, local_name.to_ascii_lowercase());
+ let attr = match self.get_attribute(&ns!(), local_name) {
+ Some(attr) => attr,
+ None => return TrustedScriptURLOrUSVString::USVString(USVString::default()),
+ };
+ let value = &**attr.value();
+ // XXXManishearth this doesn't handle `javascript:` urls properly
+ self.owner_document()
+ .base_url()
+ .join(value)
+ .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
+ .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
+ }
+
+ pub(crate) fn set_trusted_type_url_attribute(
+ &self,
+ local_name: &LocalName,
+ value: TrustedScriptURLOrUSVString,
+ can_gc: CanGc,
+ ) -> Fallible<()> {
+ assert_eq!(*local_name, local_name.to_ascii_lowercase());
+ let value = match value {
+ TrustedScriptURLOrUSVString::USVString(url) => {
+ let global = self.owner_global();
+ // TODO(36258): Reflectively get the name of the class
+ let sink = format!("{} {}", "HTMLScriptElement", &local_name);
+ let result = TrustedTypePolicyFactory::get_trusted_type_compliant_string(
+ &global,
+ url.to_string(),
+ &sink,
+ "'script'",
+ can_gc,
+ );
+ result?
+ },
+ // This partially implements <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
+ // Step 1: If input is an instance of expectedType, return stringified input and abort these steps.
+ TrustedScriptURLOrUSVString::TrustedScriptURL(script_url) => script_url.to_string(),
+ };
+ self.set_attribute(local_name, AttrValue::String(value), can_gc);
+ Ok(())
+ }
+
pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
match self.get_attribute(&ns!(), local_name) {
Some(x) => x.Value(),
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 2582291ed87..2658911c795 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -22,7 +22,7 @@ use constellation_traits::{
ScriptToConstellationChan, ScriptToConstellationMessage,
};
use content_security_policy::{
- CheckResult, CspList, PolicyDisposition, Violation, ViolationResource,
+ CheckResult, CspList, PolicyDisposition, PolicySource, Violation, ViolationResource,
};
use crossbeam_channel::Sender;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
@@ -30,6 +30,8 @@ use dom_struct::dom_struct;
use embedder_traits::{
EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects, GamepadUpdateType,
};
+use http::HeaderMap;
+use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use js::glue::{IsWrapper, UnwrapObjectDynamic};
@@ -2415,6 +2417,27 @@ impl GlobalScope {
unreachable!();
}
+ /// <https://www.w3.org/TR/CSP/#initialize-document-csp>
+ pub(crate) fn parse_csp_list_from_metadata(
+ headers: &Option<Serde<HeaderMap>>,
+ ) -> Option<CspList> {
+ // TODO: Implement step 1 (local scheme special case)
+ let mut csp = headers.as_ref()?.get_all("content-security-policy").iter();
+ // This silently ignores the CSP if it contains invalid Unicode.
+ // We should probably report an error somewhere.
+ let c = csp.next().and_then(|c| c.to_str().ok())?;
+ let mut csp_list = CspList::parse(c, PolicySource::Header, PolicyDisposition::Enforce);
+ for c in csp {
+ let c = c.to_str().ok()?;
+ csp_list.append(CspList::parse(
+ c,
+ PolicySource::Header,
+ PolicyDisposition::Enforce,
+ ));
+ }
+ Some(csp_list)
+ }
+
/// Get the [base url](https://html.spec.whatwg.org/multipage/#api-base-url)
/// for this global scope.
pub(crate) fn api_base_url(&self) -> ServoUrl {
@@ -3089,10 +3112,10 @@ impl GlobalScope {
/// <https://www.w3.org/TR/CSP/#get-csp-of-object>
pub(crate) fn get_csp_list(&self) -> Option<CspList> {
- if self.downcast::<Window>().is_some() {
+ if self.downcast::<Window>().is_some() || self.downcast::<WorkerGlobalScope>().is_some() {
return self.policy_container().csp_list;
}
- // TODO: Worker and Worklet global scopes.
+ // TODO: Worklet global scopes.
None
}
@@ -3352,7 +3375,7 @@ impl GlobalScope {
let data = structuredclone::write(cx, value, Some(guard))?;
- structuredclone::read(self, data, retval).map_err(|_| Error::DataClone(None))?;
+ structuredclone::read(self, data, retval)?;
Ok(())
}
@@ -3456,11 +3479,16 @@ impl GlobalScope {
ViolationResource::TrustedTypePolicy { sample } => {
(Some(sample), "trusted-types-policy".to_owned())
},
+ ViolationResource::TrustedTypeSink { sample } => {
+ (Some(sample), "trusted-types-sink".to_owned())
+ },
};
let report = CSPViolationReportBuilder::default()
.resource(resource)
.sample(sample)
.effective_directive(violation.directive.name)
+ .original_policy(violation.policy.to_string())
+ .report_only(violation.policy.disposition == PolicyDisposition::Report)
.build(self);
let task = CSPViolationReportTask::new(self, report);
self.task_manager()
diff --git a/components/script/dom/htmlaudioelement.rs b/components/script/dom/htmlaudioelement.rs
index dbf0a88eb2a..938c2e7ccd6 100644
--- a/components/script/dom/htmlaudioelement.rs
+++ b/components/script/dom/htmlaudioelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, QualName, local_name, ns};
use js::rust::HandleObject;
use crate::dom::bindings::codegen::Bindings::ElementBinding::Element_Binding::ElementMethods;
diff --git a/components/script/dom/htmlbaseelement.rs b/components/script/dom/htmlbaseelement.rs
index 45a13f83772..9f263e1056c 100644
--- a/components/script/dom/htmlbaseelement.rs
+++ b/components/script/dom/htmlbaseelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use servo_url::ServoUrl;
diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs
index 5cd877cdf82..b4efba9bed9 100644
--- a/components/script/dom/htmlbodyelement.rs
+++ b/components/script/dom/htmlbodyelement.rs
@@ -4,7 +4,7 @@
use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, LoadStatus};
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use servo_url::ServoUrl;
use style::attr::AttrValue;
diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs
index 09d0ae6e73f..6f83360e187 100644
--- a/components/script/dom/htmlbuttonelement.rs
+++ b/components/script/dom/htmlbuttonelement.rs
@@ -6,7 +6,7 @@ use std::cell::Cell;
use std::default::Default;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url};
+use html5ever::{LocalName, Prefix, local_name};
use js::rust::HandleObject;
use stylo_dom::ElementState;
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 77e8b412146..9e20539ceca 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -12,7 +12,7 @@ use constellation_traits::BlobImpl;
use constellation_traits::ScriptToConstellationMessage;
use dom_struct::dom_struct;
use euclid::default::Size2D;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use image::codecs::jpeg::JpegEncoder;
use image::codecs::png::PngEncoder;
use image::codecs::webp::WebPEncoder;
diff --git a/components/script/dom/htmldialogelement.rs b/components/script/dom/htmldialogelement.rs
index 3872932049d..fbd84e4efd3 100644
--- a/components/script/dom/htmldialogelement.rs
+++ b/components/script/dom/htmldialogelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use crate::dom::bindings::cell::DomRefCell;
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index 0cdfebf5342..9505d5182c7 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -7,7 +7,7 @@ use std::default::Default;
use std::rc::Rc;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use script_layout_interface::QueryMsg;
use style::attr::AttrValue;
diff --git a/components/script/dom/htmlfontelement.rs b/components/script/dom/htmlfontelement.rs
index ee7015fb66d..fb02a10a4e4 100644
--- a/components/script/dom/htmlfontelement.rs
+++ b/components/script/dom/htmlfontelement.rs
@@ -4,7 +4,7 @@
use cssparser::match_ignore_ascii_case;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::AttrValue;
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index 1294e11043a..ce6dcca66f3 100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -9,7 +9,7 @@ use constellation_traits::{LoadData, LoadOrigin, NavigationHistoryBehavior};
use dom_struct::dom_struct;
use encoding_rs::{Encoding, UTF_8};
use headers::{ContentType, HeaderMapExt};
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use http::Method;
use js::rust::HandleObject;
use mime::{self, Mime};
diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs
index b4845fc949c..7b2d715318f 100644
--- a/components/script/dom/htmlheadelement.rs
+++ b/components/script/dom/htmlheadelement.rs
@@ -4,7 +4,7 @@
use content_security_policy::{CspList, PolicyDisposition, PolicySource};
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
diff --git a/components/script/dom/htmlhrelement.rs b/components/script/dom/htmlhrelement.rs
index 5754b2f3dd3..c88a0fcf184 100644
--- a/components/script/dom/htmlhrelement.rs
+++ b/components/script/dom/htmlhrelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmlhyperlinkelementutils.rs b/components/script/dom/htmlhyperlinkelementutils.rs
index 52b16f796e5..699db4d62f4 100644
--- a/components/script/dom/htmlhyperlinkelementutils.rs
+++ b/components/script/dom/htmlhyperlinkelementutils.rs
@@ -2,7 +2,7 @@
* 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/. */
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use servo_url::ServoUrl;
use crate::dom::bindings::cell::DomRefCell;
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 33457cb29d4..c5194c4527f 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -13,7 +13,7 @@ use constellation_traits::{
};
use dom_struct::dom_struct;
use embedder_traits::ViewportDetails;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use net_traits::ReferrerPolicy;
use profile_traits::ipc as ProfiledIpc;
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index e6b4336fe54..adff445ae1c 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -14,7 +14,7 @@ use content_security_policy as csp;
use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct;
use euclid::Point2D;
-use html5ever::{LocalName, Prefix, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, QualName, local_name, ns};
use js::jsapi::JSAutoRealm;
use js::rust::HandleObject;
use mime::{self, Mime};
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 42165499032..1999c7193ff 100644
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -14,7 +14,7 @@ use std::{f64, ptr};
use dom_struct::dom_struct;
use embedder_traits::{FilterPattern, InputMethodType};
use encoding_rs::Encoding;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::jsapi::{
ClippedTime, DateGetMsecSinceEpoch, Handle, JS_ClearPendingException, JSObject, NewDateObject,
NewUCRegExpObject, ObjectIsDate, RegExpFlag_UnicodeSets, RegExpFlags,
diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs
index efa386c7cdd..9733c3b7c6e 100644
--- a/components/script/dom/htmllabelelement.rs
+++ b/components/script/dom/htmllabelelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::AttrValue;
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs
index 969551f98c8..db5c14af450 100644
--- a/components/script/dom/htmllinkelement.rs
+++ b/components/script/dom/htmllinkelement.rs
@@ -10,7 +10,7 @@ use base::id::WebViewId;
use content_security_policy as csp;
use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use net_traits::policy_container::PolicyContainer;
use net_traits::request::{
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 8ddef6d33cb..c07f866ab41 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -16,7 +16,7 @@ use embedder_traits::resources::{self, Resource as EmbedderResource};
use embedder_traits::{MediaPositionState, MediaSessionEvent, MediaSessionPlaybackState};
use euclid::default::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use http::StatusCode;
use http::header::{self, HeaderMap, HeaderValue};
use ipc_channel::ipc::{self, IpcSharedMemory, channel};
diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs
index 74b79fadad3..e94a5e1ff33 100644
--- a/components/script/dom/htmlmetaelement.rs
+++ b/components/script/dom/htmlmetaelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::str::HTML_SPACE_CHARACTERS;
diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs
index a6941461e5d..276bddca986 100644
--- a/components/script/dom/htmlobjectelement.rs
+++ b/components/script/dom/htmlobjectelement.rs
@@ -5,7 +5,7 @@
use std::default::Default;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use pixels::Image;
use servo_arc::Arc;
diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs
index d6e8be04b64..b573388c73a 100644
--- a/components/script/dom/htmloptionelement.rs
+++ b/components/script/dom/htmloptionelement.rs
@@ -6,7 +6,7 @@ use std::cell::Cell;
use std::convert::TryInto;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, QualName, local_name, ns};
use js::rust::HandleObject;
use style::str::{split_html_space_chars, str_join};
use stylo_dom::ElementState;
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 3a71de1fa66..9452dcb17a6 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -44,6 +44,8 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::GenericBindings::HTMLElementBinding::HTMLElement_Binding::HTMLElementMethods;
+use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString;
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomGlobal;
@@ -1342,10 +1344,10 @@ impl VirtualMethods for HTMLScriptElement {
impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
// https://html.spec.whatwg.org/multipage/#dom-script-src
- make_url_getter!(Src, "src");
+ make_trusted_type_url_getter!(Src, "src");
// https://html.spec.whatwg.org/multipage/#dom-script-src
- make_url_setter!(SetSrc, "src");
+ make_trusted_type_url_setter!(SetSrc, "src");
// https://html.spec.whatwg.org/multipage/#dom-script-type
make_getter!(Type, "type");
diff --git a/components/script/dom/htmlslotelement.rs b/components/script/dom/htmlslotelement.rs
index 022cbbf388a..68fa105e64d 100644
--- a/components/script/dom/htmlslotelement.rs
+++ b/components/script/dom/htmlslotelement.rs
@@ -5,7 +5,7 @@
use std::cell::{Cell, Ref, RefCell};
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::gc::RootedVec;
use js::rust::HandleObject;
use script_bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId};
diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs
index 623dfdea54b..4f312e928c4 100644
--- a/components/script/dom/htmltablecellelement.rs
+++ b/components/script/dom/htmltablecellelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmltablecolelement.rs b/components/script/dom/htmltablecolelement.rs
index b2821fd38e2..c7ad4afd944 100644
--- a/components/script/dom/htmltablecolelement.rs
+++ b/components/script/dom/htmltablecolelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs
index 6783da6e97d..c24ec5490c5 100644
--- a/components/script/dom/htmltableelement.rs
+++ b/components/script/dom/htmltableelement.rs
@@ -5,7 +5,7 @@
use std::cell::Cell;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_unsigned_integer};
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmltablerowelement.rs b/components/script/dom/htmltablerowelement.rs
index a13238ca2e4..6c2d502ce88 100644
--- a/components/script/dom/htmltablerowelement.rs
+++ b/components/script/dom/htmltablerowelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmltablesectionelement.rs b/components/script/dom/htmltablesectionelement.rs
index d97e7445590..60978c64fc1 100644
--- a/components/script/dom/htmltablesectionelement.rs
+++ b/components/script/dom/htmltablesectionelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::color::AbsoluteColor;
diff --git a/components/script/dom/htmltemplateelement.rs b/components/script/dom/htmltemplateelement.rs
index 2c98035736e..128309b816b 100644
--- a/components/script/dom/htmltemplateelement.rs
+++ b/components/script/dom/htmltemplateelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, namespace_url};
+use html5ever::{LocalName, Prefix};
use js::rust::HandleObject;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs
index 7f47ee5a90a..a7435b40fdd 100644
--- a/components/script/dom/htmltextareaelement.rs
+++ b/components/script/dom/htmltextareaelement.rs
@@ -7,7 +7,7 @@ use std::default::Default;
use std::ops::Range;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::AttrValue;
use stylo_dom::ElementState;
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index a6f9103200b..6f27c164d02 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
use content_security_policy as csp;
use dom_struct::dom_struct;
use euclid::default::Size2D;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use ipc_channel::ipc;
use js::rust::HandleObject;
use net_traits::image_cache::{
@@ -233,8 +233,10 @@ impl HTMLVideoElement {
.credentials_mode(CredentialsMode::Include)
.use_url_credentials(true)
.origin(document.origin().immutable().clone())
- .pipeline_id(Some(document.global().pipeline_id()));
-
+ .pipeline_id(Some(document.global().pipeline_id()))
+ .insecure_requests_policy(document.insecure_requests_policy())
+ .has_trustworthy_ancestor_origin(document.has_trustworthy_ancestor_origin())
+ .policy_container(document.policy_container().to_owned());
// Step 5.
// This delay must be independent from the ones created by HTMLMediaElement during
// its media load algorithm, otherwise a code like
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index 7679e4a546d..b3f222af0da 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -122,6 +122,32 @@ macro_rules! make_url_setter(
);
#[macro_export]
+macro_rules! make_trusted_type_url_getter(
+ ( $attr:ident, $htmlname:tt ) => (
+ fn $attr(&self) -> TrustedScriptURLOrUSVString {
+ use $crate::dom::bindings::inheritance::Castable;
+ use $crate::dom::element::Element;
+ let element = self.upcast::<Element>();
+ element.get_trusted_type_url_attribute(&html5ever::local_name!($htmlname))
+ }
+ );
+);
+
+#[macro_export]
+macro_rules! make_trusted_type_url_setter(
+ ( $attr:ident, $htmlname:tt ) => (
+ fn $attr(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> {
+ use $crate::dom::bindings::inheritance::Castable;
+ use $crate::dom::element::Element;
+ use $crate::script_runtime::CanGc;
+ let element = self.upcast::<Element>();
+ element.set_trusted_type_url_attribute(&html5ever::local_name!($htmlname),
+ value, can_gc)
+ }
+ );
+);
+
+#[macro_export]
macro_rules! make_form_action_getter(
( $attr:ident, $htmlname:tt ) => (
fn $attr(&self) -> DOMString {
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index 3e25602b365..c3904dbb19a 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -20,7 +20,7 @@ use crate::dom::bindings::codegen::Bindings::MessagePortBinding::{
MessagePortMethods, StructuredSerializeOptions,
};
use crate::dom::bindings::conversions::root_from_object;
-use crate::dom::bindings::error::{Error, ErrorResult};
+use crate::dom::bindings::error::{Error, ErrorResult, ErrorToJsval};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
@@ -180,14 +180,13 @@ impl MessagePort {
let result = self.pack_and_post_message(type_, value, can_gc);
// If result is an abrupt completion,
- if result.is_err() {
+ if let Err(error) = result.as_ref() {
// Perform ! CrossRealmTransformSendError(port, result.[[Value]]).
- // Note: we send UndefinedValue across,
- // because somehow sending an error results in another error.
- // The Error::DataClone, which is the only one that is sent across,
- // will be created upon receipt.
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut rooted_error = UndefinedValue());
+ error
+ .clone()
+ .to_jsval(cx, &self.global(), rooted_error.handle_mut(), can_gc);
self.cross_realm_transform_send_error(rooted_error.handle(), can_gc);
}
diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs
index 558453f9235..473698d5df1 100644
--- a/components/script/dom/mutationobserver.rs
+++ b/components/script/dom/mutationobserver.rs
@@ -6,7 +6,7 @@ use std::cell::LazyCell;
use std::rc::Rc;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Namespace, namespace_url, ns};
+use html5ever::{LocalName, Namespace, ns};
use js::rust::HandleObject;
use crate::dom::bindings::callback::ExceptionHandling;
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index bcaff69adb9..2a01370085a 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -21,7 +21,7 @@ use dom_struct::dom_struct;
use embedder_traits::UntrustedNodeAddress;
use euclid::default::{Rect, Size2D, Vector2D};
use html5ever::serialize::HtmlSerializer;
-use html5ever::{Namespace, Prefix, QualName, namespace_url, ns, serialize as html_serialize};
+use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
use js::jsapi::JSObject;
use js::rust::HandleObject;
use libc::{self, c_void, uintptr_t};
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index bf39c43e923..49e740c6d6e 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -2088,19 +2088,8 @@ impl CrossRealmTransformReadable {
// Otherwise, if type is "error",
if type_string == "error" {
- if value.is_undefined() {
- // Note: for DataClone errors, we send UndefinedValue across,
- // because somehow sending the error results in another error.
- // The error is then created here.
- rooted!(in(*cx) let mut rooted_error = UndefinedValue());
- Error::DataClone(None).to_jsval(cx, global, rooted_error.handle_mut(), can_gc);
-
- // Perform ! ReadableStreamDefaultControllerError(controller, value).
- self.controller.error(rooted_error.handle(), can_gc);
- } else {
- // Perform ! ReadableStreamDefaultControllerError(controller, value).
- self.controller.error(value.handle(), can_gc);
- }
+ // Perform ! ReadableStreamDefaultControllerError(controller, value).
+ self.controller.error(value.handle(), can_gc);
// Disentangle port.
global.disentangle_port(port);
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index defed40f0ef..9b431da9c0e 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -38,6 +38,7 @@ use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::CustomTraceable;
+use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::dedicatedworkerglobalscope::AutoWorkerReset;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
@@ -379,6 +380,11 @@ impl ServiceWorkerGlobalScope {
{
// TODO: use AutoWorkerReset as in dedicated worker?
let realm = enter_realm(scope);
+ define_all_exposed_interfaces(
+ scope.upcast(),
+ InRealm::entered(&realm),
+ CanGc::note(),
+ );
scope.execute_script(DOMString::from(source), CanGc::note());
global.dispatch_activate(CanGc::note(), InRealm::entered(&realm));
}
diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs
index 7ddc425678e..1d6f4af0b01 100644
--- a/components/script/dom/servoparser/async_html.rs
+++ b/components/script/dom/servoparser/async_html.rs
@@ -18,9 +18,7 @@ use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts};
use html5ever::tree_builder::{
ElementFlags, NodeOrText as HtmlNodeOrText, QuirksMode, TreeBuilder, TreeBuilderOpts, TreeSink,
};
-use html5ever::{
- Attribute as HtmlAttribute, ExpandedName, QualName, local_name, namespace_url, ns,
-};
+use html5ever::{Attribute as HtmlAttribute, ExpandedName, QualName, local_name, ns};
use markup5ever::TokenizerResult;
use servo_url::ServoUrl;
use style::context::QuirksMode as ServoQuirksMode;
diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs
index 3bd486b5cb7..97856256268 100644
--- a/components/script/dom/servoparser/html.rs
+++ b/components/script/dom/servoparser/html.rs
@@ -12,7 +12,7 @@ use html5ever::serialize::TraversalScope::IncludeNode;
use html5ever::serialize::{AttrRef, Serialize, Serializer, TraversalScope};
use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts};
use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts};
-use html5ever::{QualName, local_name, namespace_url, ns};
+use html5ever::{QualName, local_name, ns};
use markup5ever::TokenizerResult;
use script_bindings::trace::CustomTraceable;
use servo_url::ServoUrl;
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 970c1543d09..0650fde676e 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -9,7 +9,7 @@ use base::cross_process_instant::CrossProcessInstant;
use base::id::PipelineId;
use base64::Engine as _;
use base64::engine::general_purpose;
-use content_security_policy::{self as csp, CspList};
+use content_security_policy as csp;
use dom_struct::dom_struct;
use embedder_traits::resources::{self, Resource};
use encoding_rs::Encoding;
@@ -17,7 +17,7 @@ use html5ever::buffer_queue::BufferQueue;
use html5ever::tendril::fmt::UTF8;
use html5ever::tendril::{ByteTendril, StrTendril, TendrilSink};
use html5ever::tree_builder::{ElementFlags, NodeOrText, QuirksMode, TreeSink};
-use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, namespace_url, ns};
+use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns};
use hyper_serde::Serde;
use markup5ever::TokenizerResult;
use mime::{self, Mime};
@@ -59,6 +59,7 @@ use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLD
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documenttype::DocumentType;
use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
+use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
use crate::dom::htmlimageelement::HTMLImageElement;
use crate::dom::htmlinputelement::HTMLInputElement;
@@ -850,29 +851,9 @@ impl FetchResponseListener for ParserContext {
.map(Serde::into_inner)
.map(Into::into);
- // https://www.w3.org/TR/CSP/#initialize-document-csp
- // TODO: Implement step 1 (local scheme special case)
- let csp_list = metadata.as_ref().and_then(|m| {
- let h = m.headers.as_ref()?;
- let mut csp = h.get_all("content-security-policy").iter();
- // This silently ignores the CSP if it contains invalid Unicode.
- // We should probably report an error somewhere.
- let c = csp.next().and_then(|c| c.to_str().ok())?;
- let mut csp_list = CspList::parse(
- c,
- csp::PolicySource::Header,
- csp::PolicyDisposition::Enforce,
- );
- for c in csp {
- let c = c.to_str().ok()?;
- csp_list.append(CspList::parse(
- c,
- csp::PolicySource::Header,
- csp::PolicyDisposition::Enforce,
- ));
- }
- Some(csp_list)
- });
+ let csp_list = metadata
+ .as_ref()
+ .and_then(|m| GlobalScope::parse_csp_list_from_metadata(&m.headers));
let parser = match ScriptThread::page_headers_available(&self.id, metadata, CanGc::note()) {
Some(parser) => parser,
@@ -1462,7 +1443,7 @@ impl TreeSink for Sink {
clonable,
serializable,
delegatesfocus,
- SlotAssignmentMode::Manual,
+ SlotAssignmentMode::Named,
CanGc::note(),
) {
Ok(shadow_root) => {
diff --git a/components/script/dom/svgelement.rs b/components/script/dom/svgelement.rs
index 9a48653b768..9c8b990826d 100644
--- a/components/script/dom/svgelement.rs
+++ b/components/script/dom/svgelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use script_bindings::str::DOMString;
use stylo_dom::ElementState;
diff --git a/components/script/dom/svgsvgelement.rs b/components/script/dom/svgsvgelement.rs
index 61b90a5ef39..12b7fa6bc71 100644
--- a/components/script/dom/svgsvgelement.rs
+++ b/components/script/dom/svgsvgelement.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use html5ever::{LocalName, Prefix, local_name, namespace_url, ns};
+use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use script_layout_interface::SVGSVGData;
use style::attr::AttrValue;
diff --git a/components/script/dom/trustedscripturl.rs b/components/script/dom/trustedscripturl.rs
index 01a82a4fff7..ba1e0335abc 100644
--- a/components/script/dom/trustedscripturl.rs
+++ b/components/script/dom/trustedscripturl.rs
@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use std::fmt;
+
use dom_struct::dom_struct;
use crate::dom::bindings::codegen::Bindings::TrustedScriptURLBinding::TrustedScriptURLMethods;
@@ -32,6 +34,13 @@ impl TrustedScriptURL {
}
}
+impl fmt::Display for TrustedScriptURL {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(&self.data)
+ }
+}
+
impl TrustedScriptURLMethods<crate::DomTypeHolder> for TrustedScriptURL {
/// <https://www.w3.org/TR/trusted-types/#trustedscripturl-stringification-behavior>
fn Stringifier(&self) -> DOMString {
diff --git a/components/script/dom/trustedtypepolicy.rs b/components/script/dom/trustedtypepolicy.rs
index 387e53faeb3..2ec5015eb88 100644
--- a/components/script/dom/trustedtypepolicy.rs
+++ b/components/script/dom/trustedtypepolicy.rs
@@ -59,6 +59,13 @@ impl TrustedTypePolicy {
reflect_dom_object(Box::new(Self::new_inherited(name, options)), global, can_gc)
}
+ // TODO(36258): Remove when we refactor get_trusted_type_policy_value to take an enum
+ // value to handle which callback to call. The callback should not be exposed outside
+ // of the policy object, but is currently used in TrustedPolicyFactory::process_value_with_default_policy
+ pub(crate) fn create_script_url(&self) -> Option<Rc<CreateScriptURLCallback>> {
+ self.create_script_url.clone()
+ }
+
/// This does not take all arguments as specified. That's because the return type of the
/// trusted type function and object are not the same. 2 of the 3 string callbacks return
/// a DOMString, while the other one returns an USVString. Additionally, all three callbacks
diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs
index 64ae1f8ab11..0dcc78b7cd0 100644
--- a/components/script/dom/trustedtypepolicyfactory.rs
+++ b/components/script/dom/trustedtypepolicyfactory.rs
@@ -5,9 +5,12 @@ use std::cell::RefCell;
use content_security_policy::CheckResult;
use dom_struct::dom_struct;
-use html5ever::{LocalName, Namespace, QualName, local_name, namespace_url, ns};
+use html5ever::{LocalName, Namespace, QualName, local_name, ns};
+use js::jsapi::JSObject;
+use js::jsval::NullValue;
use js::rust::HandleValue;
+use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{
TrustedTypePolicyFactoryMethods, TrustedTypePolicyOptions,
};
@@ -21,6 +24,7 @@ use crate::dom::trustedhtml::TrustedHTML;
use crate::dom::trustedscript::TrustedScript;
use crate::dom::trustedscripturl::TrustedScriptURL;
use crate::dom::trustedtypepolicy::TrustedTypePolicy;
+use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::{CanGc, JSContext};
#[dom_struct]
@@ -137,6 +141,122 @@ impl TrustedTypePolicyFactory {
// Step 4: Return data.
data
}
+ /// <https://w3c.github.io/trusted-types/dist/spec/#process-value-with-a-default-policy-algorithm>
+ #[allow(unsafe_code)]
+ pub(crate) fn process_value_with_default_policy(
+ global: &GlobalScope,
+ input: String,
+ sink: &str,
+ can_gc: CanGc,
+ ) -> Fallible<Option<DomRoot<TrustedScriptURL>>> {
+ // Step 1: Let defaultPolicy be the value of global’s trusted type policy factory's default policy.
+ let global_policy_factory = global.trusted_types(can_gc);
+ let default_policy = match global_policy_factory.default_policy.get() {
+ None => return Ok(Some(TrustedScriptURL::new(input, global, can_gc))),
+ Some(default_policy) => default_policy,
+ };
+ let cx = GlobalScope::get_cx();
+ // Step 2: Let policyValue be the result of executing Get Trusted Type policy value,
+ // with the following arguments:
+ let policy_value = default_policy.get_trusted_type_policy_value(
+ || {
+ // TODO(36258): support other trusted types as well by changing get_trusted_type_policy_value to accept
+ // the trusted type as enum and call the appropriate callback based on that.
+ default_policy.create_script_url().map(|callback| {
+ rooted!(in(*cx) let this_object: *mut JSObject);
+ rooted!(in(*cx) let mut trusted_type_name_value = NullValue());
+ unsafe {
+ "TrustedScriptURL".to_jsval(*cx, trusted_type_name_value.handle_mut());
+ }
+
+ rooted!(in(*cx) let mut sink_value = NullValue());
+ unsafe {
+ sink.to_jsval(*cx, sink_value.handle_mut());
+ }
+
+ let args = vec![trusted_type_name_value.handle(), sink_value.handle()];
+ // Step 4: Let policyValue be the result of invoking function with value as a first argument,
+ // items of arguments as subsequent arguments, and callback **this** value set to null,
+ // rethrowing any exceptions.
+ callback.Call_(
+ &this_object.handle(),
+ DOMString::from(input.to_owned()),
+ args,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )
+ })
+ },
+ false,
+ );
+ let data_string = match policy_value {
+ // Step 3: If the algorithm threw an error, rethrow the error and abort the following steps.
+ Err(error) => return Err(error),
+ Ok(policy_value) => match policy_value {
+ // Step 4: If policyValue is null or undefined, return policyValue.
+ None => return Ok(None),
+ // Step 5: Let dataString be the result of stringifying policyValue.
+ Some(policy_value) => policy_value.as_ref().into(),
+ },
+ };
+ Ok(Some(TrustedScriptURL::new(data_string, global, can_gc)))
+ }
+ /// Step 1 is implemented by the caller
+ /// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
+ pub(crate) fn get_trusted_type_compliant_string(
+ global: &GlobalScope,
+ input: String,
+ sink: &str,
+ sink_group: &str,
+ can_gc: CanGc,
+ ) -> Fallible<String> {
+ let csp_list = match global.get_csp_list() {
+ None => return Ok(input),
+ Some(csp_list) => csp_list,
+ };
+ // Step 2: Let requireTrustedTypes be the result of executing Does sink type require trusted types?
+ // algorithm, passing global, sinkGroup, and true.
+ let require_trusted_types = csp_list.does_sink_type_require_trusted_types(sink_group, true);
+ // Step 3: If requireTrustedTypes is false, return stringified input and abort these steps.
+ if !require_trusted_types {
+ return Ok(input);
+ }
+ // Step 4: Let convertedInput be the result of executing Process value with a default policy
+ // with the same arguments as this algorithm.
+ let converted_input = TrustedTypePolicyFactory::process_value_with_default_policy(
+ global,
+ input.clone(),
+ sink,
+ can_gc,
+ );
+ // Step 5: If the algorithm threw an error, rethrow the error and abort the following steps.
+ match converted_input? {
+ // Step 6: If convertedInput is null or undefined, execute the following steps:
+ None => {
+ // Step 6.1: Let disposition be the result of executing Should sink type mismatch violation
+ // be blocked by Content Security Policy? algorithm, passing global,
+ // stringified input as source, sinkGroup and sink.
+ let (disposition, violations) = csp_list
+ .should_sink_type_mismatch_violation_be_blocked_by_csp(
+ sink, sink_group, &input,
+ );
+ global.report_csp_violations(violations);
+ // Step 6.2: If disposition is “Allowed”, return stringified input and abort further steps.
+ if disposition == CheckResult::Allowed {
+ Ok(input)
+ } else {
+ // Step 6.3: Throw a TypeError and abort further steps.
+ Err(Error::Type(
+ "Cannot set value, expected trusted type".to_owned(),
+ ))
+ }
+ },
+ // Step 8: Return stringified convertedInput.
+ Some(converted_input) => Ok((*converted_input).to_string()),
+ }
+ // Step 7: Assert: convertedInput is an instance of expectedType.
+ // TODO(https://github.com/w3c/trusted-types/issues/566): Implement when spec is resolved
+ }
}
impl TrustedTypePolicyFactoryMethods<crate::DomTypeHolder> for TrustedTypePolicyFactory {
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 5775375c385..695119715e4 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -12,6 +12,7 @@ use std::time::Duration;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{PipelineId, PipelineNamespace};
use constellation_traits::WorkerGlobalScopeInit;
+use content_security_policy::CspList;
use crossbeam_channel::Receiver;
use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
use dom_struct::dom_struct;
@@ -246,6 +247,10 @@ impl WorkerGlobalScope {
self.policy_container.borrow()
}
+ pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
+ self.policy_container.borrow_mut().set_csp_list(csp_list);
+ }
+
/// Get a mutable reference to the [`TimerScheduler`] for this [`ServiceWorkerGlobalScope`].
pub(crate) fn timer_scheduler(&self) -> RefMut<TimerScheduler> {
self.timer_scheduler.borrow_mut()
@@ -300,6 +305,7 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
.use_url_credentials(true)
.origin(global_scope.origin().immutable().clone())
.insecure_requests_policy(self.insecure_requests_policy())
+ .policy_container(global_scope.policy_container())
.has_trustworthy_ancestor_origin(
global_scope.has_trustworthy_ancestor_or_current_origin(),
)
diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs
index 0196d6a83ea..6e81220731c 100644
--- a/components/script/dom/workletglobalscope.rs
+++ b/components/script/dom/workletglobalscope.rs
@@ -15,6 +15,7 @@ use js::rust::Runtime;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
+use script_bindings::realms::InRealm;
use script_traits::Painter;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use stylo_atoms::Atom;
@@ -22,6 +23,7 @@ use stylo_atoms::Atom;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::CustomTraceable;
+use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::globalscope::GlobalScope;
use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
@@ -29,6 +31,7 @@ use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worklet::WorkletExecutor;
use crate::messaging::MainThreadScriptMsg;
+use crate::realms::enter_realm;
use crate::script_module::ScriptFetchOptions;
use crate::script_runtime::{CanGc, JSContext};
@@ -56,7 +59,7 @@ impl WorkletGlobalScope {
executor: WorkletExecutor,
init: &WorkletGlobalScopeInit,
) -> DomRoot<WorkletGlobalScope> {
- match scope_type {
+ let scope: DomRoot<WorkletGlobalScope> = match scope_type {
WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
runtime,
pipeline_id,
@@ -71,7 +74,12 @@ impl WorkletGlobalScope {
executor,
init,
)),
- }
+ };
+
+ let realm = enter_realm(&*scope);
+ define_all_exposed_interfaces(scope.upcast(), InRealm::entered(&realm), CanGc::note());
+
+ scope
}
/// Create a new stack-allocated `WorkletGlobalScope`.
diff --git a/components/script/layout_dom/element.rs b/components/script/layout_dom/element.rs
index ce7ca96f464..9b50c9f3a2b 100644
--- a/components/script/layout_dom/element.rs
+++ b/components/script/layout_dom/element.rs
@@ -8,7 +8,7 @@ use std::{fmt, slice};
use atomic_refcell::{AtomicRef, AtomicRefMut};
use embedder_traits::UntrustedNodeAddress;
-use html5ever::{LocalName, Namespace, local_name, namespace_url, ns};
+use html5ever::{LocalName, Namespace, local_name, ns};
use js::jsapi::JSObject;
use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
diff --git a/components/script/layout_dom/node.rs b/components/script/layout_dom/node.rs
index 213070181ef..9d36f73bbc0 100644
--- a/components/script/layout_dom/node.rs
+++ b/components/script/layout_dom/node.rs
@@ -10,7 +10,7 @@ use std::sync::Arc as StdArc;
use base::id::{BrowsingContextId, PipelineId};
use fonts_traits::ByteIndex;
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use pixels::{Image, ImageMetadata};
use range::Range;
use script_layout_interface::wrapper_traits::{LayoutDataTrait, LayoutNode, ThreadSafeLayoutNode};
diff --git a/components/script/links.rs b/components/script/links.rs
index f7094adbfde..f38ba6f7767 100644
--- a/components/script/links.rs
+++ b/components/script/links.rs
@@ -5,7 +5,7 @@
//! Defines shared hyperlink behaviour for `<link>`, `<a>`, `<area>` and `<form>` elements.
use constellation_traits::{LoadData, LoadOrigin, NavigationHistoryBehavior};
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use malloc_size_of::malloc_size_of_is_0;
use net_traits::request::Referrer;
use style::str::HTML_SPACE_CHARACTERS;
diff --git a/components/script/script_module.rs b/components/script/script_module.rs
index 689f4a3b0a7..c7697adeea6 100644
--- a/components/script/script_module.rs
+++ b/components/script/script_module.rs
@@ -1760,7 +1760,10 @@ fn fetch_single_module_script(
.integrity_metadata(options.integrity_metadata.clone())
.credentials_mode(options.credentials_mode)
.referrer_policy(options.referrer_policy)
- .mode(mode);
+ .mode(mode)
+ .insecure_requests_policy(global.insecure_requests_policy())
+ .has_trustworthy_ancestor_origin(global.has_trustworthy_ancestor_origin())
+ .policy_container(global.policy_container().to_owned());
let context = Arc::new(Mutex::new(ModuleContext {
owner,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index bec4d59be0f..da37a12c8a7 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -57,7 +57,7 @@ use euclid::Point2D;
use euclid::default::Rect;
use fonts::{FontContext, SystemFontServiceProxy};
use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader};
-use html5ever::{local_name, namespace_url, ns};
+use html5ever::{local_name, ns};
use http::header::REFRESH;
use hyper_serde::Serde;
use ipc_channel::ipc;
@@ -336,11 +336,6 @@ pub struct ScriptThread {
#[no_trace]
layout_factory: Arc<dyn LayoutFactory>,
- // Mouse down button: TO BE REMOVED. Not needed as click event should only
- // triggered for primary button
- #[no_trace]
- mouse_down_button: Cell<Option<MouseButton>>,
-
// Mouse down point.
// In future, this shall be mouse_down_point for primary button
#[no_trace]
@@ -959,7 +954,6 @@ impl ScriptThread {
gpu_id_hub: Arc::new(IdentityHub::default()),
inherited_secure_context: state.inherited_secure_context,
layout_factory,
- mouse_down_button: Cell::new(None),
relative_mouse_down_point: Cell::new(Point2D::zero()),
}
}
@@ -3354,14 +3348,6 @@ impl ScriptThread {
return;
};
- if let InputEvent::MouseButton(mouse_button_event) = event.event {
- if mouse_button_event.action == MouseButtonAction::Down {
- self.mouse_down_button.set(Some(mouse_button_event.button));
- self.relative_mouse_down_point.set(mouse_button_event.point)
- }
- }
- document.note_pending_input_event(event.clone());
-
// Also send a 'click' event with same hit-test result if this is release
// MAYBE? TODO: https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
@@ -3370,30 +3356,42 @@ impl ScriptThread {
// that contained both elements.
// But spec doesn't specify this https://w3c.github.io/uievents/#event-type-click
+ // "The click event type MUST be dispatched on the topmost event target indicated by
+ // the pointer, when the user presses down and releases the primary pointer button"
// Servo-specific: Trigger if within 10px of the down point
if let InputEvent::MouseButton(mouse_button_event) = event.event {
- if let (Some(mouse_down_button), MouseButtonAction::Up) =
- (self.mouse_down_button.get(), mouse_button_event.action)
- {
- let pixel_dist = self.relative_mouse_down_point.get() - mouse_button_event.point;
- let pixel_dist = (pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y).sqrt();
- if mouse_down_button == mouse_button_event.button &&
- pixel_dist < 10.0 * document.window().device_pixel_ratio().get()
- {
- document.note_pending_input_event(ConstellationInputEvent {
- hit_test_result: event.hit_test_result,
- pressed_mouse_buttons: event.pressed_mouse_buttons,
- active_keyboard_modifiers: event.active_keyboard_modifiers,
- event: InputEvent::MouseButton(MouseButtonEvent {
- action: MouseButtonAction::Click,
- button: mouse_button_event.button,
- point: mouse_button_event.point,
- }),
- });
+ if let MouseButton::Left = mouse_button_event.button {
+ match mouse_button_event.action {
+ MouseButtonAction::Up => {
+ let pixel_dist =
+ self.relative_mouse_down_point.get() - mouse_button_event.point;
+ let pixel_dist =
+ (pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y).sqrt();
+ if pixel_dist < 10.0 * document.window().device_pixel_ratio().get() {
+ document.note_pending_input_event(event.clone());
+ document.note_pending_input_event(ConstellationInputEvent {
+ hit_test_result: event.hit_test_result,
+ pressed_mouse_buttons: event.pressed_mouse_buttons,
+ active_keyboard_modifiers: event.active_keyboard_modifiers,
+ event: InputEvent::MouseButton(MouseButtonEvent {
+ action: MouseButtonAction::Click,
+ button: mouse_button_event.button,
+ point: mouse_button_event.point,
+ }),
+ });
+ return;
+ }
+ },
+ MouseButtonAction::Down => {
+ self.relative_mouse_down_point.set(mouse_button_event.point)
+ },
+ MouseButtonAction::Click => {},
}
}
}
+
+ document.note_pending_input_event(event);
}
/// Handle a "navigate an iframe" message from the constellation.
diff --git a/components/script/security_manager.rs b/components/script/security_manager.rs
index 60cf2267a2c..ee320206de2 100644
--- a/components/script/security_manager.rs
+++ b/components/script/security_manager.rs
@@ -62,6 +62,8 @@ pub(crate) struct CSPViolationReportBuilder {
pub source_file: String,
/// <https://www.w3.org/TR/CSP3/#violation-effective-directive>
pub effective_directive: String,
+ /// <https://www.w3.org/TR/CSP3/#violation-policy>
+ pub original_policy: String,
}
impl CSPViolationReportBuilder {
@@ -106,6 +108,12 @@ impl CSPViolationReportBuilder {
self
}
+ /// <https://www.w3.org/TR/CSP3/#violation-policy>
+ pub fn original_policy(mut self, original_policy: String) -> CSPViolationReportBuilder {
+ self.original_policy = original_policy;
+ self
+ }
+
/// <https://w3c.github.io/webappsec-csp/#strip-url-for-use-in-reports>
fn strip_url_for_reports(&self, mut url: ServoUrl) -> String {
let scheme = url.scheme();
@@ -141,7 +149,7 @@ impl CSPViolationReportBuilder {
sample: self.sample,
blocked_url: self.resource,
source_file: self.source_file,
- original_policy: "".to_owned(),
+ original_policy: self.original_policy,
line_number: self.line_number,
column_number: self.column_number,
status_code: global.status_code().unwrap_or(0),
diff --git a/components/script/xpath/eval.rs b/components/script/xpath/eval.rs
index 9c95c3d8699..75d7ac5849c 100644
--- a/components/script/xpath/eval.rs
+++ b/components/script/xpath/eval.rs
@@ -4,7 +4,7 @@
use std::fmt;
-use html5ever::{QualName, local_name, namespace_prefix, namespace_url, ns};
+use html5ever::{QualName, local_name, namespace_prefix, ns};
use super::parser::{
AdditiveOp, Axis, EqualityOp, Expr, FilterExpr, KindTest, Literal, MultiplicativeOp, NodeTest,
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index f9ab745e4ea..4946177e0b3 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -416,7 +416,7 @@ DOMInterfaces = {
},
'HTMLScriptElement': {
- 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetText']
+ 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetSrc', 'SetText']
},
'HTMLSelectElement': {
diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py
index 107e047ea3b..48f024be70f 100644
--- a/components/script_bindings/codegen/CodegenRust.py
+++ b/components/script_bindings/codegen/CodegenRust.py
@@ -2405,15 +2405,22 @@ class CGDOMJSClass(CGThing):
"flags": "JSCLASS_FOREGROUND_FINALIZE",
"name": str_to_cstr_ptr(self.descriptor.interface.identifier.name),
"resolveHook": "None",
+ "mayResolveHook": "None",
"slots": "1",
"traceHook": f"{TRACE_HOOK_NAME}::<D>",
}
if self.descriptor.isGlobal():
assert not self.descriptor.weakReferenceable
- args["enumerateHook"] = "Some(enumerate_global::<D>)"
args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL | JSCLASS_FOREGROUND_FINALIZE"
args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
- args["resolveHook"] = "Some(resolve_global::<D>)"
+ if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
+ args["enumerateHook"] = "Some(enumerate_window::<D>)"
+ args["resolveHook"] = "Some(resolve_window::<D>)"
+ args["mayResolveHook"] = "Some(may_resolve_window::<D>)"
+ else:
+ args["enumerateHook"] = "Some(enumerate_global)"
+ args["resolveHook"] = "Some(resolve_global)"
+ args["mayResolveHook"] = "Some(may_resolve_global)"
args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
elif self.descriptor.weakReferenceable:
args["slots"] = "2"
@@ -2427,7 +2434,7 @@ pub(crate) fn init_class_ops<D: DomTypes>() {{
enumerate: None,
newEnumerate: {args['enumerateHook']},
resolve: {args['resolveHook']},
- mayResolve: None,
+ mayResolve: {args['mayResolveHook']},
finalize: Some({args['finalizeHook']}),
call: None,
construct: None,
diff --git a/components/script_bindings/import.rs b/components/script_bindings/import.rs
index 65e9ee30e1d..16cc92f07bf 100644
--- a/components/script_bindings/import.rs
+++ b/components/script_bindings/import.rs
@@ -127,10 +127,11 @@ pub(crate) mod module {
pub(crate) use crate::script_runtime::CanGc;
pub(crate) use crate::utils::{
AsVoidPtr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, DOMClass, DOMJSClass, JSCLASS_DOM_GLOBAL,
- ProtoOrIfaceArray, enumerate_global, exception_to_promise, generic_getter,
- generic_lenient_getter, generic_lenient_setter, generic_method, generic_setter,
- generic_static_promise_method, get_array_index_from_id, get_property_on_prototype,
- has_property_on_prototype, resolve_global, trace_global,
+ ProtoOrIfaceArray, enumerate_global, enumerate_window, exception_to_promise,
+ generic_getter, generic_lenient_getter, generic_lenient_setter, generic_method,
+ generic_setter, generic_static_promise_method, get_array_index_from_id,
+ get_property_on_prototype, has_property_on_prototype, may_resolve_global,
+ may_resolve_window, resolve_global, resolve_window, trace_global,
};
pub(crate) use crate::weakref::DOM_WEAK_SLOT;
pub(crate) use crate::{JSTraceable, proxyhandler};
diff --git a/components/script_bindings/root.rs b/components/script_bindings/root.rs
index 51bc979908f..3d0378f0df1 100644
--- a/components/script_bindings/root.rs
+++ b/components/script_bindings/root.rs
@@ -412,7 +412,7 @@ impl RootCollection {
.rposition(|r| std::ptr::addr_eq(*r as *const (), object as *const ()))
{
Some(idx) => {
- roots.remove(idx);
+ roots.swap_remove(idx);
},
None => panic!("Can't remove a root that was never rooted!"),
}
diff --git a/components/script_bindings/utils.rs b/components/script_bindings/utils.rs
index 03a5783958e..fa4982b9904 100644
--- a/components/script_bindings/utils.rs
+++ b/components/script_bindings/utils.rs
@@ -18,9 +18,10 @@ use js::jsapi::{
GetLinearStringLength, GetNonCCWObjectGlobal, HandleId as RawHandleId,
HandleObject as RawHandleObject, Heap, JS_AtomizeStringN, JS_ClearPendingException,
JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_IsExceptionPending,
- JS_IsGlobalObject, JS_NewEnumerateStandardClasses, JS_ResolveStandardClass, JSAtom, JSContext,
- JSJitInfo, JSObject, JSTracer, MutableHandleIdVector as RawMutableHandleIdVector,
- MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
+ JS_IsGlobalObject, JS_MayResolveStandardClass, JS_NewEnumerateStandardClasses,
+ JS_ResolveStandardClass, JSAtom, JSAtomState, JSContext, JSJitInfo, JSObject, JSTracer,
+ MutableHandleIdVector as RawMutableHandleIdVector, MutableHandleValue as RawMutableHandleValue,
+ ObjectOpResult, PropertyKey, StringIsArrayIndex, jsid,
};
use js::jsid::StringId;
use js::jsval::{JSVal, UndefinedValue};
@@ -30,7 +31,7 @@ use js::rust::wrappers::{
JS_SetPendingException, JS_SetProperty,
};
use js::rust::{
- HandleId, HandleObject, HandleValue, MutableHandleValue, ToString, get_object_class,
+ HandleId, HandleObject, HandleValue, MutableHandleValue, Runtime, ToString, get_object_class,
};
use js::{JS_CALLEE, rooted};
use malloc_size_of::MallocSizeOfOps;
@@ -577,15 +578,25 @@ impl AsCCharPtrPtr for [u8] {
/// Enumerate lazy properties of a global object.
/// Modeled after <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/bindings/BindingUtils.cpp#L2814>
-/// and <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/base/nsGlobalWindowInner.cpp#3297>
-pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
+pub(crate) unsafe extern "C" fn enumerate_global(
cx: *mut JSContext,
obj: RawHandleObject,
props: RawMutableHandleIdVector,
enumerable_only: bool,
) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
- if !JS_NewEnumerateStandardClasses(cx, obj, props, enumerable_only) {
+ JS_NewEnumerateStandardClasses(cx, obj, props, enumerable_only)
+}
+
+/// Enumerate lazy properties of a global object that is a Window.
+/// <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/base/nsGlobalWindowInner.cpp#3297>
+pub(crate) unsafe extern "C" fn enumerate_window<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ props: RawMutableHandleIdVector,
+ enumerable_only: bool,
+) -> bool {
+ if !enumerate_global(cx, obj, props, enumerable_only) {
return false;
}
@@ -610,34 +621,68 @@ pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
true
}
+/// Returns true if the resolve hook for this global may resolve the provided id.
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/dom/bindings/BindingUtils.cpp#2809>
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/js/public/Class.h#283-291>
+pub(crate) unsafe extern "C" fn may_resolve_global(
+ names: *const JSAtomState,
+ id: PropertyKey,
+ maybe_obj: *mut JSObject,
+) -> bool {
+ JS_MayResolveStandardClass(names, id, maybe_obj)
+}
+
+/// Returns true if the resolve hook for this window may resolve the provided id.
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/dom/base/nsGlobalWindowInner.cpp#3275>
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/js/public/Class.h#283-291>
+pub(crate) unsafe extern "C" fn may_resolve_window<D: DomTypes>(
+ names: *const JSAtomState,
+ id: PropertyKey,
+ maybe_obj: *mut JSObject,
+) -> bool {
+ if may_resolve_global(names, id, maybe_obj) {
+ return true;
+ }
+
+ let cx = Runtime::get()
+ .expect("There must be a JSContext active")
+ .as_ptr();
+ let Ok(bytes) = latin1_bytes_from_id(cx, id) else {
+ return false;
+ };
+
+ <D as DomHelpers<D>>::interface_map().contains_key(bytes)
+}
+
/// Resolve a lazy global property, for interface objects and named constructors.
-pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>(
+pub(crate) unsafe extern "C" fn resolve_global(
cx: *mut JSContext,
obj: RawHandleObject,
id: RawHandleId,
rval: *mut bool,
) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
- if !JS_ResolveStandardClass(cx, obj, id, rval) {
+ JS_ResolveStandardClass(cx, obj, id, rval)
+}
+
+/// Resolve a lazy global property for a Window global.
+pub(crate) unsafe extern "C" fn resolve_window<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ id: RawHandleId,
+ rval: *mut bool,
+) -> bool {
+ if !resolve_global(cx, obj, id, rval) {
return false;
}
+
if *rval {
return true;
}
- if !id.is_string() {
- *rval = false;
- return true;
- }
-
- let string = id.to_string();
- if !JS_DeprecatedStringHasLatin1Chars(string) {
+ let Ok(bytes) = latin1_bytes_from_id(cx, *id) else {
*rval = false;
return true;
- }
- let mut length = 0;
- let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
- assert!(!ptr.is_null());
- let bytes = slice::from_raw_parts(ptr, length);
+ };
if let Some(interface) = <D as DomHelpers<D>>::interface_map().get(bytes) {
(interface.define)(SafeJSContext::from_ptr(cx), Handle::from_raw(obj));
@@ -647,3 +692,22 @@ pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>(
}
true
}
+
+/// Returns a slice of bytes corresponding to the bytes in the provided string id.
+/// Returns an error if the id is not a string, or the string contains non-latin1 characters.
+/// # Safety
+/// The slice is only valid as long as the original id is not garbage collected.
+unsafe fn latin1_bytes_from_id(cx: *mut JSContext, id: jsid) -> Result<&'static [u8], ()> {
+ if !id.is_string() {
+ return Err(());
+ }
+
+ let string = id.to_string();
+ if !JS_DeprecatedStringHasLatin1Chars(string) {
+ return Err(());
+ }
+ let mut length = 0;
+ let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
+ assert!(!ptr.is_null());
+ Ok(slice::from_raw_parts(ptr, length))
+}
diff --git a/components/script_bindings/webidls/HTMLScriptElement.webidl b/components/script_bindings/webidls/HTMLScriptElement.webidl
index b79382dbbb8..6f02bb3cf47 100644
--- a/components/script_bindings/webidls/HTMLScriptElement.webidl
+++ b/components/script_bindings/webidls/HTMLScriptElement.webidl
@@ -7,8 +7,8 @@
interface HTMLScriptElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions]
- attribute USVString src;
+ [CEReactions, SetterThrows]
+ attribute (TrustedScriptURL or USVString) src;
[CEReactions]
attribute DOMString type;
[CEReactions]
diff --git a/components/script_bindings/webidls/Window.webidl b/components/script_bindings/webidls/Window.webidl
index c7b6dde617d..d42ba22ea66 100644
--- a/components/script_bindings/webidls/Window.webidl
+++ b/components/script_bindings/webidls/Window.webidl
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#window
-[Global=Window, Exposed=Window /*, LegacyUnenumerableNamedProperties */]
+[Global=Window, Exposed=Window, LegacyUnenumerableNamedProperties, NeedResolve]
/*sealed*/ interface Window : GlobalScope {
// the current browsing context
[LegacyUnforgeable, CrossOriginReadable] readonly attribute WindowProxy window;
diff --git a/components/servo/webview.rs b/components/servo/webview.rs
index f4bf13e3a7e..95eb6dfd154 100644
--- a/components/servo/webview.rs
+++ b/components/servo/webview.rs
@@ -9,7 +9,7 @@ use std::time::Duration;
use base::id::WebViewId;
use compositing::IOCompositor;
-use compositing_traits::RendererWebView;
+use compositing_traits::WebViewTrait;
use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use dpi::PhysicalSize;
use embedder_traits::{
@@ -558,7 +558,7 @@ struct ServoRendererWebView {
weak_handle: Weak<RefCell<WebViewInner>>,
}
-impl RendererWebView for ServoRendererWebView {
+impl WebViewTrait for ServoRendererWebView {
fn id(&self) -> WebViewId {
self.id
}
diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs
index 7c2bd669d02..31371f87529 100644
--- a/components/shared/compositing/lib.rs
+++ b/components/shared/compositing/lib.rs
@@ -541,7 +541,7 @@ impl From<SerializableImageData> for ImageData {
/// A trait that exposes the embedding layer's `WebView` to the Servo renderer.
/// This is to prevent a dependency cycle between the renderer and the embedding
/// layer.
-pub trait RendererWebView {
+pub trait WebViewTrait {
fn id(&self) -> WebViewId;
fn screen_geometry(&self) -> Option<ScreenGeometry>;
fn set_animating(&self, new_value: bool);
diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs
index bccb3059e24..8346551fd15 100644
--- a/components/shared/constellation/from_script_message.rs
+++ b/components/shared/constellation/from_script_message.rs
@@ -33,10 +33,8 @@ use strum_macros::IntoStaticStr;
use webgpu_traits::{WebGPU, WebGPUAdapterResponse};
use webrender_api::ImageKey;
-use crate::message_port::{
- BroadcastMsg, MessagePortMsg, PortMessageTask, StructuredSerializedData,
-};
-use crate::{LogEntry, TraversalDirection, WindowSizeType};
+use crate::structured_data::{BroadcastMsg, StructuredSerializedData};
+use crate::{LogEntry, MessagePortMsg, PortMessageTask, TraversalDirection, WindowSizeType};
/// A Script to Constellation channel.
#[derive(Clone, Debug, Deserialize, Serialize)]
diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs
index 627741a40fb..548e17b532c 100644
--- a/components/shared/constellation/lib.rs
+++ b/components/shared/constellation/lib.rs
@@ -9,15 +9,15 @@
//! on other parts of Servo.
mod from_script_message;
-mod message_port;
+mod structured_data;
-use std::collections::HashMap;
+use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::time::Duration;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
-use base::id::{PipelineId, WebViewId};
+use base::id::{MessagePortId, PipelineId, WebViewId};
use bitflags::bitflags;
use embedder_traits::{
CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
@@ -27,9 +27,9 @@ use euclid::Vector2D;
pub use from_script_message::*;
use ipc_channel::ipc::IpcSender;
use malloc_size_of_derive::MallocSizeOf;
-pub use message_port::*;
use serde::{Deserialize, Serialize};
-use servo_url::ServoUrl;
+use servo_url::{ImmutableOrigin, ServoUrl};
+pub use structured_data::*;
use strum_macros::IntoStaticStr;
use webrender_api::ExternalScrollId;
use webrender_api::units::LayoutPixel;
@@ -158,3 +158,28 @@ pub enum TraversalDirection {
/// Travel backward the given number of documents.
Back(usize),
}
+
+/// 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)]
+#[allow(clippy::large_enum_variant)]
+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),
+}
diff --git a/components/shared/constellation/message_port.rs b/components/shared/constellation/message_port.rs
deleted file mode 100644
index bb2929353af..00000000000
--- a/components/shared/constellation/message_port.rs
+++ /dev/null
@@ -1,566 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-//! This module contains data structures used for message ports and serializing
-//! DOM objects to send across them as per
-//! <https://html.spec.whatwg.org/multipage/#serializable-objects>.
-//! The implementations are here instead of in `script``, because these
-//! types can be sent through the Constellation to other ScriptThreads,
-//! and Constellation cannot depend directly on `script`.
-
-use std::cell::RefCell;
-use std::collections::{HashMap, VecDeque};
-use std::path::PathBuf;
-
-use base::id::{BlobId, DomExceptionId, DomPointId, MessagePortId};
-use log::warn;
-use malloc_size_of_derive::MallocSizeOf;
-use net_traits::filemanager_thread::RelativePos;
-use serde::{Deserialize, Serialize};
-use servo_url::ImmutableOrigin;
-use strum::{EnumIter, IntoEnumIterator};
-use uuid::Uuid;
-
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-enum MessagePortState {
- /// <https://html.spec.whatwg.org/multipage/#detached>
- Detached,
- /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
- /// The message-queue of this port is enabled,
- /// the boolean represents awaiting completion of a transfer.
- Enabled(bool),
- /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
- /// The message-queue of this port is disabled,
- /// the boolean represents awaiting completion of a transfer.
- Disabled(bool),
-}
-
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-/// The data and logic backing the DOM managed MessagePort.
-pub struct MessagePortImpl {
- /// The current state of the port.
- state: MessagePortState,
-
- /// <https://html.spec.whatwg.org/multipage/#entangle>
- entangled_port: Option<MessagePortId>,
-
- /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
- message_buffer: Option<VecDeque<PortMessageTask>>,
-
- /// The UUID of this port.
- message_port_id: MessagePortId,
-}
-
-impl MessagePortImpl {
- /// Create a new messageport impl.
- pub fn new(port_id: MessagePortId) -> MessagePortImpl {
- MessagePortImpl {
- state: MessagePortState::Disabled(false),
- entangled_port: None,
- message_buffer: None,
- message_port_id: port_id,
- }
- }
-
- /// Get the Id.
- pub fn message_port_id(&self) -> &MessagePortId {
- &self.message_port_id
- }
-
- /// Maybe get the Id of the entangled port.
- pub fn entangled_port_id(&self) -> Option<MessagePortId> {
- self.entangled_port
- }
-
- /// Entanged this port with another.
- pub fn entangle(&mut self, other_id: MessagePortId) {
- self.entangled_port = Some(other_id);
- }
-
- /// Is this port enabled?
- pub fn enabled(&self) -> bool {
- matches!(self.state, MessagePortState::Enabled(_))
- }
-
- /// Mark this port as having been shipped.
- /// <https://html.spec.whatwg.org/multipage/#has-been-shipped>
- pub fn set_has_been_shipped(&mut self) {
- match self.state {
- MessagePortState::Detached => {
- panic!("Messageport set_has_been_shipped called in detached state")
- },
- MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(true),
- MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(true),
- }
- }
-
- /// Handle the completion of the transfer,
- /// this is data received from the constellation.
- pub fn complete_transfer(&mut self, mut tasks: VecDeque<PortMessageTask>) {
- match self.state {
- MessagePortState::Detached => return,
- MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(false),
- MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(false),
- }
-
- // Note: these are the tasks that were buffered while the transfer was ongoing,
- // hence they need to execute first.
- // The global will call `start` if we are enabled,
- // which will add tasks on the event-loop to dispatch incoming messages.
- match self.message_buffer {
- Some(ref mut incoming_buffer) => {
- while let Some(task) = tasks.pop_back() {
- incoming_buffer.push_front(task);
- }
- },
- None => self.message_buffer = Some(tasks),
- }
- }
-
- /// A message was received from our entangled port,
- /// returns an optional task to be dispatched.
- pub fn handle_incoming(&mut self, task: PortMessageTask) -> Option<PortMessageTask> {
- let should_dispatch = match self.state {
- MessagePortState::Detached => return None,
- MessagePortState::Enabled(in_transfer) => !in_transfer,
- MessagePortState::Disabled(_) => false,
- };
-
- if should_dispatch {
- Some(task)
- } else {
- match self.message_buffer {
- Some(ref mut buffer) => {
- buffer.push_back(task);
- },
- None => {
- let mut queue = VecDeque::new();
- queue.push_back(task);
- self.message_buffer = Some(queue);
- },
- }
- None
- }
- }
-
- /// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
- /// returns an optional queue of tasks that were buffered while the port was disabled.
- pub fn start(&mut self) -> Option<VecDeque<PortMessageTask>> {
- match self.state {
- MessagePortState::Detached => return None,
- MessagePortState::Enabled(_) => {},
- MessagePortState::Disabled(in_transfer) => {
- self.state = MessagePortState::Enabled(in_transfer);
- },
- }
- if let MessagePortState::Enabled(true) = self.state {
- return None;
- }
- self.message_buffer.take()
- }
-
- /// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
- pub fn close(&mut self) {
- // Step 1
- self.state = MessagePortState::Detached;
- }
-}
-
-/// A data-holder for serialized data and transferred objects.
-/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
-#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)]
-pub struct StructuredSerializedData {
- /// Data serialized by SpiderMonkey.
- pub serialized: Vec<u8>,
- /// Serialized in a structured callback,
- pub blobs: Option<HashMap<BlobId, BlobImpl>>,
- /// Serialized point objects.
- pub points: Option<HashMap<DomPointId, DomPoint>>,
- /// Serialized exception objects.
- pub exceptions: Option<HashMap<DomExceptionId, DomException>>,
- /// Transferred objects.
- pub ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
-}
-
-pub(crate) trait BroadcastClone
-where
- Self: Sized,
-{
- /// The ID type that uniquely identify each value.
- type Id: Eq + std::hash::Hash + Copy;
- /// Clone this value so that it can be reused with a broadcast channel.
- /// Only return None if cloning is impossible.
- fn clone_for_broadcast(&self) -> Option<Self>;
- /// The field from which to clone values.
- fn source(data: &StructuredSerializedData) -> &Option<HashMap<Self::Id, Self>>;
- /// The field into which to place cloned values.
- fn destination(data: &mut StructuredSerializedData) -> &mut Option<HashMap<Self::Id, Self>>;
-}
-
-/// All the DOM interfaces that can be serialized.
-#[derive(Clone, Copy, Debug, EnumIter)]
-pub enum Serializable {
- /// The `Blob` interface.
- Blob,
- /// The `DOMPoint` interface.
- DomPoint,
- /// The `DOMPointReadOnly` interface.
- DomPointReadOnly,
- /// The `DOMException` interface.
- DomException,
-}
-
-impl Serializable {
- fn clone_values(&self) -> fn(&StructuredSerializedData, &mut StructuredSerializedData) {
- match self {
- Serializable::Blob => StructuredSerializedData::clone_all_of_type::<BlobImpl>,
- Serializable::DomPointReadOnly => {
- StructuredSerializedData::clone_all_of_type::<DomPoint>
- },
- Serializable::DomPoint => StructuredSerializedData::clone_all_of_type::<DomPoint>,
- Serializable::DomException => {
- StructuredSerializedData::clone_all_of_type::<DomException>
- },
- }
- }
-}
-
-/// All the DOM interfaces that can be transferred.
-#[derive(Clone, Copy, Debug, EnumIter)]
-pub enum Transferrable {
- /// The `MessagePort` interface.
- MessagePort,
- /// The `ReadableStream` interface.
- ReadableStream,
- /// The `WritableStream` interface.
- WritableStream,
-}
-
-impl StructuredSerializedData {
- fn is_empty(&self, val: Transferrable) -> bool {
- fn is_field_empty<K, V>(field: &Option<HashMap<K, V>>) -> bool {
- field.as_ref().is_some_and(|h| h.is_empty())
- }
- match val {
- Transferrable::MessagePort => is_field_empty(&self.ports),
- Transferrable::ReadableStream => is_field_empty(&self.ports),
- Transferrable::WritableStream => is_field_empty(&self.ports),
- }
- }
-
- /// Clone all values of the same type stored in this StructuredSerializedData
- /// into another instance.
- fn clone_all_of_type<T: BroadcastClone>(&self, cloned: &mut StructuredSerializedData) {
- let existing = T::source(self);
- let Some(existing) = existing else { return };
- let mut clones = HashMap::with_capacity(existing.len());
-
- for (original_id, obj) in existing.iter() {
- if let Some(clone) = obj.clone_for_broadcast() {
- clones.insert(*original_id, clone);
- }
- }
-
- *T::destination(cloned) = Some(clones);
- }
-
- /// Clone the serialized data for use with broadcast-channels.
- pub fn clone_for_broadcast(&self) -> StructuredSerializedData {
- for transferrable in Transferrable::iter() {
- if !self.is_empty(transferrable) {
- // Not panicking only because this is called from the constellation.
- warn!(
- "Attempt to broadcast structured serialized data including {:?} (should never happen).",
- transferrable,
- );
- }
- }
-
- let serialized = self.serialized.clone();
-
- let mut cloned = StructuredSerializedData {
- serialized,
- ..Default::default()
- };
-
- for serializable in Serializable::iter() {
- let clone_impl = serializable.clone_values();
- clone_impl(self, &mut cloned);
- }
-
- cloned
- }
-}
-
-/// A task on the <https://html.spec.whatwg.org/multipage/#port-message-queue>
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-pub struct PortMessageTask {
- /// The origin of this task.
- pub origin: ImmutableOrigin,
- /// A data-holder for serialized data and transferred objects.
- pub data: StructuredSerializedData,
-}
-
-/// Messages for communication between the constellation and a global managing ports.
-#[derive(Debug, Deserialize, Serialize)]
-#[allow(clippy::large_enum_variant)]
-pub enum MessagePortMsg {
- /// Complete the transfer for a batch of ports.
- CompleteTransfer(HashMap<MessagePortId, VecDeque<PortMessageTask>>),
- /// Complete the transfer of a single port,
- /// whose transfer was pending because it had been requested
- /// while a previous failed transfer was being rolled-back.
- CompletePendingTransfer(MessagePortId, VecDeque<PortMessageTask>),
- /// Remove a port, the entangled one doesn't exists anymore.
- RemoveMessagePort(MessagePortId),
- /// Handle a new port-message-task.
- NewTask(MessagePortId, PortMessageTask),
-}
-
-/// Message for communication between the constellation and a global managing broadcast channels.
-#[derive(Debug, Deserialize, Serialize)]
-pub struct BroadcastMsg {
- /// The origin of this message.
- pub origin: ImmutableOrigin,
- /// The name of the channel.
- pub channel_name: String,
- /// A data-holder for serialized data.
- pub data: StructuredSerializedData,
-}
-
-impl Clone for BroadcastMsg {
- fn clone(&self) -> BroadcastMsg {
- BroadcastMsg {
- data: self.data.clone_for_broadcast(),
- origin: self.origin.clone(),
- channel_name: self.channel_name.clone(),
- }
- }
-}
-
-/// File-based blob
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-pub struct FileBlob {
- #[ignore_malloc_size_of = "Uuid are hard(not really)"]
- id: Uuid,
- #[ignore_malloc_size_of = "PathBuf are hard"]
- name: Option<PathBuf>,
- cache: RefCell<Option<Vec<u8>>>,
- size: u64,
-}
-
-impl FileBlob {
- /// Create a new file blob.
- pub fn new(id: Uuid, name: Option<PathBuf>, cache: Option<Vec<u8>>, size: u64) -> FileBlob {
- FileBlob {
- id,
- name,
- cache: RefCell::new(cache),
- size,
- }
- }
-
- /// Get the size of the file.
- pub fn get_size(&self) -> u64 {
- self.size
- }
-
- /// Get the cached file data, if any.
- pub fn get_cache(&self) -> Option<Vec<u8>> {
- self.cache.borrow().clone()
- }
-
- /// Cache data.
- pub fn cache_bytes(&self, bytes: Vec<u8>) {
- *self.cache.borrow_mut() = Some(bytes);
- }
-
- /// Get the file id.
- pub fn get_id(&self) -> Uuid {
- self.id
- }
-}
-
-impl BroadcastClone for BlobImpl {
- type Id = BlobId;
-
- fn source(
- data: &StructuredSerializedData,
- ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
- &data.blobs
- }
-
- fn destination(
- data: &mut StructuredSerializedData,
- ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
- &mut data.blobs
- }
-
- fn clone_for_broadcast(&self) -> Option<Self> {
- let type_string = self.type_string();
-
- if let BlobData::Memory(bytes) = self.blob_data() {
- let blob_clone = BlobImpl::new_from_bytes(bytes.clone(), type_string);
-
- // Note: we insert the blob at the original id,
- // otherwise this will not match the storage key as serialized by SM in `serialized`.
- // The clone has it's own new Id however.
- return Some(blob_clone);
- } else {
- // Not panicking only because this is called from the constellation.
- log::warn!("Serialized blob not in memory format(should never happen).");
- }
- None
- }
-}
-
-/// The data backing a DOM Blob.
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-pub struct BlobImpl {
- /// UUID of the blob.
- blob_id: BlobId,
- /// Content-type string
- type_string: String,
- /// Blob data-type.
- blob_data: BlobData,
- /// Sliced blobs referring to this one.
- slices: Vec<BlobId>,
-}
-
-/// Different backends of Blob
-#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
-pub enum BlobData {
- /// File-based blob, whose content lives in the net process
- File(FileBlob),
- /// Memory-based blob, whose content lives in the script process
- Memory(Vec<u8>),
- /// Sliced blob, including parent blob-id and
- /// relative positions of current slicing range,
- /// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
- /// either File-based or Memory-based
- Sliced(BlobId, RelativePos),
-}
-
-impl BlobImpl {
- /// Construct memory-backed BlobImpl
- pub fn new_from_bytes(bytes: Vec<u8>, type_string: String) -> BlobImpl {
- let blob_id = BlobId::new();
- let blob_data = BlobData::Memory(bytes);
- BlobImpl {
- blob_id,
- type_string,
- blob_data,
- slices: vec![],
- }
- }
-
- /// Construct file-backed BlobImpl from File ID
- pub fn new_from_file(file_id: Uuid, name: PathBuf, size: u64, type_string: String) -> BlobImpl {
- let blob_id = BlobId::new();
- let blob_data = BlobData::File(FileBlob {
- id: file_id,
- name: Some(name),
- cache: RefCell::new(None),
- size,
- });
- BlobImpl {
- blob_id,
- type_string,
- blob_data,
- slices: vec![],
- }
- }
-
- /// Construct a BlobImpl from a slice of a parent.
- pub fn new_sliced(rel_pos: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
- let blob_id = BlobId::new();
- let blob_data = BlobData::Sliced(parent, rel_pos);
- BlobImpl {
- blob_id,
- type_string,
- blob_data,
- slices: vec![],
- }
- }
-
- /// Get a clone of the blob-id
- pub fn blob_id(&self) -> BlobId {
- self.blob_id
- }
-
- /// Get a clone of the type-string
- pub fn type_string(&self) -> String {
- self.type_string.clone()
- }
-
- /// Get a mutable ref to the data
- pub fn blob_data(&self) -> &BlobData {
- &self.blob_data
- }
-
- /// Get a mutable ref to the data
- pub fn blob_data_mut(&mut self) -> &mut BlobData {
- &mut self.blob_data
- }
-}
-
-#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
-/// A serializable version of the DOMPoint/DOMPointReadOnly interface.
-pub struct DomPoint {
- /// The x coordinate.
- pub x: f64,
- /// The y coordinate.
- pub y: f64,
- /// The z coordinate.
- pub z: f64,
- /// The w coordinate.
- pub w: f64,
-}
-
-impl BroadcastClone for DomPoint {
- type Id = DomPointId;
-
- fn source(
- data: &StructuredSerializedData,
- ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
- &data.points
- }
-
- fn destination(
- data: &mut StructuredSerializedData,
- ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
- &mut data.points
- }
-
- fn clone_for_broadcast(&self) -> Option<Self> {
- Some(self.clone())
- }
-}
-
-#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
-/// A serializable version of the DOMException interface.
-pub struct DomException {
- pub message: String,
- pub name: String,
-}
-
-impl BroadcastClone for DomException {
- type Id = DomExceptionId;
-
- fn source(
- data: &StructuredSerializedData,
- ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
- &data.exceptions
- }
-
- fn destination(
- data: &mut StructuredSerializedData,
- ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
- &mut data.exceptions
- }
-
- fn clone_for_broadcast(&self) -> Option<Self> {
- Some(self.clone())
- }
-}
diff --git a/components/shared/constellation/structured_data/mod.rs b/components/shared/constellation/structured_data/mod.rs
new file mode 100644
index 00000000000..41fc05493a2
--- /dev/null
+++ b/components/shared/constellation/structured_data/mod.rs
@@ -0,0 +1,91 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! This module contains implementations of structured data as described in
+//! <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data>
+
+mod serializable;
+mod transferable;
+
+use std::collections::HashMap;
+
+use base::id::{BlobId, DomExceptionId, DomPointId, MessagePortId};
+use log::warn;
+use malloc_size_of_derive::MallocSizeOf;
+use serde::{Deserialize, Serialize};
+pub use serializable::*;
+use strum::IntoEnumIterator;
+pub use transferable::*;
+
+/// A data-holder for serialized data and transferred objects.
+/// <https://html.spec.whatwg.org/multipage/#structuredserializewithtransfer>
+#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)]
+pub struct StructuredSerializedData {
+ /// Data serialized by SpiderMonkey.
+ pub serialized: Vec<u8>,
+ /// Serialized in a structured callback,
+ pub blobs: Option<HashMap<BlobId, BlobImpl>>,
+ /// Serialized point objects.
+ pub points: Option<HashMap<DomPointId, DomPoint>>,
+ /// Serialized exception objects.
+ pub exceptions: Option<HashMap<DomExceptionId, DomException>>,
+ /// Transferred objects.
+ pub ports: Option<HashMap<MessagePortId, MessagePortImpl>>,
+}
+
+impl StructuredSerializedData {
+ fn is_empty(&self, val: Transferrable) -> bool {
+ fn is_field_empty<K, V>(field: &Option<HashMap<K, V>>) -> bool {
+ field.as_ref().is_some_and(|h| h.is_empty())
+ }
+ match val {
+ Transferrable::MessagePort => is_field_empty(&self.ports),
+ Transferrable::ReadableStream => is_field_empty(&self.ports),
+ Transferrable::WritableStream => is_field_empty(&self.ports),
+ }
+ }
+
+ /// Clone all values of the same type stored in this StructuredSerializedData
+ /// into another instance.
+ fn clone_all_of_type<T: BroadcastClone>(&self, cloned: &mut StructuredSerializedData) {
+ let existing = T::source(self);
+ let Some(existing) = existing else { return };
+ let mut clones = HashMap::with_capacity(existing.len());
+
+ for (original_id, obj) in existing.iter() {
+ if let Some(clone) = obj.clone_for_broadcast() {
+ clones.insert(*original_id, clone);
+ }
+ }
+
+ *T::destination(cloned) = Some(clones);
+ }
+
+ /// Clone the serialized data for use with broadcast-channels.
+ pub fn clone_for_broadcast(&self) -> StructuredSerializedData {
+ for transferrable in Transferrable::iter() {
+ if !self.is_empty(transferrable) {
+ // Not panicking only because this is called from the constellation.
+ warn!(
+ "Attempt to broadcast structured serialized data including {:?} (should never happen).",
+ transferrable,
+ );
+ }
+ }
+
+ let serialized = self.serialized.clone();
+
+ let mut cloned = StructuredSerializedData {
+ serialized,
+ ..Default::default()
+ };
+
+ for serializable in Serializable::iter() {
+ let clone_impl = serializable.clone_values();
+ clone_impl(self, &mut cloned);
+ }
+
+ cloned
+ }
+}
diff --git a/components/shared/constellation/structured_data/serializable.rs b/components/shared/constellation/structured_data/serializable.rs
new file mode 100644
index 00000000000..abc05ad5758
--- /dev/null
+++ b/components/shared/constellation/structured_data/serializable.rs
@@ -0,0 +1,314 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! This module contains implementations in script that are serializable,
+//! as per <https://html.spec.whatwg.org/multipage/#serializable-objects>.
+//! The implementations are here instead of in script as they need to
+//! be passed through the Constellation.
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::path::PathBuf;
+
+use base::id::{BlobId, DomExceptionId, DomPointId};
+use malloc_size_of_derive::MallocSizeOf;
+use net_traits::filemanager_thread::RelativePos;
+use serde::{Deserialize, Serialize};
+use servo_url::ImmutableOrigin;
+use strum::EnumIter;
+use uuid::Uuid;
+
+use super::StructuredSerializedData;
+
+pub(crate) trait BroadcastClone
+where
+ Self: Sized,
+{
+ /// The ID type that uniquely identify each value.
+ type Id: Eq + std::hash::Hash + Copy;
+ /// Clone this value so that it can be reused with a broadcast channel.
+ /// Only return None if cloning is impossible.
+ fn clone_for_broadcast(&self) -> Option<Self>;
+ /// The field from which to clone values.
+ fn source(data: &StructuredSerializedData) -> &Option<HashMap<Self::Id, Self>>;
+ /// The field into which to place cloned values.
+ fn destination(data: &mut StructuredSerializedData) -> &mut Option<HashMap<Self::Id, Self>>;
+}
+
+/// All the DOM interfaces that can be serialized.
+#[derive(Clone, Copy, Debug, EnumIter)]
+pub enum Serializable {
+ /// The `Blob` interface.
+ Blob,
+ /// The `DOMPoint` interface.
+ DomPoint,
+ /// The `DOMPointReadOnly` interface.
+ DomPointReadOnly,
+ /// The `DOMException` interface.
+ DomException,
+}
+
+impl Serializable {
+ pub(super) fn clone_values(
+ &self,
+ ) -> fn(&StructuredSerializedData, &mut StructuredSerializedData) {
+ match self {
+ Serializable::Blob => StructuredSerializedData::clone_all_of_type::<BlobImpl>,
+ Serializable::DomPointReadOnly => {
+ StructuredSerializedData::clone_all_of_type::<DomPoint>
+ },
+ Serializable::DomPoint => StructuredSerializedData::clone_all_of_type::<DomPoint>,
+ Serializable::DomException => {
+ StructuredSerializedData::clone_all_of_type::<DomException>
+ },
+ }
+ }
+}
+
+/// Message for communication between the constellation and a global managing broadcast channels.
+#[derive(Debug, Deserialize, Serialize)]
+pub struct BroadcastMsg {
+ /// The origin of this message.
+ pub origin: ImmutableOrigin,
+ /// The name of the channel.
+ pub channel_name: String,
+ /// A data-holder for serialized data.
+ pub data: StructuredSerializedData,
+}
+
+impl Clone for BroadcastMsg {
+ fn clone(&self) -> BroadcastMsg {
+ BroadcastMsg {
+ data: self.data.clone_for_broadcast(),
+ origin: self.origin.clone(),
+ channel_name: self.channel_name.clone(),
+ }
+ }
+}
+
+/// File-based blob
+#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+pub struct FileBlob {
+ #[ignore_malloc_size_of = "Uuid are hard(not really)"]
+ id: Uuid,
+ #[ignore_malloc_size_of = "PathBuf are hard"]
+ name: Option<PathBuf>,
+ cache: RefCell<Option<Vec<u8>>>,
+ size: u64,
+}
+
+impl FileBlob {
+ /// Create a new file blob.
+ pub fn new(id: Uuid, name: Option<PathBuf>, cache: Option<Vec<u8>>, size: u64) -> FileBlob {
+ FileBlob {
+ id,
+ name,
+ cache: RefCell::new(cache),
+ size,
+ }
+ }
+
+ /// Get the size of the file.
+ pub fn get_size(&self) -> u64 {
+ self.size
+ }
+
+ /// Get the cached file data, if any.
+ pub fn get_cache(&self) -> Option<Vec<u8>> {
+ self.cache.borrow().clone()
+ }
+
+ /// Cache data.
+ pub fn cache_bytes(&self, bytes: Vec<u8>) {
+ *self.cache.borrow_mut() = Some(bytes);
+ }
+
+ /// Get the file id.
+ pub fn get_id(&self) -> Uuid {
+ self.id
+ }
+}
+
+impl BroadcastClone for BlobImpl {
+ type Id = BlobId;
+
+ fn source(
+ data: &StructuredSerializedData,
+ ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
+ &data.blobs
+ }
+
+ fn destination(
+ data: &mut StructuredSerializedData,
+ ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
+ &mut data.blobs
+ }
+
+ fn clone_for_broadcast(&self) -> Option<Self> {
+ let type_string = self.type_string();
+
+ if let BlobData::Memory(bytes) = self.blob_data() {
+ let blob_clone = BlobImpl::new_from_bytes(bytes.clone(), type_string);
+
+ // Note: we insert the blob at the original id,
+ // otherwise this will not match the storage key as serialized by SM in `serialized`.
+ // The clone has it's own new Id however.
+ return Some(blob_clone);
+ } else {
+ // Not panicking only because this is called from the constellation.
+ log::warn!("Serialized blob not in memory format(should never happen).");
+ }
+ None
+ }
+}
+
+/// The data backing a DOM Blob.
+#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+pub struct BlobImpl {
+ /// UUID of the blob.
+ blob_id: BlobId,
+ /// Content-type string
+ type_string: String,
+ /// Blob data-type.
+ blob_data: BlobData,
+ /// Sliced blobs referring to this one.
+ slices: Vec<BlobId>,
+}
+
+/// Different backends of Blob
+#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+pub enum BlobData {
+ /// File-based blob, whose content lives in the net process
+ File(FileBlob),
+ /// Memory-based blob, whose content lives in the script process
+ Memory(Vec<u8>),
+ /// Sliced blob, including parent blob-id and
+ /// relative positions of current slicing range,
+ /// IMPORTANT: The depth of tree is only two, i.e. the parent Blob must be
+ /// either File-based or Memory-based
+ Sliced(BlobId, RelativePos),
+}
+
+impl BlobImpl {
+ /// Construct memory-backed BlobImpl
+ pub fn new_from_bytes(bytes: Vec<u8>, type_string: String) -> BlobImpl {
+ let blob_id = BlobId::new();
+ let blob_data = BlobData::Memory(bytes);
+ BlobImpl {
+ blob_id,
+ type_string,
+ blob_data,
+ slices: vec![],
+ }
+ }
+
+ /// Construct file-backed BlobImpl from File ID
+ pub fn new_from_file(file_id: Uuid, name: PathBuf, size: u64, type_string: String) -> BlobImpl {
+ let blob_id = BlobId::new();
+ let blob_data = BlobData::File(FileBlob {
+ id: file_id,
+ name: Some(name),
+ cache: RefCell::new(None),
+ size,
+ });
+ BlobImpl {
+ blob_id,
+ type_string,
+ blob_data,
+ slices: vec![],
+ }
+ }
+
+ /// Construct a BlobImpl from a slice of a parent.
+ pub fn new_sliced(rel_pos: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
+ let blob_id = BlobId::new();
+ let blob_data = BlobData::Sliced(parent, rel_pos);
+ BlobImpl {
+ blob_id,
+ type_string,
+ blob_data,
+ slices: vec![],
+ }
+ }
+
+ /// Get a clone of the blob-id
+ pub fn blob_id(&self) -> BlobId {
+ self.blob_id
+ }
+
+ /// Get a clone of the type-string
+ pub fn type_string(&self) -> String {
+ self.type_string.clone()
+ }
+
+ /// Get a mutable ref to the data
+ pub fn blob_data(&self) -> &BlobData {
+ &self.blob_data
+ }
+
+ /// Get a mutable ref to the data
+ pub fn blob_data_mut(&mut self) -> &mut BlobData {
+ &mut self.blob_data
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
+/// A serializable version of the DOMPoint/DOMPointReadOnly interface.
+pub struct DomPoint {
+ /// The x coordinate.
+ pub x: f64,
+ /// The y coordinate.
+ pub y: f64,
+ /// The z coordinate.
+ pub z: f64,
+ /// The w coordinate.
+ pub w: f64,
+}
+
+impl BroadcastClone for DomPoint {
+ type Id = DomPointId;
+
+ fn source(
+ data: &StructuredSerializedData,
+ ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
+ &data.points
+ }
+
+ fn destination(
+ data: &mut StructuredSerializedData,
+ ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
+ &mut data.points
+ }
+
+ fn clone_for_broadcast(&self) -> Option<Self> {
+ Some(self.clone())
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
+/// A serializable version of the DOMException interface.
+pub struct DomException {
+ pub message: String,
+ pub name: String,
+}
+
+impl BroadcastClone for DomException {
+ type Id = DomExceptionId;
+
+ fn source(
+ data: &StructuredSerializedData,
+ ) -> &Option<std::collections::HashMap<Self::Id, Self>> {
+ &data.exceptions
+ }
+
+ fn destination(
+ data: &mut StructuredSerializedData,
+ ) -> &mut Option<std::collections::HashMap<Self::Id, Self>> {
+ &mut data.exceptions
+ }
+
+ fn clone_for_broadcast(&self) -> Option<Self> {
+ Some(self.clone())
+ }
+}
diff --git a/components/shared/constellation/structured_data/transferable.rs b/components/shared/constellation/structured_data/transferable.rs
new file mode 100644
index 00000000000..cd6388f5f34
--- /dev/null
+++ b/components/shared/constellation/structured_data/transferable.rs
@@ -0,0 +1,172 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! This module contains implementations in script that are transferable as per
+//! <https://html.spec.whatwg.org/multipage/#transferable-objects>. The implementations are here
+//! instead of in script as they need to be passed through the Constellation.
+
+use std::collections::VecDeque;
+
+use base::id::MessagePortId;
+use malloc_size_of_derive::MallocSizeOf;
+use serde::{Deserialize, Serialize};
+use strum::EnumIter;
+
+use crate::PortMessageTask;
+
+/// All the DOM interfaces that can be transferred.
+#[derive(Clone, Copy, Debug, EnumIter)]
+pub enum Transferrable {
+ /// The `MessagePort` interface.
+ MessagePort,
+ /// The `ReadableStream` interface.
+ ReadableStream,
+ /// The `WritableStream` interface.
+ WritableStream,
+}
+
+#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+enum MessagePortState {
+ /// <https://html.spec.whatwg.org/multipage/#detached>
+ Detached,
+ /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
+ /// The message-queue of this port is enabled,
+ /// the boolean represents awaiting completion of a transfer.
+ Enabled(bool),
+ /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
+ /// The message-queue of this port is disabled,
+ /// the boolean represents awaiting completion of a transfer.
+ Disabled(bool),
+}
+
+#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
+/// The data and logic backing the DOM managed MessagePort.
+pub struct MessagePortImpl {
+ /// The current state of the port.
+ state: MessagePortState,
+
+ /// <https://html.spec.whatwg.org/multipage/#entangle>
+ entangled_port: Option<MessagePortId>,
+
+ /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
+ message_buffer: Option<VecDeque<PortMessageTask>>,
+
+ /// The UUID of this port.
+ message_port_id: MessagePortId,
+}
+
+impl MessagePortImpl {
+ /// Create a new messageport impl.
+ pub fn new(port_id: MessagePortId) -> MessagePortImpl {
+ MessagePortImpl {
+ state: MessagePortState::Disabled(false),
+ entangled_port: None,
+ message_buffer: None,
+ message_port_id: port_id,
+ }
+ }
+
+ /// Get the Id.
+ pub fn message_port_id(&self) -> &MessagePortId {
+ &self.message_port_id
+ }
+
+ /// Maybe get the Id of the entangled port.
+ pub fn entangled_port_id(&self) -> Option<MessagePortId> {
+ self.entangled_port
+ }
+
+ /// Entanged this port with another.
+ pub fn entangle(&mut self, other_id: MessagePortId) {
+ self.entangled_port = Some(other_id);
+ }
+
+ /// Is this port enabled?
+ pub fn enabled(&self) -> bool {
+ matches!(self.state, MessagePortState::Enabled(_))
+ }
+
+ /// Mark this port as having been shipped.
+ /// <https://html.spec.whatwg.org/multipage/#has-been-shipped>
+ pub fn set_has_been_shipped(&mut self) {
+ match self.state {
+ MessagePortState::Detached => {
+ panic!("Messageport set_has_been_shipped called in detached state")
+ },
+ MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(true),
+ MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(true),
+ }
+ }
+
+ /// Handle the completion of the transfer,
+ /// this is data received from the constellation.
+ pub fn complete_transfer(&mut self, mut tasks: VecDeque<PortMessageTask>) {
+ match self.state {
+ MessagePortState::Detached => return,
+ MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(false),
+ MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(false),
+ }
+
+ // Note: these are the tasks that were buffered while the transfer was ongoing,
+ // hence they need to execute first.
+ // The global will call `start` if we are enabled,
+ // which will add tasks on the event-loop to dispatch incoming messages.
+ match self.message_buffer {
+ Some(ref mut incoming_buffer) => {
+ while let Some(task) = tasks.pop_back() {
+ incoming_buffer.push_front(task);
+ }
+ },
+ None => self.message_buffer = Some(tasks),
+ }
+ }
+
+ /// A message was received from our entangled port,
+ /// returns an optional task to be dispatched.
+ pub fn handle_incoming(&mut self, task: PortMessageTask) -> Option<PortMessageTask> {
+ let should_dispatch = match self.state {
+ MessagePortState::Detached => return None,
+ MessagePortState::Enabled(in_transfer) => !in_transfer,
+ MessagePortState::Disabled(_) => false,
+ };
+
+ if should_dispatch {
+ Some(task)
+ } else {
+ match self.message_buffer {
+ Some(ref mut buffer) => {
+ buffer.push_back(task);
+ },
+ None => {
+ let mut queue = VecDeque::new();
+ queue.push_back(task);
+ self.message_buffer = Some(queue);
+ },
+ }
+ None
+ }
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
+ /// returns an optional queue of tasks that were buffered while the port was disabled.
+ pub fn start(&mut self) -> Option<VecDeque<PortMessageTask>> {
+ match self.state {
+ MessagePortState::Detached => return None,
+ MessagePortState::Enabled(_) => {},
+ MessagePortState::Disabled(in_transfer) => {
+ self.state = MessagePortState::Enabled(in_transfer);
+ },
+ }
+ if let MessagePortState::Enabled(true) = self.state {
+ return None;
+ }
+ self.message_buffer.take()
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
+ pub fn close(&mut self) {
+ // Step 1
+ self.state = MessagePortState::Detached;
+ }
+}
diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs
index 16adccf8cd3..0268be6dd9c 100644
--- a/components/shared/embedder/input_events.rs
+++ b/components/shared/embedder/input_events.rs
@@ -51,7 +51,7 @@ pub struct MouseButtonEvent {
pub point: DevicePoint,
}
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum MouseButton {
Left,
Middle,