Include WebViewId into EmbedderMsg variants where possible (#35211)

`EmbedderMsg` was previously paired with an implicit
`Option<WebViewId>`, even though almost all variants were either always
`Some` or always `None`, depending on whether there was a `WebView
involved.

This patch adds the `WebViewId` to as many `EmbedderMsg` variants as
possible, so we can call their associated `WebView` delegate methods
without needing to check and unwrap the `Option`. In many cases, this
required more changes to plumb through the `WebViewId`.

Notably, all `Request`s now explicitly need a `WebView` or not, in order
to ensure that it is passed when appropriate.

Signed-off-by: Delan Azabani <dazabani@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Delan Azabani 2025-01-30 19:15:35 +08:00 committed by GitHub
parent 9eeb602f7a
commit 5e9de2cb61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 809 additions and 753 deletions

2
Cargo.lock generated
View file

@ -503,6 +503,7 @@ dependencies = [
name = "bluetooth"
version = "0.0.1"
dependencies = [
"base",
"bitflags 2.8.0",
"bluetooth_traits",
"blurdroid",
@ -521,6 +522,7 @@ dependencies = [
name = "bluetooth_traits"
version = "0.0.1"
dependencies = [
"base",
"embedder_traits",
"ipc-channel",
"regex",

View file

@ -12,6 +12,7 @@ name = "bluetooth"
path = "lib.rs"
[dependencies]
base = { workspace = true }
bitflags = { workspace = true }
bluetooth_traits = { workspace = true }
blurmock = { version = "0.1.2", optional = true }

View file

@ -19,6 +19,7 @@ use std::string::String;
use std::thread;
use std::time::Duration;
use base::id::WebViewId;
use bitflags::bitflags;
use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist};
use bluetooth_traits::scanfilter::{
@ -387,6 +388,7 @@ impl BluetoothManager {
fn select_device(
&mut self,
webview_id: WebViewId,
devices: Vec<BluetoothDevice>,
adapter: &BluetoothAdapter,
) -> Option<String> {
@ -408,11 +410,12 @@ impl BluetoothManager {
}
let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!");
let msg = (
None,
EmbedderMsg::GetSelectedBluetoothDevice(dialog_rows, ipc_sender),
);
self.embedder_proxy.send(msg);
self.embedder_proxy
.send(EmbedderMsg::GetSelectedBluetoothDevice(
webview_id,
dialog_rows,
ipc_sender,
));
match ipc_receiver.recv() {
Ok(result) => result,
@ -628,7 +631,7 @@ impl BluetoothManager {
}
// Step 9.
if let Some(address) = self.select_device(matched_devices, &adapter) {
if let Some(address) = self.select_device(options.webview_id(), matched_devices, &adapter) {
let device_id = match self.address_to_id.get(&address) {
Some(id) => id.clone(),
None => return Err(BluetoothError::NotFound),

View file

@ -425,9 +425,21 @@ impl IOCompositor {
Some(cursor) if cursor != self.cursor => cursor,
_ => return,
};
let Some(webview_id) = self
.pipeline_details(result.pipeline_id)
.pipeline
.as_ref()
.map(|composition_pipeline| composition_pipeline.top_level_browsing_context_id)
else {
warn!(
"Updating cursor for not-yet-rendered pipeline: {}",
result.pipeline_id
);
return;
};
self.cursor = cursor;
let msg = ConstellationMsg::SetCursor(cursor);
let msg = ConstellationMsg::SetCursor(webview_id, cursor);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e);
}

View file

@ -7,7 +7,7 @@
use std::fmt::{Debug, Error, Formatter};
use std::time::Duration;
use base::id::{PipelineId, TopLevelBrowsingContextId};
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
use embedder_traits::{
ClipboardEventType, EventLoopWaker, GamepadEvent, MediaSessionActionType, MouseButton, Theme,
TouchEventType, TouchId, TraversalDirection, WheelDelta,
@ -83,7 +83,7 @@ pub enum EmbedderEvent {
/// Sent when the user exits from fullscreen mode
ExitFullScreen(TopLevelBrowsingContextId),
/// Sent when a key input state changes
Keyboard(KeyboardEvent),
Keyboard(WebViewId, KeyboardEvent),
/// Sent for IME composition updates
IMEComposition(CompositionEvent),
/// Sent when Ctr+R/Apple+R is called to reload the current page.

View file

@ -1232,9 +1232,9 @@ where
)]
fn handle_request_from_background_hang_monitor(&self, message: HangMonitorAlert) {
match message {
HangMonitorAlert::Profile(bytes) => self
.embedder_proxy
.send((None, EmbedderMsg::ReportProfile(bytes))),
HangMonitorAlert::Profile(bytes) => {
self.embedder_proxy.send(EmbedderMsg::ReportProfile(bytes))
},
HangMonitorAlert::Hang(hang) => {
// TODO: In case of a permanent hang being reported, add a "kill script" workflow,
// via the embedder?
@ -1271,8 +1271,8 @@ where
FromCompositorMsg::GetFocusTopLevelBrowsingContext(resp_chan) => {
let _ = resp_chan.send(self.webviews.focused_webview().map(|(id, _)| id));
},
FromCompositorMsg::Keyboard(key_event) => {
self.handle_key_msg(key_event);
FromCompositorMsg::Keyboard(webview_id, key_event) => {
self.handle_key_msg(webview_id, key_event);
},
FromCompositorMsg::IMECompositionEvent(ime_event) => {
self.handle_ime_msg(ime_event);
@ -1391,11 +1391,8 @@ where
// A top level browsing context is created and opened in both constellation and
// compositor.
FromCompositorMsg::WebViewOpened(top_level_browsing_context_id) => {
let msg = (
Some(top_level_browsing_context_id),
EmbedderMsg::WebViewOpened(top_level_browsing_context_id),
);
self.embedder_proxy.send(msg);
self.embedder_proxy
.send(EmbedderMsg::WebViewOpened(top_level_browsing_context_id));
},
// Close a top level browsing context.
FromCompositorMsg::CloseWebView(top_level_browsing_context_id) => {
@ -1414,8 +1411,7 @@ where
},
FromCompositorMsg::BlurWebView => {
self.webviews.unfocus();
self.embedder_proxy
.send((None, EmbedderMsg::WebViewBlurred));
self.embedder_proxy.send(EmbedderMsg::WebViewBlurred);
},
// Handle a forward or back request
FromCompositorMsg::TraverseHistory(top_level_browsing_context_id, direction) => {
@ -1442,7 +1438,9 @@ where
FromCompositorMsg::ForwardEvent(destination_pipeline_id, event) => {
self.forward_event(destination_pipeline_id, event);
},
FromCompositorMsg::SetCursor(cursor) => self.handle_set_cursor_msg(cursor),
FromCompositorMsg::SetCursor(webview_id, cursor) => {
self.handle_set_cursor_msg(webview_id, cursor)
},
FromCompositorMsg::ToggleProfiler(rate, max_duration) => {
for background_monitor_control_sender in &self.background_monitor_control_senders {
if let Err(e) = background_monitor_control_sender.send(
@ -1469,7 +1467,7 @@ where
)
.entered();
self.embedder_proxy
.send((None, EmbedderMsg::ReadyToPresent(webview_ids)));
.send(EmbedderMsg::ReadyToPresent(webview_ids));
},
FromCompositorMsg::Gamepad(gamepad_event) => {
self.handle_gamepad_msg(gamepad_event);
@ -1557,8 +1555,7 @@ where
self.handle_schedule_broadcast(source_pipeline_id, router_id, message);
},
FromScriptMsg::ForwardToEmbedder(embedder_msg) => {
self.embedder_proxy
.send((Some(source_top_ctx_id), embedder_msg));
self.embedder_proxy.send(embedder_msg);
},
FromScriptMsg::PipelineExited => {
self.handle_pipeline_exited(source_pipeline_id);
@ -1756,10 +1753,8 @@ where
};
}
self.active_media_session = Some(pipeline_id);
self.embedder_proxy.send((
Some(source_top_ctx_id),
EmbedderMsg::MediaSessionEvent(event),
));
self.embedder_proxy
.send(EmbedderMsg::MediaSessionEvent(source_top_ctx_id, event));
},
#[cfg(feature = "webgpu")]
FromScriptMsg::RequestAdapter(response_sender, options, ids) => self
@ -2793,9 +2788,10 @@ where
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
self.embedder_proxy.send((
Some(top_level_browsing_context_id),
EmbedderMsg::Panic(reason.clone(), backtrace.clone()),
self.embedder_proxy.send(EmbedderMsg::Panic(
top_level_browsing_context_id,
reason.clone(),
backtrace.clone(),
));
let browsing_context = match self.browsing_contexts.get(&browsing_context_id) {
@ -2874,10 +2870,8 @@ where
return warn!("{top_level_browsing_context_id}: FocusWebView on unknown top-level browsing context");
}
self.webviews.focus(top_level_browsing_context_id);
self.embedder_proxy.send((
Some(top_level_browsing_context_id),
EmbedderMsg::WebViewFocused(top_level_browsing_context_id),
));
self.embedder_proxy
.send(EmbedderMsg::WebViewFocused(top_level_browsing_context_id));
}
#[cfg_attr(
@ -2950,9 +2944,9 @@ where
Some(pipeline) => pipeline,
};
self.embedder_proxy.send((
Some(pipeline.top_level_browsing_context_id),
EmbedderMsg::EventDelivered((&event).into()),
self.embedder_proxy.send(EmbedderMsg::EventDelivered(
pipeline.top_level_browsing_context_id,
(&event).into(),
));
if let Err(e) = pipeline.event_loop.send(ConstellationControlMsg::SendEvent(
@ -3052,16 +3046,13 @@ where
self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal);
if self.webviews.focused_webview().map(|(id, _)| id) == Some(top_level_browsing_context_id)
{
self.embedder_proxy
.send((None, EmbedderMsg::WebViewBlurred));
self.embedder_proxy.send(EmbedderMsg::WebViewBlurred);
}
self.webviews.remove(top_level_browsing_context_id);
self.compositor_proxy
.send(CompositorMsg::RemoveWebView(top_level_browsing_context_id));
self.embedder_proxy.send((
Some(top_level_browsing_context_id),
EmbedderMsg::WebViewClosed(top_level_browsing_context_id),
));
self.embedder_proxy
.send(EmbedderMsg::WebViewClosed(top_level_browsing_context_id));
let Some(browsing_context) = browsing_context else {
return;
@ -3431,9 +3422,9 @@ where
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)]
fn handle_set_cursor_msg(&mut self, cursor: Cursor) {
fn handle_set_cursor_msg(&mut self, webview_id: WebViewId, cursor: Cursor) {
self.embedder_proxy
.send((None, EmbedderMsg::SetCursor(cursor)))
.send(EmbedderMsg::SetCursor(webview_id, cursor));
}
#[cfg_attr(
@ -3499,11 +3490,12 @@ where
},
};
// Allow the embedder to handle the url itself
let msg = (
Some(top_level_browsing_context_id),
EmbedderMsg::AllowNavigationRequest(source_id, load_data.url.clone()),
);
self.embedder_proxy.send(msg);
self.embedder_proxy
.send(EmbedderMsg::AllowNavigationRequest(
top_level_browsing_context_id,
source_id,
load_data.url.clone(),
));
}
#[cfg_attr(
@ -4215,41 +4207,33 @@ where
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true))
)]
fn handle_key_msg(&mut self, event: KeyboardEvent) {
fn handle_key_msg(&mut self, webview_id: WebViewId, event: KeyboardEvent) {
// Send to the focused browsing contexts' current pipeline. If it
// doesn't exist, fall back to sending to the compositor.
let focused_browsing_context_id = self
.webviews
.focused_webview()
.map(|(_, webview)| webview.focused_browsing_context_id);
match focused_browsing_context_id {
Some(browsing_context_id) => {
let event = CompositorEvent::KeyboardEvent(event);
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(ctx) => ctx.pipeline_id,
None => {
return warn!(
"{}: Got key event for nonexistent browsing context",
browsing_context_id,
);
},
};
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.event_loop.send(msg),
None => {
return debug!("{}: Got key event after closure", pipeline_id);
},
};
if let Err(e) = result {
self.handle_send_error(pipeline_id, e);
}
},
let Some(webview) = self.webviews.get(webview_id) else {
warn!("Handling keyboard event for unknown webview: {webview_id}");
return;
};
let browsing_context_id = webview.focused_browsing_context_id;
let event = CompositorEvent::KeyboardEvent(event);
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(ctx) => ctx.pipeline_id,
None => {
warn!("No focused browsing context! Falling back to sending key to compositor");
let event = (None, EmbedderMsg::Keyboard(event));
self.embedder_proxy.send(event);
return warn!(
"{}: Got key event for nonexistent browsing context",
browsing_context_id,
);
},
};
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.event_loop.send(msg),
None => {
return debug!("{}: Got key event after closure", pipeline_id);
},
};
if let Err(e) = result {
self.handle_send_error(pipeline_id, e);
}
}
@ -4410,10 +4394,8 @@ where
// Focus the top-level browsing context.
self.webviews.focus(top_level_browsing_context_id);
self.embedder_proxy.send((
Some(top_level_browsing_context_id),
EmbedderMsg::WebViewFocused(top_level_browsing_context_id),
));
self.embedder_proxy
.send(EmbedderMsg::WebViewFocused(top_level_browsing_context_id));
// Update the webviews focused browsing context.
match self.webviews.get_mut(top_level_browsing_context_id) {
@ -4557,13 +4539,13 @@ where
WebDriverCommandMsg::CloseWebView(top_level_browsing_context_id) => {
self.handle_close_top_level_browsing_context(top_level_browsing_context_id);
},
WebDriverCommandMsg::NewWebView(sender, load_sender) => {
WebDriverCommandMsg::NewWebView(webview_id, sender, load_sender) => {
let (chan, port) = match ipc::channel() {
Ok(result) => result,
Err(error) => return warn!("Failed to create channel: {error:?}"),
};
self.embedder_proxy
.send((None, EmbedderMsg::AllowOpeningWebView(chan)));
.send(EmbedderMsg::AllowOpeningWebView(webview_id, chan));
let webview_id = match port.recv() {
Ok(Some(webview_id)) => webview_id,
Ok(None) => return warn!("Embedder refused to allow opening webview"),
@ -4588,10 +4570,8 @@ where
response_sender,
) => {
self.webdriver.resize_channel = Some(response_sender);
self.embedder_proxy.send((
Some(top_level_browsing_context_id),
EmbedderMsg::ResizeTo(size),
));
self.embedder_proxy
.send(EmbedderMsg::ResizeTo(top_level_browsing_context_id, size));
},
WebDriverCommandMsg::LoadUrl(
top_level_browsing_context_id,
@ -4833,11 +4813,11 @@ where
.rev()
.scan(current_url, &resolve_url_future),
);
let msg = (
Some(top_level_browsing_context_id),
EmbedderMsg::HistoryChanged(entries, current_index),
);
self.embedder_proxy.send(msg);
self.embedder_proxy.send(EmbedderMsg::HistoryChanged(
top_level_browsing_context_id,
entries,
current_index,
));
}
#[cfg_attr(

View file

@ -217,16 +217,16 @@ mod from_script {
Self::WebResourceRequested(..) => target_variant!("WebResourceRequested"),
Self::AllowUnload(..) => target_variant!("AllowUnload"),
Self::Keyboard(..) => target_variant!("Keyboard"),
Self::ClearClipboardContents => target_variant!("ClearClipboardContents"),
Self::ClearClipboardContents(..) => target_variant!("ClearClipboardContents"),
Self::GetClipboardContents(..) => target_variant!("GetClipboardContents"),
Self::SetClipboardContents(..) => target_variant!("SetClipboardContents"),
Self::SetCursor(..) => target_variant!("SetCursor"),
Self::NewFavicon(..) => target_variant!("NewFavicon"),
Self::HeadParsed => target_variant!("HeadParsed"),
Self::HeadParsed(..) => target_variant!("HeadParsed"),
Self::HistoryChanged(..) => target_variant!("HistoryChanged"),
Self::SetFullscreenState(..) => target_variant!("SetFullscreenState"),
Self::LoadStart => target_variant!("LoadStart"),
Self::LoadComplete => target_variant!("LoadComplete"),
Self::LoadStart(..) => target_variant!("LoadStart"),
Self::LoadComplete(..) => target_variant!("LoadComplete"),
Self::Panic(..) => target_variant!("Panic"),
Self::GetSelectedBluetoothDevice(..) => {
target_variant!("GetSelectedBluetoothDevice")
@ -234,11 +234,12 @@ mod from_script {
Self::SelectFiles(..) => target_variant!("SelectFiles"),
Self::PromptPermission(..) => target_variant!("PromptPermission"),
Self::ShowIME(..) => target_variant!("ShowIME"),
Self::HideIME => target_variant!("HideIME"),
Self::HideIME(..) => target_variant!("HideIME"),
Self::Shutdown => target_variant!("Shutdown"),
Self::ReportProfile(..) => target_variant!("ReportProfile"),
Self::MediaSessionEvent(..) => target_variant!("MediaSessionEvent"),
Self::OnDevtoolsStarted(..) => target_variant!("OnDevtoolsStarted"),
Self::RequestDevtoolsConnection(..) => target_variant!("RequestDevtoolsConnection"),
Self::ReadyToPresent(..) => target_variant!("ReadyToPresent"),
Self::EventDelivered(..) => target_variant!("EventDelivered"),
Self::PlayGamepadHapticEffect(..) => target_variant!("PlayGamepadHapticEffect"),

View file

@ -26,7 +26,7 @@ use devtools_traits::{
DevtoolsControlMsg, DevtoolsPageInfo, LogLevel, NavigationState, NetworkEvent, PageError,
ScriptToDevtoolsControlMsg, WorkerId,
};
use embedder_traits::{EmbedderMsg, EmbedderProxy, PromptDefinition, PromptOrigin, PromptResult};
use embedder_traits::{EmbedderMsg, EmbedderProxy};
use ipc_channel::ipc::{self, IpcSender};
use log::{debug, trace, warn};
use serde::Serialize;
@ -154,7 +154,7 @@ fn run_server(
let token = format!("{:X}", servo_rand::ServoRng::default().next_u32());
let port = bound.as_ref().map(|(_, port)| *port).ok_or(());
embedder.send((None, EmbedderMsg::OnDevtoolsStarted(port, token.clone())));
embedder.send(EmbedderMsg::OnDevtoolsStarted(port, token.clone()));
let listener = match bound {
Some((l, _)) => l,
@ -762,10 +762,7 @@ fn allow_devtools_client(stream: &mut TcpStream, embedder: &EmbedderProxy, token
};
// No token found. Prompt user
let (embedder_sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
let message = "Accept incoming devtools connection?".to_owned();
let prompt = PromptDefinition::YesNo(message, embedder_sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Trusted);
embedder.send((None, msg));
receiver.recv().unwrap() == PromptResult::Primary
let (request_sender, request_receiver) = ipc::channel().expect("Failed to create IPC channel!");
embedder.send(EmbedderMsg::RequestDevtoolsConnection(request_sender));
request_receiver.recv().unwrap()
}

View file

@ -9,6 +9,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use app_units::Au;
use base::id::WebViewId;
use fnv::FnvHasher;
use fonts_traits::WebFontLoadFinishedCallback;
use log::{debug, trace};
@ -358,6 +359,7 @@ impl FontContext {
#[derive(Clone)]
pub(crate) struct WebFontDownloadState {
webview_id: WebViewId,
pub(crate) css_font_face_descriptors: Arc<CSSFontFaceDescriptors>,
remaining_sources: Vec<Source>,
finished_callback: WebFontLoadFinishedCallback,
@ -369,6 +371,7 @@ pub(crate) struct WebFontDownloadState {
pub trait FontContextWebFontMethods {
fn add_all_web_fonts_from_stylesheet(
&self,
webview_id: WebViewId,
stylesheet: &DocumentStyleSheet,
guard: &SharedRwLockReadGuard,
device: &Device,
@ -382,6 +385,7 @@ pub trait FontContextWebFontMethods {
impl FontContextWebFontMethods for Arc<FontContext> {
fn add_all_web_fonts_from_stylesheet(
&self,
webview_id: WebViewId,
stylesheet: &DocumentStyleSheet,
guard: &SharedRwLockReadGuard,
device: &Device,
@ -441,6 +445,7 @@ impl FontContextWebFontMethods for Arc<FontContext> {
.handle_web_font_load_started_for_stylesheet(stylesheet);
self.process_next_web_font_source(WebFontDownloadState {
webview_id,
css_font_face_descriptors: Arc::new(rule.into()),
remaining_sources: sources,
finished_callback: finished_callback.clone(),
@ -623,8 +628,12 @@ impl RemoteWebFontDownloader {
};
// FIXME: This shouldn't use NoReferrer, but the current documents url
let request = RequestBuilder::new(url.clone().into(), Referrer::NoReferrer)
.destination(Destination::Font);
let request = RequestBuilder::new(
Some(state.webview_id),
url.clone().into(),
Referrer::NoReferrer,
)
.destination(Destination::Font);
debug!("Loading @font-face {} from {}", web_font_family_name, url);
let downloader = Self {

View file

@ -15,7 +15,7 @@ use std::sync::{Arc, LazyLock, Mutex};
use app_units::Au;
use base::cross_process_instant::CrossProcessInstant;
use base::id::PipelineId;
use base::id::{PipelineId, WebViewId};
use base::Epoch;
use embedder_traits::resources::{self, Resource};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
@ -119,6 +119,9 @@ pub struct LayoutThread {
/// The ID of the pipeline that we belong to.
id: PipelineId,
/// The webview that contains the pipeline we belong to.
webview_id: WebViewId,
/// The URL of the pipeline that we belong to.
url: ServoUrl,
@ -195,18 +198,7 @@ pub struct LayoutFactoryImpl();
impl LayoutFactory for LayoutFactoryImpl {
fn create(&self, config: LayoutConfig) -> Box<dyn Layout> {
Box::new(LayoutThread::new(
config.id,
config.url,
config.is_iframe,
config.script_chan,
config.image_cache,
config.font_context,
config.time_profiler_chan,
config.compositor_api,
config.paint_time_metrics,
config.window_size,
))
Box::new(LayoutThread::new(config))
}
}
@ -503,21 +495,11 @@ impl LayoutThread {
self.root_flow.borrow().clone()
}
#[allow(clippy::too_many_arguments)]
fn new(
id: PipelineId,
url: ServoUrl,
is_iframe: bool,
script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>,
font_context: Arc<FontContext>,
time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {
fn new(config: LayoutConfig) -> LayoutThread {
// Let webrender know about this pipeline by sending an empty display list.
compositor_api.send_initial_transaction(id.into());
config
.compositor_api
.send_initial_transaction(config.id.into());
let mut font = Font::initial_values();
let default_font_size = pref!(fonts_default_size);
@ -530,8 +512,8 @@ impl LayoutThread {
let device = Device::new(
MediaType::screen(),
QuirksMode::NoQuirks,
window_size.initial_viewport,
Scale::new(window_size.device_pixel_ratio.get()),
config.window_size.initial_viewport,
Scale::new(config.window_size.device_pixel_ratio.get()),
Box::new(LayoutFontMetricsProvider),
ComputedValues::initial_values_with_font_override(font),
// TODO: obtain preferred color scheme from embedder
@ -539,14 +521,15 @@ impl LayoutThread {
);
LayoutThread {
id,
url,
is_iframe,
script_chan,
time_profiler_chan,
id: config.id,
webview_id: config.webview_id,
url: config.url,
is_iframe: config.is_iframe,
script_chan: config.script_chan,
time_profiler_chan: config.time_profiler_chan,
registered_painters: RegisteredPaintersImpl(Default::default()),
image_cache,
font_context,
image_cache: config.image_cache,
font_context: config.font_context,
first_reflow: Cell::new(true),
parallel_flag: true,
generation: Cell::new(0),
@ -554,16 +537,16 @@ impl LayoutThread {
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
epoch: Cell::new(Epoch(1)),
viewport_size: Size2D::new(
Au::from_f32_px(window_size.initial_viewport.width),
Au::from_f32_px(window_size.initial_viewport.height),
Au::from_f32_px(config.window_size.initial_viewport.width),
Au::from_f32_px(config.window_size.initial_viewport.height),
),
compositor_api,
compositor_api: config.compositor_api,
stylist: Stylist::new(device, QuirksMode::NoQuirks),
display_list: Default::default(),
indexable_text: Default::default(),
scroll_offsets: Default::default(),
webrender_image_cache: Arc::new(RwLock::new(FnvHashMap::default())),
paint_time_metrics,
paint_time_metrics: config.paint_time_metrics,
last_iframe_sizes: Default::default(),
debug: opts::get().debug.clone(),
nonincremental_layout: opts::get().nonincremental_layout,
@ -640,6 +623,7 @@ impl LayoutThread {
};
self.font_context.add_all_web_fonts_from_stylesheet(
self.webview_id,
stylesheet,
guard,
self.stylist.device(),

View file

@ -16,7 +16,7 @@ use std::sync::{Arc, LazyLock};
use app_units::Au;
use base::cross_process_instant::CrossProcessInstant;
use base::id::PipelineId;
use base::id::{PipelineId, WebViewId};
use base::Epoch;
use embedder_traits::resources::{self, Resource};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
@ -105,6 +105,9 @@ pub struct LayoutThread {
/// The ID of the pipeline that we belong to.
id: PipelineId,
/// The webview that contains the pipeline we belong to.
webview_id: WebViewId,
/// The URL of the pipeline that we belong to.
url: ServoUrl,
@ -169,18 +172,7 @@ pub struct LayoutFactoryImpl();
impl LayoutFactory for LayoutFactoryImpl {
fn create(&self, config: LayoutConfig) -> Box<dyn Layout> {
Box::new(LayoutThread::new(
config.id,
config.url,
config.is_iframe,
config.script_chan,
config.image_cache,
config.font_context,
config.time_profiler_chan,
config.compositor_api,
config.paint_time_metrics,
config.window_size,
))
Box::new(LayoutThread::new(config))
}
}
@ -476,23 +468,12 @@ impl Layout for LayoutThread {
}
}
#[allow(clippy::too_many_arguments)]
impl LayoutThread {
#[allow(clippy::too_many_arguments)]
fn new(
id: PipelineId,
url: ServoUrl,
is_iframe: bool,
script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>,
font_context: Arc<FontContext>,
time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {
fn new(config: LayoutConfig) -> LayoutThread {
// Let webrender know about this pipeline by sending an empty display list.
compositor_api.send_initial_transaction(id.into());
config
.compositor_api
.send_initial_transaction(config.id.into());
let mut font = Font::initial_values();
let default_font_size = pref!(fonts_default_size);
@ -507,23 +488,24 @@ impl LayoutThread {
let device = Device::new(
MediaType::screen(),
QuirksMode::NoQuirks,
window_size.initial_viewport,
Scale::new(window_size.device_pixel_ratio.get()),
Box::new(LayoutFontMetricsProvider(font_context.clone())),
config.window_size.initial_viewport,
Scale::new(config.window_size.device_pixel_ratio.get()),
Box::new(LayoutFontMetricsProvider(config.font_context.clone())),
ComputedValues::initial_values_with_font_override(font),
// TODO: obtain preferred color scheme from embedder
PrefersColorScheme::Light,
);
LayoutThread {
id,
url,
is_iframe,
script_chan: script_chan.clone(),
time_profiler_chan,
id: config.id,
webview_id: config.webview_id,
url: config.url,
is_iframe: config.is_iframe,
script_chan: config.script_chan.clone(),
time_profiler_chan: config.time_profiler_chan,
registered_painters: RegisteredPaintersImpl(Default::default()),
image_cache,
font_context,
image_cache: config.image_cache,
font_context: config.font_context,
first_reflow: Cell::new(true),
generation: Cell::new(0),
box_tree: Default::default(),
@ -531,14 +513,14 @@ impl LayoutThread {
// Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR
epoch: Cell::new(Epoch(1)),
viewport_size: Size2D::new(
Au::from_f32_px(window_size.initial_viewport.width),
Au::from_f32_px(window_size.initial_viewport.height),
Au::from_f32_px(config.window_size.initial_viewport.width),
Au::from_f32_px(config.window_size.initial_viewport.height),
),
compositor_api,
compositor_api: config.compositor_api,
scroll_offsets: Default::default(),
stylist: Stylist::new(device, QuirksMode::NoQuirks),
webrender_image_cache: Default::default(),
paint_time_metrics,
paint_time_metrics: config.paint_time_metrics,
debug: opts::get().debug.clone(),
}
}
@ -619,6 +601,7 @@ impl LayoutThread {
};
self.font_context.add_all_web_fonts_from_stylesheet(
self.webview_id,
stylesheet,
guard,
self.stylist.device(),

View file

@ -195,18 +195,6 @@ pub fn should_request_be_blocked_by_csp(
.unwrap_or(csp::CheckResult::Allowed)
}
pub fn maybe_intercept_request(
request: &mut Request,
context: &FetchContext,
response: &mut Option<Response>,
) {
context
.request_intercepter
.lock()
.unwrap()
.intercept_request(request, response, context);
}
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
pub async fn main_fetch(
fetch_params: &mut FetchParams,
@ -314,7 +302,11 @@ pub async fn main_fetch(
let current_scheme = current_url.scheme();
// Intercept the request and maybe override the response.
maybe_intercept_request(request, context, &mut response);
context
.request_intercepter
.lock()
.unwrap()
.intercept_request(request, &mut response, context);
let mut response = match response {
Some(res) => res,

View file

@ -10,6 +10,7 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::{self, AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock, Weak};
use base::id::WebViewId;
use embedder_traits::{EmbedderMsg, EmbedderProxy, FilterPattern};
use headers::{ContentLength, ContentRange, ContentType, HeaderMap, HeaderMapExt, Range};
use http::header::{self, HeaderValue};
@ -153,14 +154,14 @@ impl FileManager {
/// Message handler
pub fn handle(&self, msg: FileManagerThreadMsg) {
match msg {
FileManagerThreadMsg::SelectFile(filter, sender, origin, opt_test_path) => {
FileManagerThreadMsg::SelectFile(webview_id, filter, sender, origin, opt_test_path) => {
let store = self.store.clone();
let embedder = self.embedder_proxy.clone();
self.thread_pool
.upgrade()
.map(|pool| {
pool.spawn(move || {
store.select_file(filter, sender, origin, opt_test_path, embedder);
store.select_file(webview_id, filter, sender, origin, opt_test_path, embedder);
});
})
.unwrap_or_else(|| {
@ -169,14 +170,20 @@ impl FileManager {
);
});
},
FileManagerThreadMsg::SelectFiles(filter, sender, origin, opt_test_paths) => {
FileManagerThreadMsg::SelectFiles(
webview_id,
filter,
sender,
origin,
opt_test_paths,
) => {
let store = self.store.clone();
let embedder = self.embedder_proxy.clone();
self.thread_pool
.upgrade()
.map(|pool| {
pool.spawn(move || {
store.select_files(filter, sender, origin, opt_test_paths, embedder);
store.select_files(webview_id, filter, sender, origin, opt_test_paths, embedder);
});
})
.unwrap_or_else(|| {
@ -571,17 +578,18 @@ impl FileManagerStore {
fn query_files_from_embedder(
&self,
webview_id: WebViewId,
patterns: Vec<FilterPattern>,
multiple_files: bool,
embedder_proxy: EmbedderProxy,
) -> Option<Vec<String>> {
let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!");
let msg = (
None,
EmbedderMsg::SelectFiles(patterns, multiple_files, ipc_sender),
);
embedder_proxy.send(msg);
embedder_proxy.send(EmbedderMsg::SelectFiles(
webview_id,
patterns,
multiple_files,
ipc_sender,
));
match ipc_receiver.recv() {
Ok(result) => result,
Err(e) => {
@ -593,6 +601,7 @@ impl FileManagerStore {
fn select_file(
&self,
webview_id: WebViewId,
patterns: Vec<FilterPattern>,
sender: IpcSender<FileManagerResult<SelectedFile>>,
origin: FileOrigin,
@ -605,7 +614,7 @@ impl FileManagerStore {
let opt_s = if pref!(dom_testing_html_input_element_select_files_enabled) {
opt_test_path
} else {
self.query_files_from_embedder(patterns, false, embedder_proxy)
self.query_files_from_embedder(webview_id, patterns, false, embedder_proxy)
.and_then(|mut x| x.pop())
};
@ -623,6 +632,7 @@ impl FileManagerStore {
fn select_files(
&self,
webview_id: WebViewId,
patterns: Vec<FilterPattern>,
sender: IpcSender<FileManagerResult<Vec<SelectedFile>>>,
origin: FileOrigin,
@ -635,7 +645,7 @@ impl FileManagerStore {
let opt_v = if pref!(dom_testing_html_input_element_select_files_enabled) {
opt_test_paths
} else {
self.query_files_from_embedder(patterns, true, embedder_proxy)
self.query_files_from_embedder(webview_id, patterns, true, embedder_proxy)
};
match opt_v {

View file

@ -9,7 +9,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use async_recursion::async_recursion;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{HistoryStateId, PipelineId, TopLevelBrowsingContextId};
use base::id::{HistoryStateId, PipelineId, WebViewId};
use crossbeam_channel::Sender;
use devtools_traits::{
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
@ -1583,10 +1583,12 @@ async fn http_network_or_cache_fetch(
// Step 14.3 If requests use-URL-credentials flag is unset or isAuthenticationFetch is true, then:
if !http_request.use_url_credentials || authentication_fetch_flag {
let Some(credentials) = prompt_user_for_credentials(
&context.state.embedder_proxy,
http_request.target_browsing_context_id,
) else {
let Some(webview_id) = http_request.target_webview_id else {
return response;
};
let Some(credentials) =
prompt_user_for_credentials(&context.state.embedder_proxy, webview_id)
else {
return response;
};
let Some(username) = credentials.username else {
@ -1639,10 +1641,12 @@ async fn http_network_or_cache_fetch(
// Step 15.4 Prompt the end user as appropriate in requests window
// window and store the result as a proxy-authentication entry.
let Some(credentials) = prompt_user_for_credentials(
&context.state.embedder_proxy,
http_request.target_browsing_context_id,
) else {
let Some(webview_id) = http_request.target_webview_id else {
return response;
};
let Some(credentials) =
prompt_user_for_credentials(&context.state.embedder_proxy, webview_id)
else {
return response;
};
let Some(user_name) = credentials.username else {
@ -1779,18 +1783,16 @@ impl Drop for ResponseEndTimer {
fn prompt_user_for_credentials(
embedder_proxy: &Mutex<EmbedderProxy>,
top_level_browsing_context_id: Option<TopLevelBrowsingContextId>,
webview_id: WebViewId,
) -> Option<PromptCredentialsInput> {
let proxy = embedder_proxy.lock().unwrap();
let (ipc_sender, ipc_receiver) = ipc::channel().unwrap();
proxy.send((
top_level_browsing_context_id,
EmbedderMsg::Prompt(
PromptDefinition::Credentials(ipc_sender),
PromptOrigin::Trusted,
),
proxy.send(EmbedderMsg::Prompt(
webview_id,
PromptDefinition::Credentials(ipc_sender),
PromptOrigin::Trusted,
));
let Ok(credentials) = ipc_receiver.recv() else {
@ -2100,21 +2102,25 @@ async fn cors_preflight_fetch(
context: &FetchContext,
) -> Response {
// Step 1
let mut preflight = RequestBuilder::new(request.current_url(), request.referrer.clone())
.method(Method::OPTIONS)
.origin(match &request.origin {
Origin::Client => {
unreachable!("We shouldn't get Client origin in cors_preflight_fetch.")
},
Origin::Origin(origin) => origin.clone(),
})
.pipeline_id(request.pipeline_id)
.initiator(request.initiator)
.destination(request.destination)
.referrer_policy(request.referrer_policy)
.mode(RequestMode::CorsMode)
.response_tainting(ResponseTainting::CorsTainting)
.build();
let mut preflight = RequestBuilder::new(
request.target_webview_id,
request.current_url(),
request.referrer.clone(),
)
.method(Method::OPTIONS)
.origin(match &request.origin {
Origin::Client => {
unreachable!("We shouldn't get Client origin in cors_preflight_fetch.")
},
Origin::Origin(origin) => origin.clone(),
})
.pipeline_id(request.pipeline_id)
.initiator(request.initiator)
.destination(request.destination)
.referrer_policy(request.referrer_policy)
.mode(RequestMode::CorsMode)
.response_tainting(ResponseTainting::CorsTainting)
.build();
// Step 2
preflight

View file

@ -40,9 +40,10 @@ impl RequestIntercepter {
request.redirect_count > 0,
);
self.embedder_proxy.send((
request.target_browsing_context_id,
EmbedderMsg::WebResourceRequested(req, tx),
self.embedder_proxy.send(EmbedderMsg::WebResourceRequested(
request.target_webview_id,
req,
tx,
));
let mut response_received = false;

View file

@ -24,7 +24,7 @@ fn assert_parse(
use net_traits::request::RequestBuilder;
let url = ServoUrl::parse(url).unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.pipeline_id(None)
.build();

View file

@ -65,7 +65,7 @@ fn test_fetch_response_is_not_network_error() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -79,7 +79,7 @@ fn test_fetch_response_is_not_network_error() {
#[test]
fn test_fetch_on_bad_port_is_network_error() {
let url = ServoUrl::parse("http://www.example.org:6667").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -101,7 +101,7 @@ fn test_fetch_response_body_matches_const_message() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -121,7 +121,7 @@ fn test_fetch_response_body_matches_const_message() {
#[test]
fn test_fetch_aboutblank() {
let url = ServoUrl::parse("about:blank").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
@ -186,7 +186,7 @@ fn test_fetch_blob() {
);
let url = ServoUrl::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(origin.origin())
.build();
@ -228,7 +228,7 @@ fn test_file() {
.unwrap();
let url = ServoUrl::from_file_path(path.clone()).unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
@ -271,7 +271,7 @@ fn test_file() {
#[test]
fn test_fetch_ftp() {
let url = ServoUrl::parse("ftp://not-supported").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -281,7 +281,7 @@ fn test_fetch_ftp() {
#[test]
fn test_fetch_bogus_scheme() {
let url = ServoUrl::parse("bogus://whatever").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -330,7 +330,7 @@ fn test_cors_preflight_fetch() {
let (server, url) = make_server(handler);
let target_url = url.clone().join("a.html").unwrap();
let mut request = RequestBuilder::new(url, Referrer::ReferrerUrl(target_url)).build();
let mut request = RequestBuilder::new(None, url, Referrer::ReferrerUrl(target_url)).build();
request.referrer_policy = ReferrerPolicy::Origin;
request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode;
@ -383,7 +383,7 @@ fn test_cors_preflight_cache_fetch() {
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url, Referrer::NoReferrer).build();
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build();
request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode;
let wrapped_request0 = request.clone();
@ -448,7 +448,7 @@ fn test_cors_preflight_fetch_network_error() {
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url, Referrer::NoReferrer).build();
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build();
request.method = Method::from_bytes(b"CHICKEN").unwrap();
request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode;
@ -477,7 +477,7 @@ fn test_fetch_response_is_basic_filtered() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -542,7 +542,7 @@ fn test_fetch_response_is_cors_filtered() {
let (server, url) = make_server(handler);
// an origin mis-match will stop it from defaulting to a basic filtered response
let mut request = RequestBuilder::new(url, Referrer::NoReferrer).build();
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build();
request.mode = RequestMode::CorsMode;
let fetch_response = fetch(request, None);
let _ = server.close();
@ -576,7 +576,7 @@ fn test_fetch_response_is_opaque_filtered() {
let (server, url) = make_server(handler);
// an origin mis-match will fall through to an Opaque filtered response
let request = RequestBuilder::new(url, Referrer::NoReferrer).build();
let request = RequestBuilder::new(None, url, Referrer::NoReferrer).build();
let fetch_response = fetch(request, None);
let _ = server.close();
@ -624,7 +624,7 @@ fn test_fetch_response_is_opaque_redirect_filtered() {
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
request.redirect_mode = RedirectMode::Manual;
@ -660,7 +660,7 @@ fn test_fetch_with_local_urls_only() {
let (server, server_url) = make_server(handler);
let do_fetch = |url: ServoUrl| {
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
@ -728,7 +728,7 @@ fn test_fetch_with_hsts() {
HstsEntry::new("localhost".to_owned(), IncludeSubdomains::NotIncluded, None).unwrap(),
);
}
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
// Set the flag.
@ -782,7 +782,7 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
context.state.override_manager.add_override(certificate);
}
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -838,7 +838,7 @@ fn test_fetch_self_signed() {
protocols: Arc::new(ProtocolRegistry::default()),
};
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -859,7 +859,7 @@ fn test_fetch_self_signed() {
context.state.override_manager.add_override(certificate);
}
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -884,7 +884,7 @@ fn test_fetch_with_sri_network_error() {
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
// To calulate hash use :
@ -910,7 +910,7 @@ fn test_fetch_with_sri_sucess() {
};
let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
// To calulate hash use :
@ -952,7 +952,7 @@ fn test_fetch_blocked_nosniff() {
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.destination(destination)
.build();
@ -999,7 +999,7 @@ fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -1089,7 +1089,7 @@ fn test_fetch_redirect_updates_method_runner(
let (server, url) = crate::make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.method(method)
.build();
@ -1174,7 +1174,7 @@ fn test_fetch_async_returns_complete_response() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let fetch_response = fetch(request, None);
@ -1194,7 +1194,7 @@ fn test_opaque_filtered_fetch_async_returns_complete_response() {
let (server, url) = make_server(handler);
// an origin mis-match will fall through to an Opaque filtered response
let request = RequestBuilder::new(url, Referrer::NoReferrer).build();
let request = RequestBuilder::new(None, url, Referrer::NoReferrer).build();
let fetch_response = fetch(request, None);
let _ = server.close();
@ -1228,7 +1228,7 @@ fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.redirect_mode(RedirectMode::Manual)
.build();
@ -1253,7 +1253,7 @@ fn test_fetch_with_devtools() {
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.redirect_mode(RedirectMode::Manual)
.pipeline_id(Some(TEST_PIPELINE_ID))
@ -1341,12 +1341,13 @@ fn test_fetch_request_intercepted() {
static HEADERVALUE: &str = "custom-value";
static STATUS_MESSAGE: &[u8] = b"custom status message";
let (embedder_proxy, mut embedder_receiver) = create_embedder_proxy_and_receiver();
let (embedder_proxy, embedder_receiver) = create_embedder_proxy_and_receiver();
std::thread::spawn(move || {
let (_browser_context_id, embedder_msg) = embedder_receiver.recv_embedder_msg();
let embedder_msg = embedder_receiver.recv().unwrap();
match embedder_msg {
embedder_traits::EmbedderMsg::WebResourceRequested(
_,
web_resource_request,
response_sender,
) => {
@ -1396,7 +1397,7 @@ fn test_fetch_request_intercepted() {
};
let url = ServoUrl::parse("http://www.example.org").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.origin(url.origin())
.build();
let response = fetch_with_context(request, &mut context);

View file

@ -7,6 +7,7 @@ use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use base::id::TEST_WEBVIEW_ID;
use embedder_traits::FilterPattern;
use ipc_channel::ipc;
use net::filemanager_thread::FileManager;
@ -44,6 +45,7 @@ fn test_filemanager() {
// Try to select a dummy file "components/net/tests/test.jpeg"
let (tx, rx) = ipc::channel().unwrap();
filemanager.handle(FileManagerThreadMsg::SelectFile(
TEST_WEBVIEW_ID,
patterns.clone(),
tx,
origin.clone(),

View file

@ -20,7 +20,7 @@ fn test_refreshing_resource_sets_done_chan_the_appropriate_value() {
ResponseBody::Done(vec![]),
];
let url = ServoUrl::parse("https://servo.org").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.pipeline_id(Some(TEST_PIPELINE_ID))
.origin(url.origin())
.build();

View file

@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
use base::id::TEST_PIPELINE_ID;
use base::id::{TEST_PIPELINE_ID, TEST_WEBVIEW_ID};
use cookie::Cookie as CookiePair;
use crossbeam_channel::{unbounded, Receiver};
use devtools_traits::{
@ -175,7 +175,7 @@ fn test_check_default_headers_loaded_in_every_request() {
*expected_headers.lock().unwrap() = Some(headers.clone());
// Testing for method.GET
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(url.clone().origin())
@ -201,7 +201,7 @@ fn test_check_default_headers_loaded_in_every_request() {
HeaderValue::from_str(&url_str[..url_str.len() - 1]).unwrap(),
);
*expected_headers.lock().unwrap() = Some(post_headers);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::POST)
.destination(Destination::Document)
.origin(url.clone().origin())
@ -231,7 +231,7 @@ fn test_load_when_request_is_not_get_or_head_and_there_is_no_body_content_length
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::POST)
.body(None)
.destination(Destination::Document)
@ -264,7 +264,7 @@ fn test_request_and_response_data_with_network_messages() {
let mut request_headers = HeaderMap::new();
request_headers.typed_insert(Host::from("bar.foo".parse::<Authority>().unwrap()));
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.headers(request_headers)
.body(None)
@ -377,7 +377,7 @@ fn test_request_and_response_message_from_devtool_without_pipeline_id() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -417,7 +417,7 @@ fn test_redirected_request_to_devtools() {
};
let (pre_server, pre_url) = make_server(pre_handler);
let request = RequestBuilder::new(pre_url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer)
.method(Method::POST)
.destination(Destination::Document)
.pipeline_id(Some(TEST_PIPELINE_ID))
@ -470,7 +470,7 @@ fn test_load_when_redirecting_from_a_post_should_rewrite_next_request_as_get() {
};
let (pre_server, pre_url) = make_server(pre_handler);
let request = RequestBuilder::new(pre_url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer)
.method(Method::POST)
.destination(Destination::Document)
.origin(mock_origin())
@ -502,7 +502,7 @@ fn test_load_should_decode_the_response_as_deflate_when_response_headers_have_co
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -537,7 +537,7 @@ fn test_load_should_decode_the_response_as_gzip_when_response_headers_have_conte
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -584,7 +584,7 @@ fn test_load_doesnt_send_request_body_on_any_redirect() {
let content = b"Body on POST!";
let request_body = create_request_body_with_content(content.to_vec());
let request = RequestBuilder::new(pre_url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer)
.body(Some(request_body))
.method(Method::POST)
.destination(Destination::Document)
@ -614,7 +614,7 @@ fn test_load_doesnt_add_host_to_hsts_list_when_url_is_http_even_if_hsts_headers_
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -661,7 +661,7 @@ fn test_load_sets_cookies_in_the_resource_manager_when_it_get_set_cookie_header_
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -714,7 +714,7 @@ fn test_load_sets_requests_cookies_header_for_url_by_getting_cookies_from_the_re
cookie_jar.push(cookie, &url, CookieSource::HTTP);
}
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -761,7 +761,7 @@ fn test_load_sends_cookie_if_nonhttp() {
cookie_jar.push(cookie, &url, CookieSource::HTTP);
}
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -800,7 +800,7 @@ fn test_cookie_set_with_httponly_should_not_be_available_using_getcookiesforurl(
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -849,7 +849,7 @@ fn test_when_cookie_received_marked_secure_is_ignored_for_http() {
assert_cookie_for_domain(&context.state.cookie_jar, url.as_str(), None);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -884,7 +884,7 @@ fn test_load_sets_content_length_to_length_of_request_body() {
let request_body = create_request_body_with_content(content.to_vec());
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::POST)
.body(Some(request_body))
.destination(Destination::Document)
@ -924,7 +924,7 @@ fn test_load_uses_explicit_accept_from_headers_in_load_data() {
let mut accept_headers = HeaderMap::new();
accept_headers.insert(header::ACCEPT, HeaderValue::from_static("text/html"));
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.headers(accept_headers)
.destination(Destination::Document)
@ -962,7 +962,7 @@ fn test_load_sets_default_accept_to_html_xhtml_xml_and_then_anything_else() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1001,7 +1001,7 @@ fn test_load_uses_explicit_accept_encoding_from_load_data_headers() {
let mut accept_encoding_headers = HeaderMap::new();
accept_encoding_headers.insert(header::ACCEPT_ENCODING, HeaderValue::from_static("chunked"));
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.headers(accept_encoding_headers)
.destination(Destination::Document)
@ -1039,7 +1039,7 @@ fn test_load_sets_default_accept_encoding_to_gzip_and_deflate() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1095,7 +1095,7 @@ fn test_load_errors_when_there_a_redirect_loop() {
*url_b_for_a.lock().unwrap() = Some(url_b.clone());
let request = RequestBuilder::new(url_a.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url_a.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1155,7 +1155,7 @@ fn test_load_succeeds_with_a_redirect_loop() {
*url_b_for_a.lock().unwrap() = Some(url_b.clone());
let request = RequestBuilder::new(url_a.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url_a.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1198,7 +1198,7 @@ fn test_load_follows_a_redirect() {
};
let (pre_server, pre_url) = make_server(pre_handler);
let request = RequestBuilder::new(pre_url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1283,7 +1283,7 @@ fn test_redirect_from_x_to_y_provides_y_cookies_from_y() {
cookie_jar.push(cookie_y, &url_y, CookieSource::HTTP);
}
let request = RequestBuilder::new(url_x.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url_x.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1334,7 +1334,7 @@ fn test_redirect_from_x_to_x_provides_x_with_cookie_from_first_response() {
let url = url.join("/initial/").unwrap();
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.destination(Destination::Document)
.origin(mock_origin())
@ -1367,7 +1367,7 @@ fn test_if_auth_creds_not_in_url_but_in_cache_it_sets_it() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1412,7 +1412,7 @@ fn test_auth_ui_needs_www_auth() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1479,7 +1479,7 @@ fn test_fetch_compressed_response_update_count() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1565,7 +1565,7 @@ fn test_user_credentials_prompt_when_proxy_authentication_is_required() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1613,7 +1613,7 @@ fn test_prompt_credentials_when_client_receives_unauthorized_response() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1660,7 +1660,7 @@ fn test_prompt_credentials_user_cancels_dialog_input() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)
@ -1703,7 +1703,7 @@ fn test_prompt_credentials_user_input_incorrect_credentials() {
};
let (server, url) = make_server(handler);
let request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET)
.body(None)
.destination(Destination::Document)

View file

@ -26,9 +26,9 @@ use std::net::TcpListener as StdTcpListener;
use std::path::{Path, PathBuf};
use std::sync::{Arc, LazyLock, Mutex, RwLock, Weak};
use crossbeam_channel::{unbounded, Sender};
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::DevtoolsControlMsg;
use embedder_traits::{EmbedderProxy, EmbedderReceiver, EventLoopWaker};
use embedder_traits::{EmbedderMsg, EmbedderProxy, EventLoopWaker};
use futures::future::ready;
use http_body_util::combinators::BoxBody;
use http_body_util::{BodyExt, Empty, Full};
@ -96,7 +96,7 @@ fn create_embedder_proxy() -> EmbedderProxy {
}
}
fn create_embedder_proxy_and_receiver() -> (EmbedderProxy, EmbedderReceiver) {
fn create_embedder_proxy_and_receiver() -> (EmbedderProxy, Receiver<EmbedderMsg>) {
let (sender, receiver) = unbounded();
let event_loop_waker = || {
struct DummyEventLoopWaker {}
@ -120,19 +120,18 @@ fn create_embedder_proxy_and_receiver() -> (EmbedderProxy, EmbedderReceiver) {
event_loop_waker: event_loop_waker(),
};
let embedder_receiver = EmbedderReceiver { receiver };
(embedder_proxy, embedder_receiver)
(embedder_proxy, receiver)
}
fn receive_credential_prompt_msgs(
mut embedder_receiver: EmbedderReceiver,
embedder_receiver: Receiver<EmbedderMsg>,
username: Option<String>,
password: Option<String>,
) -> std::thread::JoinHandle<()> {
std::thread::spawn(move || loop {
let (_browser_context_id, embedder_msg) = embedder_receiver.recv_embedder_msg();
let embedder_msg = embedder_receiver.recv().unwrap();
match embedder_msg {
embedder_traits::EmbedderMsg::Prompt(prompt_definition, _prompt_origin) => {
embedder_traits::EmbedderMsg::Prompt(_, prompt_definition, _prompt_origin) => {
match prompt_definition {
embedder_traits::PromptDefinition::Credentials(ipc_sender) => {
ipc_sender
@ -143,7 +142,7 @@ fn receive_credential_prompt_msgs(
}
break;
},
embedder_traits::EmbedderMsg::WebResourceRequested(_, _) => {},
embedder_traits::EmbedderMsg::WebResourceRequested(..) => {},
_ => unreachable!(),
}
})

View file

@ -2,6 +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 base::id::WebViewId;
use embedder_traits::EmbedderMsg;
use ipc_channel::ipc::channel;
use script_traits::{ScriptMsg, ScriptToConstellationChan};
@ -13,19 +14,26 @@ pub trait ClipboardProvider {
fn set_clipboard_contents(&mut self, _: String);
}
impl ClipboardProvider for ScriptToConstellationChan {
pub(crate) struct EmbedderClipboardProvider {
pub constellation_sender: ScriptToConstellationChan,
pub webview_id: WebViewId,
}
impl ClipboardProvider for EmbedderClipboardProvider {
fn clipboard_contents(&mut self) -> String {
let (tx, rx) = channel().unwrap();
self.send(ScriptMsg::ForwardToEmbedder(
EmbedderMsg::GetClipboardContents(tx),
))
.unwrap();
self.constellation_sender
.send(ScriptMsg::ForwardToEmbedder(
EmbedderMsg::GetClipboardContents(self.webview_id, tx),
))
.unwrap();
rx.recv().unwrap()
}
fn set_clipboard_contents(&mut self, s: String) {
self.send(ScriptMsg::ForwardToEmbedder(
EmbedderMsg::SetClipboardContents(s),
))
.unwrap();
self.constellation_sender
.send(ScriptMsg::ForwardToEmbedder(
EmbedderMsg::SetClipboardContents(self.webview_id, s),
))
.unwrap();
}
}

View file

@ -220,6 +220,7 @@ impl Bluetooth {
}
let option = RequestDeviceoptions::new(
self.global().as_window().webview_id(),
BluetoothScanfilterSequence::new(uuid_filters),
ServiceUUIDSequence::new(optional_services_uuids),
);

View file

@ -6,7 +6,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId, WebViewId};
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::DevtoolScriptControlMsg;
use dom_struct::dom_struct;
@ -236,6 +236,10 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
}
impl DedicatedWorkerGlobalScope {
pub(crate) fn webview_id(&self) -> Option<WebViewId> {
WebViewId::installed()
}
#[allow(clippy::too_many_arguments)]
fn new_inherited(
init: WorkerGlobalScopeInit,
@ -361,15 +365,19 @@ impl DedicatedWorkerGlobalScope {
let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
let request = RequestBuilder::new(worker_url.clone(), referrer)
.destination(Destination::Worker)
.mode(RequestMode::SameOrigin)
.credentials_mode(CredentialsMode::CredentialsSameOrigin)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
.pipeline_id(Some(pipeline_id))
.referrer_policy(referrer_policy)
.origin(origin);
let request = RequestBuilder::new(
top_level_browsing_context_id,
worker_url.clone(),
referrer,
)
.destination(Destination::Worker)
.mode(RequestMode::SameOrigin)
.credentials_mode(CredentialsMode::CredentialsSameOrigin)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
.pipeline_id(Some(pipeline_id))
.referrer_policy(referrer_policy)
.origin(origin);
let runtime = unsafe {
let task_source = SendableTaskSource {

View file

@ -15,6 +15,7 @@ use std::sync::{LazyLock, Mutex};
use std::time::{Duration, Instant};
use base::cross_process_instant::CrossProcessInstant;
use base::id::WebViewId;
use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg};
use chrono::Local;
use content_security_policy::{self as csp, CspList};
@ -648,6 +649,10 @@ impl Document {
}
}
pub(crate) fn webview_id(&self) -> WebViewId {
self.window.webview_id()
}
#[inline]
pub(crate) fn window(&self) -> &Window {
&self.window
@ -1027,13 +1032,13 @@ impl Document {
match state {
DocumentReadyState::Loading => {
if self.window().is_top_level() {
self.send_to_embedder(EmbedderMsg::LoadStart);
self.send_to_embedder(EmbedderMsg::Status(None));
self.send_to_embedder(EmbedderMsg::LoadStart(self.webview_id()));
self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
}
},
DocumentReadyState::Complete => {
if self.window().is_top_level() {
self.send_to_embedder(EmbedderMsg::LoadComplete);
self.send_to_embedder(EmbedderMsg::LoadComplete(self.webview_id()));
}
update_with_current_instant(&self.dom_complete);
},
@ -1121,7 +1126,7 @@ impl Document {
// Notify the embedder to hide the input method.
if elem.input_method_type().is_some() {
self.send_to_embedder(EmbedderMsg::HideIME);
self.send_to_embedder(EmbedderMsg::HideIME(self.webview_id()));
}
}
@ -1165,6 +1170,7 @@ impl Document {
(None, false)
};
self.send_to_embedder(EmbedderMsg::ShowIME(
self.webview_id(),
kind,
text,
multiline,
@ -1225,7 +1231,7 @@ impl Document {
let window = self.window();
if window.is_top_level() {
let title = self.title().map(String::from);
self.send_to_embedder(EmbedderMsg::ChangePageTitle(title));
self.send_to_embedder(EmbedderMsg::ChangePageTitle(self.webview_id(), title));
}
}
@ -1621,7 +1627,7 @@ impl Document {
// Step 1
if drag_data_store.list_len() > 0 {
// Step 1.1 Clear the clipboard.
self.send_to_embedder(EmbedderMsg::ClearClipboardContents);
self.send_to_embedder(EmbedderMsg::ClearClipboardContents(self.webview_id()));
// Step 1.2
for item in drag_data_store.iter_item_list() {
match item {
@ -1629,7 +1635,10 @@ impl Document {
// Step 1.2.1.1 Ensure encoding is correct per OS and locale conventions
// Step 1.2.1.2 Normalize line endings according to platform conventions
// Step 1.2.1.3
self.send_to_embedder(EmbedderMsg::SetClipboardContents(string.data()));
self.send_to_embedder(EmbedderMsg::SetClipboardContents(
self.webview_id(),
string.data(),
));
},
Kind::File(_) => {
// Step 1.2.2 If data is of a type listed in the mandatory data types list, then
@ -1642,7 +1651,7 @@ impl Document {
// Step 2.1
if drag_data_store.clear_was_called {
// Step 2.1.1 If types-to-clear list is empty, clear the clipboard
self.send_to_embedder(EmbedderMsg::ClearClipboardContents);
self.send_to_embedder(EmbedderMsg::ClearClipboardContents(self.webview_id()));
// Step 2.1.2 Else remove the types in the list from the clipboard
// As of now this can't be done with Arboard, and it's possible that will be removed from the spec
}
@ -2049,7 +2058,7 @@ impl Document {
}
if cancel_state == EventDefault::Allowed {
let msg = EmbedderMsg::Keyboard(keyboard_event.clone());
let msg = EmbedderMsg::Keyboard(self.webview_id(), keyboard_event.clone());
self.send_to_embedder(msg);
// This behavior is unspecced
@ -2455,7 +2464,7 @@ impl Document {
.is_empty();
if default_prevented || return_value_not_empty {
let (chan, port) = ipc::channel().expect("Failed to create IPC channel!");
let msg = EmbedderMsg::AllowUnload(chan);
let msg = EmbedderMsg::AllowUnload(self.webview_id(), chan);
self.send_to_embedder(msg);
can_unload = port.recv().unwrap();
}
@ -4049,7 +4058,7 @@ impl Document {
let window = self.window();
// Step 6
if !error {
let event = EmbedderMsg::SetFullscreenState(true);
let event = EmbedderMsg::SetFullscreenState(self.webview_id(), true);
self.send_to_embedder(event);
}
@ -4091,7 +4100,7 @@ impl Document {
let window = self.window();
// Step 8
let event = EmbedderMsg::SetFullscreenState(false);
let event = EmbedderMsg::SetFullscreenState(self.webview_id(), false);
self.send_to_embedder(event);
// Step 9

View file

@ -554,6 +554,7 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource {
// Step 8
// TODO: Step 9 set request's client settings
let mut request = create_a_potential_cors_request(
global.webview_id(),
url_record,
Destination::None,
Some(cors_attribute_state),

View file

@ -235,6 +235,7 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
weak_magnitude: *params.weakMagnitude,
};
let event = EmbedderMsg::PlayGamepadHapticEffect(
document.webview_id(),
self.gamepad_index as usize,
embedder_traits::GamepadHapticEffectType::DualRumble(params),
effect_complete_sender,
@ -287,8 +288,11 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
}),
);
let event =
EmbedderMsg::StopGamepadHapticEffect(self.gamepad_index as usize, effect_stop_sender);
let event = EmbedderMsg::StopGamepadHapticEffect(
document.webview_id(),
self.gamepad_index as usize,
effect_stop_sender,
);
self.global().as_window().send_to_embedder(event);
self.playing_effect_promise.borrow().clone().unwrap()
@ -356,7 +360,12 @@ impl GamepadHapticActuator {
let (send, _rcv) = ipc::channel().expect("ipc channel failure");
let event = EmbedderMsg::StopGamepadHapticEffect(self.gamepad_index as usize, send);
let document = self.global().as_window().Document();
let event = EmbedderMsg::StopGamepadHapticEffect(
document.webview_id(),
self.gamepad_index as usize,
send,
);
self.global().as_window().send_to_embedder(event);
}
}

View file

@ -16,7 +16,7 @@ use std::{mem, ptr};
use base::id::{
BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
ServiceWorkerId, ServiceWorkerRegistrationId,
ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
};
use content_security_policy::{CheckResult, CspList, PolicyDisposition};
use crossbeam_channel::Sender;
@ -691,6 +691,20 @@ impl FileListener {
}
impl GlobalScope {
/// A sender to the event loop of this global scope. This either sends to the Worker event loop
/// or the ScriptThread event loop in the case of a `Window`. This can be `None` for dedicated
/// workers that are not currently handling a message.
pub(crate) fn webview_id(&self) -> Option<WebViewId> {
if let Some(window) = self.downcast::<Window>() {
Some(window.webview_id())
} else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
dedicated.webview_id()
} else {
// ServiceWorkerGlobalScope, PaintWorklet, or DissimilarOriginWindow
None
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn new_inherited(
pipeline_id: PipelineId,

View file

@ -153,7 +153,7 @@ impl VirtualMethods for HTMLBodyElement {
let window = self.owner_window();
window.prevent_layout_until_load_event();
if window.is_top_level() {
window.send_to_embedder(EmbedderMsg::HeadParsed);
window.send_to_embedder(EmbedderMsg::HeadParsed(window.webview_id()));
}
}

View file

@ -10,7 +10,6 @@ use std::sync::Arc;
use std::{char, mem};
use app_units::{Au, AU_PER_PX};
use base::id::PipelineId;
use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct;
use euclid::Point2D;
@ -23,16 +22,14 @@ use net_traits::image_cache::{
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponder, ImageResponse,
PendingImageId, UsePlaceholder,
};
use net_traits::request::{
CorsSettings, Destination, Initiator, Referrer, RequestBuilder, RequestId,
};
use net_traits::request::{Destination, Initiator, RequestId};
use net_traits::{
FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError, ReferrerPolicy,
ResourceFetchTiming, ResourceTimingType,
};
use num_traits::ToPrimitive;
use pixels::{CorsStatus, Image, ImageMetadata};
use servo_url::origin::{ImmutableOrigin, MutableOrigin};
use servo_url::origin::MutableOrigin;
use servo_url::ServoUrl;
use style::attr::{parse_integer, parse_length, AttrValue, LengthOrPercentageOrAuto};
use style::context::QuirksMode;
@ -318,34 +315,6 @@ impl PreInvoke for ImageContext {
}
}
#[derive(PartialEq)]
pub(crate) enum FromPictureOrSrcSet {
Yes,
No,
}
// https://html.spec.whatwg.org/multipage/#update-the-image-data steps 17-20
// This function is also used to prefetch an image in `script::dom::servoparser::prefetch`.
pub(crate) fn image_fetch_request(
img_url: ServoUrl,
origin: ImmutableOrigin,
referrer: Referrer,
pipeline_id: PipelineId,
cors_setting: Option<CorsSettings>,
referrer_policy: ReferrerPolicy,
from_picture_or_srcset: FromPictureOrSrcSet,
) -> RequestBuilder {
let mut request =
create_a_potential_cors_request(img_url, Destination::Image, cors_setting, None, referrer)
.origin(origin)
.pipeline_id(Some(pipeline_id))
.referrer_policy(referrer_policy);
if from_picture_or_srcset == FromPictureOrSrcSet::Yes {
request = request.initiator(Initiator::ImageSet);
}
request
}
#[allow(non_snake_case)]
impl HTMLImageElement {
/// Update the current image with a valid URL.
@ -445,19 +414,23 @@ impl HTMLImageElement {
url: img_url.clone(),
};
let request = image_fetch_request(
// https://html.spec.whatwg.org/multipage/#update-the-image-data steps 17-20
// This function is also used to prefetch an image in `script::dom::servoparser::prefetch`.
let mut request = create_a_potential_cors_request(
Some(window.webview_id()),
img_url.clone(),
document.origin().immutable().clone(),
document.global().get_referrer(),
document.global().pipeline_id(),
Destination::Image,
cors_setting_for_element(self.upcast()),
referrer_policy_for_element(self.upcast()),
if Self::uses_srcset_or_picture(self.upcast()) {
FromPictureOrSrcSet::Yes
} else {
FromPictureOrSrcSet::No
},
);
None,
document.global().get_referrer(),
)
.origin(document.origin().immutable().clone())
.pipeline_id(Some(document.global().pipeline_id()))
.referrer_policy(referrer_policy_for_element(self.upcast()));
if Self::uses_srcset_or_picture(self.upcast()) {
request = request.initiator(Initiator::ImageSet);
}
// This is a background load because the load blocker already fulfills the
// purpose of delaying the document's load event.

View file

@ -24,7 +24,6 @@ use net_traits::blob_url_store::get_blob_origin;
use net_traits::filemanager_thread::FileManagerThreadMsg;
use net_traits::{CoreResourceMsg, IpcSend};
use profile_traits::ipc;
use script_traits::ScriptToConstellationChan;
use servo_atoms::Atom;
use style::attr::AttrValue;
use style::str::{split_commas, str_join};
@ -34,6 +33,7 @@ use unicode_bidi::{bidi_class, BidiClass};
use url::Url;
use super::bindings::str::{FromInputValueString, ToInputValueString};
use crate::clipboard_provider::EmbedderClipboardProvider;
use crate::dom::activation::Activatable;
use crate::dom::attr::Attr;
use crate::dom::bindings::cell::DomRefCell;
@ -299,7 +299,7 @@ pub(crate) struct HTMLInputElement {
minlength: Cell<i32>,
#[ignore_malloc_size_of = "TextInput contains an IPCSender which cannot be measured"]
#[no_trace]
textinput: DomRefCell<TextInput<ScriptToConstellationChan>>,
textinput: DomRefCell<TextInput<EmbedderClipboardProvider>>,
// https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag
value_dirty: Cell<bool>,
// not specified explicitly, but implied by the fact that sanitization can't
@ -334,7 +334,7 @@ impl HTMLInputElement {
prefix: Option<Prefix>,
document: &Document,
) -> HTMLInputElement {
let chan = document
let constellation_sender = document
.window()
.as_global_scope()
.script_to_constellation_chan()
@ -355,7 +355,10 @@ impl HTMLInputElement {
textinput: DomRefCell::new(TextInput::new(
Single,
DOMString::new(),
chan,
EmbedderClipboardProvider {
constellation_sender,
webview_id: document.webview_id(),
},
None,
None,
SelectionDirection::None,
@ -1897,6 +1900,7 @@ impl HTMLInputElement {
let mut files: Vec<DomRoot<File>> = vec![];
let mut error = None;
let webview_id = window.webview_id();
let filter = filter_from_accept(&self.Accept());
let target = self.upcast::<EventTarget>();
@ -1906,7 +1910,8 @@ impl HTMLInputElement {
let (chan, recv) = ipc::channel(self.global().time_profiler_chan().clone())
.expect("Error initializing channel");
let msg = FileManagerThreadMsg::SelectFiles(filter, chan, origin, opt_test_paths);
let msg =
FileManagerThreadMsg::SelectFiles(webview_id, filter, chan, origin, opt_test_paths);
resource_threads
.send(CoreResourceMsg::ToFileManager(msg))
.unwrap();
@ -1933,7 +1938,8 @@ impl HTMLInputElement {
let (chan, recv) = ipc::channel(self.global().time_profiler_chan().clone())
.expect("Error initializing channel");
let msg = FileManagerThreadMsg::SelectFile(filter, chan, origin, opt_test_path);
let msg =
FileManagerThreadMsg::SelectFile(webview_id, filter, chan, origin, opt_test_path);
resource_threads
.send(CoreResourceMsg::ToFileManager(msg))
.unwrap();

View file

@ -6,6 +6,7 @@ use std::borrow::{Borrow, ToOwned};
use std::cell::Cell;
use std::default::Default;
use base::id::WebViewId;
use cssparser::{Parser as CssParser, ParserInput};
use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
@ -366,7 +367,7 @@ impl HTMLLinkElement {
// Step 4. Let request be the result of creating a link request given options.
let url = options.base_url.clone();
let Some(request) = options.create_link_request() else {
let Some(request) = options.create_link_request(self.owner_window().webview_id()) else {
// Step 5. If request is null, then return.
return;
};
@ -466,7 +467,7 @@ impl HTMLLinkElement {
Ok(url) => {
let window = document.window();
if window.is_top_level() {
let msg = EmbedderMsg::NewFavicon(url.clone());
let msg = EmbedderMsg::NewFavicon(document.webview_id(), url.clone());
window.send_to_embedder(msg);
}
},
@ -626,7 +627,7 @@ impl HTMLLinkElementMethods<crate::DomTypeHolder> for HTMLLinkElement {
impl LinkProcessingOptions {
/// <https://html.spec.whatwg.org/multipage/#create-a-link-request>
fn create_link_request(self) -> Option<RequestBuilder> {
fn create_link_request(self, webview_id: WebViewId) -> Option<RequestBuilder> {
// Step 1. Assert: options's href is not the empty string.
assert!(!self.href.is_empty());
@ -651,6 +652,7 @@ impl LinkProcessingOptions {
// FIXME: Step 11. Set request's priority to options's fetch priority.
// FIXME: Use correct referrer
let builder = create_a_potential_cors_request(
Some(webview_id),
url,
destination,
self.cross_origin,

View file

@ -885,6 +885,7 @@ impl HTMLMediaElement {
let cors_setting = cors_setting_for_element(self.upcast());
let request = create_a_potential_cors_request(
Some(document.webview_id()),
url.clone(),
destination,
cors_setting,

View file

@ -11,7 +11,7 @@ use std::ptr;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use base::id::PipelineId;
use base::id::{PipelineId, WebViewId};
use content_security_policy as csp;
use dom_struct::dom_struct;
use encoding_rs::Encoding;
@ -542,6 +542,7 @@ impl PreInvoke for ClassicContext {}
/// Steps 1-2 of <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
// This function is also used to prefetch a script in `script::dom::servoparser::prefetch`.
pub(crate) fn script_fetch_request(
webview_id: WebViewId,
url: ServoUrl,
cors_setting: Option<CorsSettings>,
origin: ImmutableOrigin,
@ -551,6 +552,7 @@ pub(crate) fn script_fetch_request(
// We intentionally ignore options' credentials_mode member for classic scripts.
// The mode is initialized by create_a_potential_cors_request.
create_a_potential_cors_request(
Some(webview_id),
url,
Destination::Script,
cors_setting,
@ -576,6 +578,7 @@ fn fetch_a_classic_script(
// Step 1, 2.
let doc = script.owner_document();
let request = script_fetch_request(
doc.webview_id(),
url.clone(),
cors_setting,
doc.origin().immutable().clone(),

View file

@ -9,10 +9,10 @@ use std::ops::Range;
use dom_struct::dom_struct;
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
use js::rust::HandleObject;
use script_traits::ScriptToConstellationChan;
use style::attr::AttrValue;
use style_dom::ElementState;
use crate::clipboard_provider::EmbedderClipboardProvider;
use crate::dom::attr::Attr;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
@ -52,7 +52,7 @@ pub(crate) struct HTMLTextAreaElement {
htmlelement: HTMLElement,
#[ignore_malloc_size_of = "TextInput contains an IPCSender which cannot be measured"]
#[no_trace]
textinput: DomRefCell<TextInput<ScriptToConstellationChan>>,
textinput: DomRefCell<TextInput<EmbedderClipboardProvider>>,
placeholder: DomRefCell<DOMString>,
// https://html.spec.whatwg.org/multipage/#concept-textarea-dirty
value_dirty: Cell<bool>,
@ -142,7 +142,7 @@ impl HTMLTextAreaElement {
prefix: Option<Prefix>,
document: &Document,
) -> HTMLTextAreaElement {
let chan = document
let constellation_sender = document
.window()
.as_global_scope()
.script_to_constellation_chan()
@ -158,7 +158,10 @@ impl HTMLTextAreaElement {
textinput: DomRefCell::new(TextInput::new(
Lines::Multiple,
DOMString::new(),
chan,
EmbedderClipboardProvider {
constellation_sender,
webview_id: document.webview_id(),
},
None,
None,
SelectionDirection::None,

View file

@ -223,12 +223,16 @@ impl HTMLVideoElement {
fn do_fetch_poster_frame(&self, poster_url: ServoUrl, id: PendingImageId, can_gc: CanGc) {
// Continuation of step 4.
let document = self.owner_document();
let request = RequestBuilder::new(poster_url.clone(), document.global().get_referrer())
.destination(Destination::Image)
.credentials_mode(CredentialsMode::Include)
.use_url_credentials(true)
.origin(document.origin().immutable().clone())
.pipeline_id(Some(document.global().pipeline_id()));
let request = RequestBuilder::new(
Some(document.webview_id()),
poster_url.clone(),
document.global().get_referrer(),
)
.destination(Destination::Image)
.credentials_mode(CredentialsMode::Include)
.use_url_credentials(true)
.origin(document.origin().immutable().clone())
.pipeline_id(Some(document.global().pipeline_id()));
// Step 5.
// This delay must be independent from the ones created by HTMLMediaElement during

View file

@ -362,8 +362,12 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool {
}
fn prompt_user_from_embedder(prompt: PermissionPrompt, gs: &GlobalScope) -> PermissionState {
let Some(webview_id) = gs.webview_id() else {
warn!("Requesting permissions from non-webview-associated global scope");
return PermissionState::Denied;
};
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
gs.send_to_embedder(EmbedderMsg::PromptPermission(prompt, sender));
gs.send_to_embedder(EmbedderMsg::PromptPermission(webview_id, prompt, sender));
match receiver.recv() {
Ok(PermissionRequest::Granted) => PermissionState::Granted,

View file

@ -108,7 +108,7 @@ impl Request {
}
fn net_request_from_global(global: &GlobalScope, url: ServoUrl) -> NetTraitsRequest {
RequestBuilder::new(url, global.get_referrer())
RequestBuilder::new(global.webview_id(), url, global.get_referrer())
.origin(global.get_url().origin())
.pipeline_id(Some(global.pipeline_id()))
.https_state(global.get_https_state())

View file

@ -334,7 +334,7 @@ impl ServiceWorkerGlobalScope {
.map(Referrer::ReferrerUrl)
.unwrap_or_else(|| global.upcast::<GlobalScope>().get_referrer());
let request = RequestBuilder::new(script_url, referrer)
let request = RequestBuilder::new(None, script_url, referrer)
.destination(Destination::ServiceWorker)
.credentials_mode(CredentialsMode::Include)
.parser_metadata(ParserMetadata::NotParserInserted)

View file

@ -4,7 +4,8 @@
use std::cell::{Cell, RefCell};
use base::id::PipelineId;
use base::id::{PipelineId, WebViewId};
use content_security_policy::Destination;
use html5ever::buffer_queue::BufferQueue;
use html5ever::tokenizer::states::RawKind;
use html5ever::tokenizer::{
@ -19,10 +20,9 @@ use servo_url::{ImmutableOrigin, ServoUrl};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::trace::{CustomTraceable, JSTraceable};
use crate::dom::document::{determine_policy_for_token, Document};
use crate::dom::htmlimageelement::{image_fetch_request, FromPictureOrSrcSet};
use crate::dom::htmlscriptelement::script_fetch_request;
use crate::fetch::create_a_potential_cors_request;
use crate::script_module::ScriptFetchOptions;
use crate::stylesheet_loader::stylesheet_fetch_request;
#[derive(JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
@ -43,6 +43,7 @@ impl Tokenizer {
let sink = PrefetchSink {
origin: document.origin().immutable().clone(),
pipeline_id: document.global().pipeline_id(),
webview_id: document.webview_id(),
base_url: RefCell::new(None),
document_url: document.url(),
referrer: document.global().get_referrer(),
@ -70,6 +71,8 @@ struct PrefetchSink {
#[no_trace]
pipeline_id: PipelineId,
#[no_trace]
webview_id: WebViewId,
#[no_trace]
document_url: ServoUrl,
#[no_trace]
base_url: RefCell<Option<ServoUrl>>,
@ -102,6 +105,7 @@ impl TokenSink for PrefetchSink {
.map(|attr| String::from(&attr.value))
.unwrap_or_default();
let request = script_fetch_request(
self.webview_id,
url,
cors_setting,
self.origin.clone(),
@ -124,15 +128,18 @@ impl TokenSink for PrefetchSink {
(TagKind::StartTag, &local_name!("img")) if self.prefetching.get() => {
if let Some(url) = self.get_url(tag, local_name!("src")) {
debug!("Prefetch {} {}", tag.name, url);
let request = image_fetch_request(
let request = create_a_potential_cors_request(
Some(self.webview_id),
url,
self.origin.clone(),
self.referrer.clone(),
self.pipeline_id,
Destination::Image,
self.get_cors_settings(tag, local_name!("crossorigin")),
self.get_referrer_policy(tag, local_name!("referrerpolicy")),
FromPictureOrSrcSet::No,
);
None,
self.referrer.clone(),
)
.origin(self.origin.clone())
.pipeline_id(Some(self.pipeline_id))
.referrer_policy(self.get_referrer_policy(tag, local_name!("referrerpolicy")));
let _ = self
.resource_threads
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));
@ -152,15 +159,21 @@ impl TokenSink for PrefetchSink {
.get_attr(tag, local_name!("integrity"))
.map(|attr| String::from(&attr.value))
.unwrap_or_default();
let request = stylesheet_fetch_request(
// https://html.spec.whatwg.org/multipage/#default-fetch-and-process-the-linked-resource
let request = create_a_potential_cors_request(
Some(self.webview_id),
url,
Destination::Style,
cors_setting,
self.origin.clone(),
self.pipeline_id,
None,
self.referrer.clone(),
referrer_policy,
integrity_metadata,
);
)
.origin(self.origin.clone())
.pipeline_id(Some(self.pipeline_id))
.referrer_policy(referrer_policy)
.integrity_metadata(integrity_metadata);
let _ = self
.resource_threads
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));

View file

@ -7,8 +7,7 @@
//!
//! <https://html.spec.whatwg.org/multipage/#textFieldSelection>
use script_traits::ScriptToConstellationChan;
use crate::clipboard_provider::EmbedderClipboardProvider;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::SelectionMode;
use crate::dom::bindings::conversions::DerivedFrom;
@ -27,13 +26,13 @@ pub(crate) trait TextControlElement: DerivedFrom<EventTarget> + DerivedFrom<Node
pub(crate) struct TextControlSelection<'a, E: TextControlElement> {
element: &'a E,
textinput: &'a DomRefCell<TextInput<ScriptToConstellationChan>>,
textinput: &'a DomRefCell<TextInput<EmbedderClipboardProvider>>,
}
impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
pub(crate) fn new(
element: &'a E,
textinput: &'a DomRefCell<TextInput<ScriptToConstellationChan>>,
textinput: &'a DomRefCell<TextInput<EmbedderClipboardProvider>>,
) -> Self {
TextControlSelection { element, textinput }
}

View file

@ -255,7 +255,7 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
let ws = WebSocket::new(global, proto, url_record.clone(), dom_action_sender, can_gc);
let address = Trusted::new(&*ws);
let request = RequestBuilder::new(url_record, Referrer::NoReferrer)
let request = RequestBuilder::new(global.webview_id(), url_record, Referrer::NoReferrer)
.origin(global.origin().immutable().clone())
.mode(RequestMode::WebSocket { protocols });

View file

@ -17,7 +17,7 @@ use std::time::{Duration, Instant};
use app_units::Au;
use backtrace::Backtrace;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{BrowsingContextId, PipelineId};
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use base64::Engine;
use bluetooth_traits::BluetoothRequest;
use canvas_traits::webgl::WebGLChan;
@ -209,6 +209,11 @@ impl LayoutBlocker {
#[dom_struct]
pub(crate) struct Window {
globalscope: GlobalScope,
/// The webview that contains this [`Window`].
///
/// This may not be the top-level [`Window`], in the case of frames.
#[no_trace]
webview_id: WebViewId,
script_chan: Sender<MainThreadScriptMsg>,
#[no_trace]
#[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"]
@ -391,6 +396,10 @@ pub(crate) struct Window {
}
impl Window {
pub(crate) fn webview_id(&self) -> WebViewId {
self.webview_id
}
pub(crate) fn as_global_scope(&self) -> &GlobalScope {
self.upcast::<GlobalScope>()
}
@ -726,7 +735,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let (sender, receiver) =
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
let prompt = PromptDefinition::Alert(s.to_string(), sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
self.send_to_embedder(msg);
receiver.recv().unwrap();
}
@ -736,7 +745,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let (sender, receiver) =
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
let prompt = PromptDefinition::OkCancel(s.to_string(), sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
self.send_to_embedder(msg);
receiver.recv().unwrap() == PromptResult::Primary
}
@ -746,7 +755,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let (sender, receiver) =
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
let prompt = PromptDefinition::Input(message.to_string(), default.to_string(), sender);
let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
let msg = EmbedderMsg::Prompt(self.webview_id(), prompt, PromptOrigin::Untrusted);
self.send_to_embedder(msg);
receiver.recv().unwrap().map(|s| s.into())
}
@ -1322,7 +1331,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
//TODO determine if this operation is allowed
let dpr = self.device_pixel_ratio();
let size = Size2D::new(width, height).to_f32() * dpr;
self.send_to_embedder(EmbedderMsg::ResizeTo(size.to_i32()));
self.send_to_embedder(EmbedderMsg::ResizeTo(self.webview_id(), size.to_i32()));
}
// https://drafts.csswg.org/cssom-view/#dom-window-resizeby
@ -1341,7 +1350,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
//TODO determine if this operation is allowed
let dpr = self.device_pixel_ratio();
let point = Point2D::new(x, y).to_f32() * dpr;
let msg = EmbedderMsg::MoveTo(point.to_i32());
let msg = EmbedderMsg::MoveTo(self.webview_id(), point.to_i32());
self.send_to_embedder(msg);
}
@ -2738,6 +2747,7 @@ impl Window {
#[allow(unsafe_code)]
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
webview_id: WebViewId,
runtime: Rc<Runtime>,
script_chan: Sender<MainThreadScriptMsg>,
layout: Box<dyn Layout>,
@ -2786,6 +2796,7 @@ impl Window {
));
let win = Box::new(Self {
webview_id,
globalscope: GlobalScope::new_inherited(
pipeline_id,
devtools_chan,

View file

@ -292,7 +292,7 @@ impl WindowProxy {
.and_then(ScriptThread::find_document)
.map(|doc| DomRoot::from_ref(doc.window()))
.unwrap();
let msg = EmbedderMsg::AllowOpeningWebView(chan);
let msg = EmbedderMsg::AllowOpeningWebView(window.webview_id(), chan);
window.send_to_embedder(msg);
if let Some(new_top_level_browsing_context_id) = port.recv().unwrap() {
let new_browsing_context_id =

View file

@ -278,13 +278,17 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
rooted!(in(self.runtime.borrow().as_ref().unwrap().cx()) let mut rval = UndefinedValue());
for url in urls {
let global_scope = self.upcast::<GlobalScope>();
let request = NetRequestInit::new(url.clone(), global_scope.get_referrer())
.destination(Destination::Script)
.credentials_mode(CredentialsMode::Include)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
.origin(global_scope.origin().immutable().clone())
.pipeline_id(Some(self.upcast::<GlobalScope>().pipeline_id()));
let request = NetRequestInit::new(
global_scope.webview_id(),
url.clone(),
global_scope.get_referrer(),
)
.destination(Destination::Script)
.credentials_mode(CredentialsMode::Include)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
.origin(global_scope.origin().immutable().clone())
.pipeline_id(Some(self.upcast::<GlobalScope>().pipeline_id()));
let (url, source) = match fetch::load_whole_resource(
request,

View file

@ -652,6 +652,7 @@ impl WorkletThread {
// TODO: Caching.
let resource_fetcher = self.global_init.resource_threads.sender();
let request = RequestBuilder::new(
None,
script_url,
global_scope.upcast::<GlobalScope>().get_referrer(),
)

View file

@ -673,6 +673,7 @@ impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest {
};
let mut request = RequestBuilder::new(
self.global().webview_id(),
self.request_url.borrow().clone().unwrap(),
self.referrer.clone(),
)

View file

@ -5,6 +5,7 @@
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use base::id::WebViewId;
use ipc_channel::ipc;
use net_traits::policy_container::RequestPolicyContainer;
use net_traits::request::{
@ -113,7 +114,7 @@ fn request_init_from_request(request: NetTraitsRequest) -> RequestBuilder {
referrer: request.referrer.clone(),
referrer_policy: request.referrer_policy,
pipeline_id: request.pipeline_id,
target_browsing_context_id: request.target_browsing_context_id,
target_webview_id: request.target_webview_id,
redirect_mode: request.redirect_mode,
integrity_metadata: request.integrity_metadata.clone(),
url_list: vec![],
@ -366,13 +367,14 @@ pub(crate) fn load_whole_resource(
/// <https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request>
pub(crate) fn create_a_potential_cors_request(
webview_id: Option<WebViewId>,
url: ServoUrl,
destination: Destination,
cors_setting: Option<CorsSettings>,
same_origin_fallback: Option<bool>,
referrer: Referrer,
) -> RequestBuilder {
RequestBuilder::new(url, referrer)
RequestBuilder::new(webview_id, url, referrer)
// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
// Step 1
.mode(match cors_setting {

View file

@ -106,10 +106,14 @@ pub(crate) fn fetch_image_for_layout(
url: url.clone(),
};
let request = FetchRequestInit::new(url, document.global().get_referrer())
.origin(document.origin().immutable().clone())
.destination(Destination::Image)
.pipeline_id(Some(document.global().pipeline_id()));
let request = FetchRequestInit::new(
Some(document.webview_id()),
url,
document.global().get_referrer(),
)
.origin(document.origin().immutable().clone())
.destination(Destination::Image)
.pipeline_id(Some(document.global().pipeline_id()));
// Layout image loads do not delay the document load event.
document.fetch_background(request, context);

View file

@ -192,21 +192,23 @@ impl InProgressLoad {
pub(crate) fn request_builder(&mut self) -> RequestBuilder {
let id = self.pipeline_id;
let top_level_browsing_context_id = self.top_level_browsing_context_id;
let mut request_builder =
RequestBuilder::new(self.load_data.url.clone(), self.load_data.referrer.clone())
.method(self.load_data.method.clone())
.destination(Destination::Document)
.mode(RequestMode::Navigate)
.credentials_mode(CredentialsMode::Include)
.use_url_credentials(true)
.pipeline_id(Some(id))
.target_browsing_context_id(Some(top_level_browsing_context_id))
.referrer_policy(self.load_data.referrer_policy)
.headers(self.load_data.headers.clone())
.body(self.load_data.data.clone())
.redirect_mode(RedirectMode::Manual)
.origin(self.origin.immutable().clone())
.crash(self.load_data.crash.clone());
let mut request_builder = RequestBuilder::new(
Some(top_level_browsing_context_id),
self.load_data.url.clone(),
self.load_data.referrer.clone(),
)
.method(self.load_data.method.clone())
.destination(Destination::Document)
.mode(RequestMode::Navigate)
.credentials_mode(CredentialsMode::Include)
.use_url_credentials(true)
.pipeline_id(Some(id))
.referrer_policy(self.load_data.referrer_policy)
.headers(self.load_data.headers.clone())
.body(self.load_data.data.clone())
.redirect_mode(RedirectMode::Manual)
.origin(self.origin.immutable().clone())
.crash(self.load_data.crash.clone());
request_builder.url_list = self.url_list.clone();
if !request_builder.headers.contains_key(header::ACCEPT) {

View file

@ -1745,9 +1745,10 @@ fn fetch_single_module_script(
ModuleOwner::Worker(_) | ModuleOwner::DynamicModule(_) => None,
ModuleOwner::Window(script) => Some(script.root().owner_document()),
};
let webview_id = document.as_ref().map(|document| document.webview_id());
// Step 7-8.
let request = RequestBuilder::new(url.clone(), global.get_referrer())
let request = RequestBuilder::new(webview_id, url.clone(), global.get_referrer())
.destination(destination)
.origin(global.origin().immutable().clone())
.parser_metadata(options.parser_metadata)

View file

@ -1052,7 +1052,7 @@ impl ScriptThread {
let url = document.url();
url.join(&value).map(|url| url.to_string()).ok()
});
let event = EmbedderMsg::Status(status);
let event = EmbedderMsg::Status(window.webview_id(), status);
window.send_to_embedder(event);
state_already_changed = true;
@ -1069,7 +1069,7 @@ impl ScriptThread {
.next()
.is_some()
{
let event = EmbedderMsg::Status(None);
let event = EmbedderMsg::Status(window.webview_id(), None);
window.send_to_embedder(event);
}
}
@ -3101,9 +3101,9 @@ impl ScriptThread {
let layout_config = LayoutConfig {
id: incomplete.pipeline_id,
webview_id: incomplete.top_level_browsing_context_id,
url: final_url.clone(),
is_iframe: incomplete.parent_info.is_some(),
constellation_chan: self.senders.layout_to_constellation_ipc_sender.clone(),
script_chan: self.senders.constellation_sender.clone(),
image_cache: self.image_cache.clone(),
font_context: font_context.clone(),
@ -3115,6 +3115,7 @@ impl ScriptThread {
// Create the window and document objects.
let window = Window::new(
incomplete.top_level_browsing_context_id,
self.js_runtime.clone(),
self.senders.self_sender.clone(),
self.layout_factory.create(layout_config),

View file

@ -5,17 +5,16 @@
use std::io::{Read, Seek, Write};
use std::sync::atomic::AtomicBool;
use base::id::PipelineId;
use cssparser::SourceLocation;
use encoding_rs::UTF_8;
use mime::{self, Mime};
use net_traits::request::{CorsSettings, Destination, Referrer, RequestBuilder, RequestId};
use net_traits::request::{CorsSettings, Destination, RequestId};
use net_traits::{
FetchMetadata, FetchResponseListener, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy,
ResourceFetchTiming, ResourceTimingType,
};
use servo_arc::Arc;
use servo_url::{ImmutableOrigin, ServoUrl};
use servo_url::ServoUrl;
use style::media_queries::MediaList;
use style::parser::ParserContext;
use style::shared_lock::{Locked, SharedRwLock};
@ -343,39 +342,24 @@ impl StylesheetLoader<'_> {
document.increment_script_blocking_stylesheet_count();
}
let request = stylesheet_fetch_request(
// https://html.spec.whatwg.org/multipage/#default-fetch-and-process-the-linked-resource
let request = create_a_potential_cors_request(
Some(document.webview_id()),
url.clone(),
Destination::Style,
cors_setting,
document.origin().immutable().clone(),
self.elem.global().pipeline_id(),
None,
self.elem.global().get_referrer(),
referrer_policy,
integrity_metadata,
);
let request = document.prepare_request(request);
)
.origin(document.origin().immutable().clone())
.pipeline_id(Some(self.elem.global().pipeline_id()))
.referrer_policy(referrer_policy)
.integrity_metadata(integrity_metadata);
document.fetch(LoadType::Stylesheet(url), request, context);
}
}
// This function is also used to prefetch a stylesheet in `script::dom::servoparser::prefetch`.
// https://html.spec.whatwg.org/multipage/#default-fetch-and-process-the-linked-resource
pub(crate) fn stylesheet_fetch_request(
url: ServoUrl,
cors_setting: Option<CorsSettings>,
origin: ImmutableOrigin,
pipeline_id: PipelineId,
referrer: Referrer,
referrer_policy: ReferrerPolicy,
integrity_metadata: String,
) -> RequestBuilder {
create_a_potential_cors_request(url, Destination::Style, cors_setting, None, referrer)
.origin(origin)
.pipeline_id(Some(pipeline_id))
.referrer_policy(referrer_policy)
.integrity_metadata(integrity_metadata)
}
impl StyleStylesheetLoader for StylesheetLoader<'_> {
/// Request a stylesheet after parsing a given `@import` rule, and return
/// the constructed `@import` rule.

View file

@ -10,10 +10,9 @@ use std::default::Default;
use std::ops::{Add, AddAssign, Range};
use keyboard_types::{Key, KeyState, Modifiers, ShortcutMatcher};
use script_traits::ScriptToConstellationChan;
use unicode_segmentation::UnicodeSegmentation;
use crate::clipboard_provider::ClipboardProvider;
use crate::clipboard_provider::{ClipboardProvider, EmbedderClipboardProvider};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
use crate::dom::bindings::inheritance::Castable;
@ -1150,7 +1149,7 @@ impl<T: ClipboardProvider> TextInput<T> {
/// <https://www.w3.org/TR/clipboard-apis/#clipboard-actions> step 3
pub(crate) fn handle_text_clipboard_action(
owning_node: &impl NodeTraits,
textinput: &DomRefCell<TextInput<ScriptToConstellationChan>>,
textinput: &DomRefCell<TextInput<EmbedderClipboardProvider>>,
event: &ClipboardEvent,
can_gc: CanGc,
) -> bool {

View file

@ -128,7 +128,7 @@ impl ApplicationHandler<WakerEvent> for App {
webviews,
} = self
{
for (_webview_id, message) in servo.get_events().collect::<Vec<_>>() {
for message in servo.get_events().collect::<Vec<_>>() {
match message {
// FIXME: rust-analyzer autocompletes this as top_level_browsing_context_id
EmbedderMsg::WebViewOpened(webview_id) => {
@ -142,12 +142,12 @@ impl ApplicationHandler<WakerEvent> for App {
webview.raise_to_top(true);
}
},
EmbedderMsg::AllowOpeningWebView(webview_id_sender) => {
EmbedderMsg::AllowOpeningWebView(_, webview_id_sender) => {
let webview = servo.new_auxiliary_webview();
let _ = webview_id_sender.send(Some(webview.id()));
webviews.push(webview);
},
EmbedderMsg::AllowNavigationRequest(pipeline_id, _) => {
EmbedderMsg::AllowNavigationRequest(_, pipeline_id, _) => {
servo.handle_events([EmbedderEvent::AllowNavigationResponse(
pipeline_id,
true,

View file

@ -53,7 +53,7 @@ use constellation::{
Constellation, FromCompositorLogger, FromScriptLogger, InitialConstellationState,
UnprivilegedContent,
};
use crossbeam_channel::{unbounded, Sender};
use crossbeam_channel::{unbounded, Receiver, Sender};
pub use embedder_traits::*;
use env_logger::Builder as EnvLoggerBuilder;
use euclid::Scale;
@ -187,8 +187,8 @@ mod media_platform {
pub struct Servo {
compositor: Rc<RefCell<IOCompositor>>,
constellation_proxy: ConstellationProxy,
embedder_receiver: EmbedderReceiver,
messages_for_embedder: Vec<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
embedder_receiver: Receiver<EmbedderMsg>,
messages_for_embedder: Vec<EmbedderMsg>,
/// For single-process Servo instances, this field controls the initialization
/// and deinitialization of the JS Engine. Multiprocess Servo instances have their
/// own instance that exists in the content process instead.
@ -738,20 +738,17 @@ impl Servo {
.on_pinch_zoom_window_event(zoom);
},
EmbedderEvent::Navigation(top_level_browsing_context_id, direction) => {
let msg =
ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction);
EmbedderEvent::Navigation(webview_id, direction) => {
let msg = ConstellationMsg::TraverseHistory(webview_id, direction);
if let Err(e) = self.constellation_proxy.try_send(msg) {
warn!("Sending navigation to constellation failed ({:?}).", e);
}
self.messages_for_embedder.push((
Some(top_level_browsing_context_id),
EmbedderMsg::Status(None),
));
self.messages_for_embedder
.push(EmbedderMsg::Status(webview_id, None));
},
EmbedderEvent::Keyboard(key_event) => {
let msg = ConstellationMsg::Keyboard(key_event);
EmbedderEvent::Keyboard(webview_id, key_event) => {
let msg = ConstellationMsg::Keyboard(webview_id, key_event);
if let Err(e) = self.constellation_proxy.try_send(msg) {
warn!("Sending keyboard event to constellation failed ({:?}).", e);
}
@ -930,10 +927,8 @@ impl Servo {
}
fn receive_messages(&mut self) {
while let Some((top_level_browsing_context, msg)) =
self.embedder_receiver.try_recv_embedder_msg()
{
match (msg, self.compositor.borrow().shutdown_state) {
while let Ok(message) = self.embedder_receiver.try_recv() {
match (message, self.compositor.borrow().shutdown_state) {
(_, ShutdownState::FinishedShuttingDown) => {
error!(
"embedder shouldn't be handling messages after compositor has shut down"
@ -942,20 +937,19 @@ impl Servo {
(_, ShutdownState::ShuttingDown) => {},
(EmbedderMsg::Keyboard(key_event), ShutdownState::NotShuttingDown) => {
let event = (top_level_browsing_context, EmbedderMsg::Keyboard(key_event));
self.messages_for_embedder.push(event);
(EmbedderMsg::Keyboard(webview_id, key_event), ShutdownState::NotShuttingDown) => {
self.messages_for_embedder
.push(EmbedderMsg::Keyboard(webview_id, key_event));
},
(msg, ShutdownState::NotShuttingDown) => {
self.messages_for_embedder
.push((top_level_browsing_context, msg));
(message, ShutdownState::NotShuttingDown) => {
self.messages_for_embedder.push(message);
},
}
}
}
pub fn get_events(&mut self) -> Drain<'_, (Option<TopLevelBrowsingContextId>, EmbedderMsg)> {
pub fn get_events(&mut self) -> Drain<'_, EmbedderMsg> {
self.messages_for_embedder.drain(..)
}
@ -971,8 +965,7 @@ impl Servo {
if self.compositor.borrow().shutdown_state != ShutdownState::FinishedShuttingDown {
self.compositor.borrow_mut().perform_updates();
} else {
self.messages_for_embedder
.push((None, EmbedderMsg::Shutdown));
self.messages_for_embedder.push(EmbedderMsg::Shutdown);
}
need_resize
}
@ -1038,14 +1031,14 @@ impl Servo {
fn create_embedder_channel(
event_loop_waker: Box<dyn EventLoopWaker>,
) -> (EmbedderProxy, EmbedderReceiver) {
) -> (EmbedderProxy, Receiver<EmbedderMsg>) {
let (sender, receiver) = unbounded();
(
EmbedderProxy {
sender,
event_loop_waker,
},
EmbedderReceiver { receiver },
receiver,
)
}

View file

@ -202,7 +202,7 @@ impl WebView {
pub fn notify_keyboard_event(&self, event: KeyboardEvent) {
self.0
.constellation_proxy
.send(ConstellationMsg::Keyboard(event))
.send(ConstellationMsg::Keyboard(self.id(), event))
}
pub fn notify_ime_event(&self, event: CompositionEvent) {

View file

@ -443,3 +443,5 @@ pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId = BrowsingContextId {
namespace_id: TEST_NAMESPACE,
index: TEST_BROWSING_CONTEXT_INDEX,
};
pub const TEST_WEBVIEW_ID: WebViewId = TopLevelBrowsingContextId(TEST_BROWSING_CONTEXT_ID);

View file

@ -12,6 +12,7 @@ name = "bluetooth_traits"
path = "lib.rs"
[dependencies]
base = { workspace = true }
embedder_traits = { workspace = true }
ipc-channel = { workspace = true }
regex = { workspace = true }

View file

@ -5,6 +5,7 @@
use std::collections::{HashMap, HashSet};
use std::slice::Iter;
use base::id::WebViewId;
use serde::{Deserialize, Serialize};
// A device name can never be longer than 29 bytes. An adv packet is at most
@ -114,21 +115,28 @@ impl BluetoothScanfilterSequence {
#[derive(Debug, Deserialize, Serialize)]
pub struct RequestDeviceoptions {
webview_id: WebViewId,
filters: BluetoothScanfilterSequence,
optional_services: ServiceUUIDSequence,
}
impl RequestDeviceoptions {
pub fn new(
webview_id: WebViewId,
filters: BluetoothScanfilterSequence,
services: ServiceUUIDSequence,
) -> RequestDeviceoptions {
RequestDeviceoptions {
webview_id,
filters,
optional_services: services,
}
}
pub fn webview_id(&self) -> WebViewId {
self.webview_id
}
pub fn get_filters(&self) -> &BluetoothScanfilterSequence {
&self.filters
}

View file

@ -35,7 +35,7 @@ pub enum ConstellationMsg {
/// Query the constellation to see if the current compositor output is stable
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
/// Inform the constellation of a key event.
Keyboard(KeyboardEvent),
Keyboard(WebViewId, KeyboardEvent),
/// Inform the constellation of a composition event (IME).
IMECompositionEvent(CompositionEvent),
/// Whether to allow script to navigate.
@ -73,7 +73,7 @@ pub enum ConstellationMsg {
/// Forward an event to the script task of the given pipeline.
ForwardEvent(PipelineId, CompositorEvent),
/// Requesting a change to the onscreen cursor.
SetCursor(Cursor),
SetCursor(WebViewId, Cursor),
/// Enable the sampling profiler, with a given sampling rate and max total sampling duration.
ToggleProfiler(Duration, Duration),
/// Request to exit from fullscreen mode

View file

@ -6,8 +6,8 @@ pub mod resources;
use std::fmt::{Debug, Error, Formatter};
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
use crossbeam_channel::{Receiver, Sender};
use base::id::{PipelineId, WebViewId};
use crossbeam_channel::Sender;
use http::{HeaderMap, Method, StatusCode};
use ipc_channel::ipc::IpcSender;
use keyboard_types::KeyboardEvent;
@ -77,14 +77,14 @@ impl Clone for Box<dyn EventLoopWaker> {
/// Sends messages to the embedder.
pub struct EmbedderProxy {
pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
pub sender: Sender<EmbedderMsg>,
pub event_loop_waker: Box<dyn EventLoopWaker>,
}
impl EmbedderProxy {
pub fn send(&self, msg: (Option<TopLevelBrowsingContextId>, EmbedderMsg)) {
pub fn send(&self, message: EmbedderMsg) {
// Send a message and kick the OS event loop awake.
if let Err(err) = self.sender.send(msg) {
if let Err(err) = self.sender.send(message) {
warn!("Failed to send response ({:?}).", err);
}
self.event_loop_waker.wake();
@ -100,22 +100,6 @@ impl Clone for EmbedderProxy {
}
}
/// The port that the embedder receives messages on.
pub struct EmbedderReceiver {
pub receiver: Receiver<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
}
impl EmbedderReceiver {
pub fn try_recv_embedder_msg(
&mut self,
) -> Option<(Option<TopLevelBrowsingContextId>, EmbedderMsg)> {
self.receiver.try_recv().ok()
}
pub fn recv_embedder_msg(&mut self) -> (Option<TopLevelBrowsingContextId>, EmbedderMsg) {
self.receiver.recv().unwrap()
}
}
#[derive(Deserialize, Serialize)]
pub enum ContextMenuResult {
Dismissed,
@ -167,86 +151,108 @@ pub enum PromptResult {
#[derive(Deserialize, Serialize)]
pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome.
Status(Option<String>),
Status(WebViewId, Option<String>),
/// Alerts the embedder that the current page has changed its title.
ChangePageTitle(Option<String>),
ChangePageTitle(WebViewId, Option<String>),
/// Move the window to a point
MoveTo(DeviceIntPoint),
MoveTo(WebViewId, DeviceIntPoint),
/// Resize the window to size
ResizeTo(DeviceIntSize),
ResizeTo(WebViewId, DeviceIntSize),
/// Show dialog to user
Prompt(PromptDefinition, PromptOrigin),
Prompt(WebViewId, PromptDefinition, PromptOrigin),
/// Show a context menu to the user
ShowContextMenu(IpcSender<ContextMenuResult>, Option<String>, Vec<String>),
ShowContextMenu(
WebViewId,
IpcSender<ContextMenuResult>,
Option<String>,
Vec<String>,
),
/// Whether or not to allow a pipeline to load a url.
AllowNavigationRequest(PipelineId, ServoUrl),
AllowNavigationRequest(WebViewId, PipelineId, ServoUrl),
/// Whether or not to allow script to open a new tab/browser
AllowOpeningWebView(IpcSender<Option<WebViewId>>),
AllowOpeningWebView(WebViewId, IpcSender<Option<WebViewId>>),
/// A webview was created.
WebViewOpened(TopLevelBrowsingContextId),
WebViewOpened(WebViewId),
/// A webview was destroyed.
WebViewClosed(TopLevelBrowsingContextId),
WebViewClosed(WebViewId),
/// A webview gained focus for keyboard events.
WebViewFocused(TopLevelBrowsingContextId),
WebViewFocused(WebViewId),
/// All webviews lost focus for keyboard events.
WebViewBlurred,
/// Wether or not to unload a document
AllowUnload(IpcSender<bool>),
AllowUnload(WebViewId, IpcSender<bool>),
/// Sends an unconsumed key event back to the embedder.
Keyboard(KeyboardEvent),
Keyboard(WebViewId, KeyboardEvent),
/// Inform embedder to clear the clipboard
ClearClipboardContents,
ClearClipboardContents(WebViewId),
/// Gets system clipboard contents
GetClipboardContents(IpcSender<String>),
GetClipboardContents(WebViewId, IpcSender<String>),
/// Sets system clipboard contents
SetClipboardContents(String),
SetClipboardContents(WebViewId, String),
/// Changes the cursor.
SetCursor(Cursor),
SetCursor(WebViewId, Cursor),
/// A favicon was detected
NewFavicon(ServoUrl),
NewFavicon(WebViewId, ServoUrl),
/// `<head>` tag finished parsing
HeadParsed,
HeadParsed(WebViewId),
/// The history state has changed.
HistoryChanged(Vec<ServoUrl>, usize),
HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
/// Enter or exit fullscreen
SetFullscreenState(bool),
SetFullscreenState(WebViewId, bool),
/// The load of a page has begun
LoadStart,
LoadStart(WebViewId),
/// The load of a page has completed
LoadComplete,
WebResourceRequested(WebResourceRequest, IpcSender<WebResourceResponseMsg>),
LoadComplete(WebViewId),
WebResourceRequested(
Option<WebViewId>,
WebResourceRequest,
IpcSender<WebResourceResponseMsg>,
),
/// A pipeline panicked. First string is the reason, second one is the backtrace.
Panic(String, Option<String>),
Panic(WebViewId, String, Option<String>),
/// Open dialog to select bluetooth device.
GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
GetSelectedBluetoothDevice(WebViewId, Vec<String>, IpcSender<Option<String>>),
/// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
SelectFiles(
WebViewId,
Vec<FilterPattern>,
bool,
IpcSender<Option<Vec<String>>>,
),
/// Open interface to request permission specified by prompt.
PromptPermission(PermissionPrompt, IpcSender<PermissionRequest>),
PromptPermission(WebViewId, PermissionPrompt, IpcSender<PermissionRequest>),
/// Request to present an IME to the user when an editable element is focused.
/// If the input is text, the second parameter defines the pre-existing string
/// text content and the zero-based index into the string locating the insertion point.
/// bool is true for multi-line and false otherwise.
ShowIME(InputMethodType, Option<(String, i32)>, bool, DeviceIntRect),
ShowIME(
WebViewId,
InputMethodType,
Option<(String, i32)>,
bool,
DeviceIntRect,
),
/// Request to hide the IME when the editable element is blurred.
HideIME,
HideIME(WebViewId),
/// Servo has shut down
Shutdown,
/// Report a complete sampled profile
ReportProfile(Vec<u8>),
/// Notifies the embedder about media session events
/// (i.e. when there is metadata for the active media session, playback state changes...).
MediaSessionEvent(MediaSessionEvent),
MediaSessionEvent(WebViewId, MediaSessionEvent),
/// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
OnDevtoolsStarted(Result<u16, ()>, String),
/// Ask the user to allow a devtools client to connect.
RequestDevtoolsConnection(IpcSender<bool>),
/// Notify the embedder that it needs to present a new frame.
ReadyToPresent(Vec<WebViewId>),
/// The given event was delivered to a pipeline in the given browser.
EventDelivered(CompositorEventVariant),
EventDelivered(WebViewId, CompositorEventVariant),
/// Request to play a haptic effect on a connected gamepad.
PlayGamepadHapticEffect(usize, GamepadHapticEffectType, IpcSender<bool>),
PlayGamepadHapticEffect(WebViewId, usize, GamepadHapticEffectType, IpcSender<bool>),
/// Request to stop a haptic effect on a connected gamepad.
StopGamepadHapticEffect(usize, IpcSender<bool>),
StopGamepadHapticEffect(WebViewId, usize, IpcSender<bool>),
}
/// The variant of CompositorEvent that was delivered to a pipeline.
@ -275,23 +281,23 @@ impl Debug for EmbedderMsg {
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
EmbedderMsg::ClearClipboardContents => write!(f, "ClearClipboardContents"),
EmbedderMsg::ClearClipboardContents(..) => write!(f, "ClearClipboardContents"),
EmbedderMsg::GetClipboardContents(..) => write!(f, "GetClipboardContents"),
EmbedderMsg::SetClipboardContents(..) => write!(f, "SetClipboardContents"),
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"),
EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"),
EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
EmbedderMsg::LoadStart => write!(f, "LoadStart"),
EmbedderMsg::LoadComplete => write!(f, "LoadComplete"),
EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"),
EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"),
EmbedderMsg::WebResourceRequested(..) => write!(f, "WebResourceRequested"),
EmbedderMsg::Panic(..) => write!(f, "Panic"),
EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"),
EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"),
EmbedderMsg::PromptPermission(..) => write!(f, "PromptPermission"),
EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"),
EmbedderMsg::HideIME => write!(f, "HideIME"),
EmbedderMsg::HideIME(..) => write!(f, "HideIME"),
EmbedderMsg::Shutdown => write!(f, "Shutdown"),
EmbedderMsg::AllowOpeningWebView(..) => write!(f, "AllowOpeningWebView"),
EmbedderMsg::WebViewOpened(..) => write!(f, "WebViewOpened"),
@ -301,6 +307,7 @@ impl Debug for EmbedderMsg {
EmbedderMsg::ReportProfile(..) => write!(f, "ReportProfile"),
EmbedderMsg::MediaSessionEvent(..) => write!(f, "MediaSessionEvent"),
EmbedderMsg::OnDevtoolsStarted(..) => write!(f, "OnDevtoolsStarted"),
EmbedderMsg::RequestDevtoolsConnection(..) => write!(f, "RequestDevtoolsConnection"),
EmbedderMsg::ShowContextMenu(..) => write!(f, "ShowContextMenu"),
EmbedderMsg::ReadyToPresent(..) => write!(f, "ReadyToPresent"),
EmbedderMsg::EventDelivered(..) => write!(f, "HitTestedEvent"),

View file

@ -7,6 +7,7 @@ use std::ops::Range;
use std::path::PathBuf;
use std::time::SystemTime;
use base::id::WebViewId;
use embedder_traits::FilterPattern;
use ipc_channel::ipc::IpcSender;
use malloc_size_of_derive::MallocSizeOf;
@ -136,6 +137,7 @@ pub struct SelectedFile {
pub enum FileManagerThreadMsg {
/// Select a single file. Last field is pre-selected file path for testing
SelectFile(
WebViewId,
Vec<FilterPattern>,
IpcSender<FileManagerResult<SelectedFile>>,
FileOrigin,
@ -144,6 +146,7 @@ pub enum FileManagerThreadMsg {
/// Select multiple files. Last field is pre-selected file paths for testing
SelectFiles(
WebViewId,
Vec<FilterPattern>,
IpcSender<FileManagerResult<Vec<SelectedFile>>>,
FileOrigin,

View file

@ -4,7 +4,7 @@
use std::sync::{Arc, Mutex};
use base::id::{PipelineId, TopLevelBrowsingContextId};
use base::id::{PipelineId, WebViewId};
use content_security_policy::{self as csp};
use http::header::{HeaderName, AUTHORIZATION};
use http::{HeaderMap, Method};
@ -266,7 +266,7 @@ pub struct RequestBuilder {
pub referrer: Referrer,
pub referrer_policy: ReferrerPolicy,
pub pipeline_id: Option<PipelineId>,
pub target_browsing_context_id: Option<TopLevelBrowsingContextId>,
pub target_webview_id: Option<WebViewId>,
pub redirect_mode: RedirectMode,
pub integrity_metadata: String,
// to keep track of redirects
@ -280,7 +280,7 @@ pub struct RequestBuilder {
}
impl RequestBuilder {
pub fn new(url: ServoUrl, referrer: Referrer) -> RequestBuilder {
pub fn new(webview_id: Option<WebViewId>, url: ServoUrl, referrer: Referrer) -> RequestBuilder {
RequestBuilder {
id: RequestId::default(),
method: Method::GET,
@ -301,7 +301,7 @@ impl RequestBuilder {
referrer,
referrer_policy: ReferrerPolicy::EmptyString,
pipeline_id: None,
target_browsing_context_id: None,
target_webview_id: webview_id,
redirect_mode: RedirectMode::Follow,
integrity_metadata: "".to_owned(),
url_list: vec![],
@ -383,14 +383,6 @@ impl RequestBuilder {
self
}
pub fn target_browsing_context_id(
mut self,
target_browsing_context_id: Option<TopLevelBrowsingContextId>,
) -> RequestBuilder {
self.target_browsing_context_id = target_browsing_context_id;
self
}
pub fn redirect_mode(mut self, redirect_mode: RedirectMode) -> RequestBuilder {
self.redirect_mode = redirect_mode;
self
@ -433,6 +425,7 @@ impl RequestBuilder {
Some(Origin::Origin(self.origin)),
self.referrer,
self.pipeline_id,
self.target_webview_id,
self.https_state,
);
request.initiator = self.initiator;
@ -461,7 +454,6 @@ impl RequestBuilder {
request.response_tainting = self.response_tainting;
request.crash = self.crash;
request.policy_container = self.policy_container;
request.target_browsing_context_id = self.target_browsing_context_id;
request
}
}
@ -488,7 +480,7 @@ pub struct Request {
pub body: Option<RequestBody>,
// TODO: client object
pub window: Window,
pub target_browsing_context_id: Option<TopLevelBrowsingContextId>,
pub target_webview_id: Option<WebViewId>,
/// <https://fetch.spec.whatwg.org/#request-keepalive-flag>
pub keep_alive: bool,
/// <https://fetch.spec.whatwg.org/#request-service-workers-mode>
@ -545,6 +537,7 @@ impl Request {
origin: Option<Origin>,
referrer: Referrer,
pipeline_id: Option<PipelineId>,
webview_id: Option<WebViewId>,
https_state: HttpsState,
) -> Request {
Request {
@ -563,7 +556,7 @@ impl Request {
referrer,
referrer_policy: ReferrerPolicy::EmptyString,
pipeline_id,
target_browsing_context_id: None,
target_webview_id: webview_id,
synchronous: false,
mode: RequestMode::NoCors,
use_cors_preflight: false,

View file

@ -23,7 +23,7 @@ use background_hang_monitor_api::BackgroundHangMonitorRegister;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{
BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId,
TopLevelBrowsingContextId,
TopLevelBrowsingContextId, WebViewId,
};
use base::Epoch;
use bitflags::bitflags;
@ -732,7 +732,11 @@ pub enum WebDriverCommandMsg {
/// the provided channels to return the top level browsing context id
/// associated with the new webview, and a notification when the initial
/// load is complete.
NewWebView(IpcSender<TopLevelBrowsingContextId>, IpcSender<LoadStatus>),
NewWebView(
WebViewId,
IpcSender<TopLevelBrowsingContextId>,
IpcSender<LoadStatus>,
),
/// Close the webview associated with the provided id.
CloseWebView(TopLevelBrowsingContextId),
/// Focus the webview associated with the provided id.

View file

@ -18,7 +18,7 @@ use std::sync::Arc;
use app_units::Au;
use atomic_refcell::AtomicRefCell;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{BrowsingContextId, PipelineId};
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use base::Epoch;
use canvas_traits::canvas::{CanvasId, CanvasMsg};
use euclid::default::{Point2D, Rect};
@ -33,7 +33,7 @@ use net_traits::image_cache::{ImageCache, PendingImageId};
use profile_traits::mem::Report;
use profile_traits::time;
use script_traits::{
ConstellationControlMsg, InitialScriptState, LayoutMsg, LoadData, Painter, ScrollState,
ConstellationControlMsg, InitialScriptState, LoadData, Painter, ScrollState,
UntrustedNodeAddress, WindowSizeData,
};
use serde::{Deserialize, Serialize};
@ -182,9 +182,9 @@ pub struct HTMLMediaData {
pub struct LayoutConfig {
pub id: PipelineId,
pub webview_id: WebViewId,
pub url: ServoUrl,
pub is_iframe: bool,
pub constellation_chan: IpcSender<LayoutMsg>,
pub script_chan: IpcSender<ConstellationControlMsg>,
pub image_cache: Arc<dyn ImageCache>,
pub font_context: Arc<FontContext>,

View file

@ -947,7 +947,12 @@ impl Handler {
) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap();
let cmd_msg = WebDriverCommandMsg::NewWebView(sender, self.load_status_sender.clone());
let session = self.session().unwrap();
let cmd_msg = WebDriverCommandMsg::NewWebView(
session.top_level_browsing_context_id,
sender,
self.load_status_sender.clone(),
);
self.constellation_chan
.send(ConstellationMsg::WebDriverCommand(cmd_msg))
.unwrap();

View file

@ -143,26 +143,27 @@ mod from_servo {
Self::WebResourceRequested(..) => target!("WebResourceRequested"),
Self::AllowUnload(..) => target!("AllowUnload"),
Self::Keyboard(..) => target!("Keyboard"),
Self::ClearClipboardContents => target!("ClearClipboardContents"),
Self::ClearClipboardContents(..) => target!("ClearClipboardContents"),
Self::GetClipboardContents(..) => target!("GetClipboardContents"),
Self::SetClipboardContents(..) => target!("SetClipboardContents"),
Self::SetCursor(..) => target!("SetCursor"),
Self::NewFavicon(..) => target!("NewFavicon"),
Self::HeadParsed => target!("HeadParsed"),
Self::HeadParsed(..) => target!("HeadParsed"),
Self::HistoryChanged(..) => target!("HistoryChanged"),
Self::SetFullscreenState(..) => target!("SetFullscreenState"),
Self::LoadStart => target!("LoadStart"),
Self::LoadComplete => target!("LoadComplete"),
Self::LoadStart(..) => target!("LoadStart"),
Self::LoadComplete(..) => target!("LoadComplete"),
Self::Panic(..) => target!("Panic"),
Self::GetSelectedBluetoothDevice(..) => target!("GetSelectedBluetoothDevice"),
Self::SelectFiles(..) => target!("SelectFiles"),
Self::PromptPermission(..) => target!("PromptPermission"),
Self::ShowIME(..) => target!("ShowIME"),
Self::HideIME => target!("HideIME"),
Self::HideIME(..) => target!("HideIME"),
Self::Shutdown => target!("Shutdown"),
Self::ReportProfile(..) => target!("ReportProfile"),
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
Self::OnDevtoolsStarted(..) => target!("OnDevtoolsStarted"),
Self::RequestDevtoolsConnection(..) => target!("RequestDevtoolsConnection"),
Self::ReadyToPresent(..) => target!("ReadyToPresent"),
Self::EventDelivered(..) => target!("EventDelivered"),
Self::PlayGamepadHapticEffect(..) => target!("PlayGamepadHapticEffect"),

View file

@ -404,8 +404,8 @@ impl WebViewManager {
.position(|webview| webview.0 == focused_id)
}
fn send_error(&self, webview_id: Option<WebViewId>, error: String) {
let Some(webview) = webview_id.and_then(|id| self.get(id)) else {
fn send_error(&self, webview_id: WebViewId, error: String) {
let Some(webview) = self.get(webview_id) else {
return warn!("{error}");
};
webview.servo_webview.send_error(error);
@ -417,55 +417,47 @@ impl WebViewManager {
servo: &mut Servo,
clipboard: &mut Option<Clipboard>,
opts: &Opts,
events: Vec<(Option<WebViewId>, EmbedderMsg)>,
messages: Vec<EmbedderMsg>,
) -> ServoEventResponse {
let mut need_present = self.load_status() != LoadStatus::LoadComplete;
let mut need_update = false;
for (webview_id, msg) in events {
if let Some(webview_id) = webview_id {
trace_embedder_msg!(msg, "{webview_id} {msg:?}");
} else {
trace_embedder_msg!(msg, "{msg:?}");
}
for message in messages {
trace_embedder_msg!(message, "{message:?}");
match msg {
EmbedderMsg::Status(status) => {
match message {
EmbedderMsg::Status(_, status) => {
self.status_text = status;
need_update = true;
},
EmbedderMsg::ChangePageTitle(title) => {
EmbedderMsg::ChangePageTitle(webview_id, title) => {
// Set the title to the target webview, and update the OS window title
// if this is the currently focused one.
if let Some(webview_id) = webview_id {
if let Some(webview) = self.get_mut(webview_id) {
webview.title = title.clone();
if webview.focused {
self.window.set_title(&format!(
"{} - Servo",
title.clone().unwrap_or_default()
));
}
need_update = true;
if let Some(webview) = self.get_mut(webview_id) {
webview.title = title.clone();
if webview.focused {
self.window.set_title(&format!(
"{} - Servo",
title.clone().unwrap_or_default()
));
}
need_update = true;
}
},
EmbedderMsg::MoveTo(point) => {
EmbedderMsg::MoveTo(_, point) => {
self.window.set_position(point);
},
EmbedderMsg::ResizeTo(inner_size) => {
if let Some(webview_id) = webview_id {
if let Some(webview) = self.get_mut(webview_id) {
if webview.rect.size() != inner_size.to_f32() {
webview.rect.set_size(inner_size.to_f32());
webview.servo_webview.move_resize(webview.rect);
}
};
if let Some(webview) = self.get(webview_id) {
self.window.request_resize(webview, inner_size);
EmbedderMsg::ResizeTo(webview_id, inner_size) => {
if let Some(webview) = self.get_mut(webview_id) {
if webview.rect.size() != inner_size.to_f32() {
webview.rect.set_size(inner_size.to_f32());
webview.servo_webview.move_resize(webview.rect);
}
};
if let Some(webview) = self.get(webview_id) {
self.window.request_resize(webview, inner_size);
}
},
EmbedderMsg::Prompt(definition, origin) => {
EmbedderMsg::Prompt(webview_id, definition, origin) => {
let res = if opts.headless {
match definition {
PromptDefinition::Alert(_message, sender) => sender.send(()),
@ -553,7 +545,7 @@ impl WebViewManager {
self.send_error(webview_id, format!("Failed to send Prompt response: {e}"))
}
},
EmbedderMsg::AllowUnload(sender) => {
EmbedderMsg::AllowUnload(webview_id, sender) => {
// Always allow unload for now.
if let Err(e) = sender.send(true) {
self.send_error(
@ -562,12 +554,10 @@ impl WebViewManager {
)
}
},
EmbedderMsg::AllowNavigationRequest(pipeline_id, _url) => {
if let Some(_webview_id) = webview_id {
servo.allow_navigation_response(pipeline_id, true);
}
EmbedderMsg::AllowNavigationRequest(_, pipeline_id, _url) => {
servo.allow_navigation_response(pipeline_id, true);
},
EmbedderMsg::AllowOpeningWebView(response_chan) => {
EmbedderMsg::AllowOpeningWebView(_, response_chan) => {
let webview = servo.new_auxiliary_webview();
match response_chan.send(Some(webview.id())) {
Ok(()) => self.add(webview),
@ -614,15 +604,15 @@ impl WebViewManager {
}
self.focused_webview_id = None;
},
EmbedderMsg::Keyboard(key_event) => {
EmbedderMsg::Keyboard(webview_id, key_event) => {
self.handle_overridable_key_bindings(webview_id, key_event);
},
EmbedderMsg::ClearClipboardContents => {
EmbedderMsg::ClearClipboardContents(_) => {
clipboard
.as_mut()
.and_then(|clipboard| clipboard.clear().ok());
},
EmbedderMsg::GetClipboardContents(sender) => {
EmbedderMsg::GetClipboardContents(_, sender) => {
let contents = clipboard
.as_mut()
.and_then(|clipboard| clipboard.get_text().ok())
@ -631,52 +621,52 @@ impl WebViewManager {
warn!("Failed to send clipboard ({})", e);
}
},
EmbedderMsg::SetClipboardContents(text) => {
EmbedderMsg::SetClipboardContents(_, text) => {
if let Some(clipboard) = clipboard.as_mut() {
if let Err(e) = clipboard.set_text(text) {
warn!("Error setting clipboard contents ({})", e);
}
}
},
EmbedderMsg::SetCursor(cursor) => {
EmbedderMsg::SetCursor(_, cursor) => {
self.window.set_cursor(cursor);
},
EmbedderMsg::NewFavicon(_url) => {
EmbedderMsg::NewFavicon(_, _url) => {
// FIXME: show favicons in the UI somehow
},
EmbedderMsg::HeadParsed => {
if let Some(webview) = webview_id.and_then(|id| self.get_mut(id)) {
EmbedderMsg::HeadParsed(webview_id) => {
if let Some(webview) = self.get_mut(webview_id) {
webview.load_status = LoadStatus::HeadParsed;
need_update = true;
};
},
EmbedderMsg::HistoryChanged(urls, current) => {
if let Some(webview) = webview_id.and_then(|id| self.get_mut(id)) {
EmbedderMsg::HistoryChanged(webview_id, urls, current) => {
if let Some(webview) = self.get_mut(webview_id) {
webview.url = Some(urls[current].clone());
need_update = true;
};
},
EmbedderMsg::SetFullscreenState(state) => {
EmbedderMsg::SetFullscreenState(_, state) => {
self.window.set_fullscreen(state);
},
EmbedderMsg::LoadStart => {
if let Some(webview) = webview_id.and_then(|id| self.get_mut(id)) {
EmbedderMsg::LoadStart(webview_id) => {
if let Some(webview) = self.get_mut(webview_id) {
webview.load_status = LoadStatus::LoadStart;
need_update = true;
};
},
EmbedderMsg::LoadComplete => {
if let Some(webview) = webview_id.and_then(|id| self.get_mut(id)) {
EmbedderMsg::LoadComplete(webview_id) => {
if let Some(webview) = self.get_mut(webview_id) {
webview.load_status = LoadStatus::LoadComplete;
need_update = true;
};
},
EmbedderMsg::WebResourceRequested(_web_resource_request, _response_sender) => {},
EmbedderMsg::WebResourceRequested(_, _web_resource_request, _response_sender) => {},
EmbedderMsg::Shutdown => {
self.shutdown_requested = true;
},
EmbedderMsg::Panic(_reason, _backtrace) => {},
EmbedderMsg::GetSelectedBluetoothDevice(devices, sender) => {
EmbedderMsg::Panic(_, _reason, _backtrace) => {},
EmbedderMsg::GetSelectedBluetoothDevice(webview_id, devices, sender) => {
let selected = platform_get_selected_devices(devices);
if let Err(e) = sender.send(selected) {
self.send_error(
@ -685,7 +675,7 @@ impl WebViewManager {
);
};
},
EmbedderMsg::SelectFiles(patterns, multiple_files, sender) => {
EmbedderMsg::SelectFiles(webview_id, patterns, multiple_files, sender) => {
let result = match (opts.headless, get_selected_files(patterns, multiple_files))
{
(true, _) | (false, None) => sender.send(None),
@ -698,16 +688,16 @@ impl WebViewManager {
);
};
},
EmbedderMsg::PromptPermission(prompt, sender) => {
EmbedderMsg::PromptPermission(_, prompt, sender) => {
let _ = sender.send(match opts.headless {
true => PermissionRequest::Denied,
false => prompt_user(prompt),
});
},
EmbedderMsg::ShowIME(_kind, _text, _multiline, _rect) => {
EmbedderMsg::ShowIME(_webview_id, _kind, _text, _multiline, _rect) => {
debug!("ShowIME received");
},
EmbedderMsg::HideIME => {
EmbedderMsg::HideIME(_webview_id) => {
debug!("HideIME received");
},
EmbedderMsg::ReportProfile(bytes) => {
@ -717,7 +707,7 @@ impl WebViewManager {
error!("Failed to store profile: {}", e);
}
},
EmbedderMsg::MediaSessionEvent(_) => {
EmbedderMsg::MediaSessionEvent(..) => {
debug!("MediaSessionEvent received");
// TODO(ferjm): MediaSession support for winit based browsers.
},
@ -725,28 +715,31 @@ impl WebViewManager {
Ok(p) => info!("Devtools Server running on port {}", p),
Err(()) => error!("Error running devtools server"),
},
EmbedderMsg::ShowContextMenu(sender, ..) => {
EmbedderMsg::RequestDevtoolsConnection(response_sender) => {
let _ = response_sender.send(true);
},
EmbedderMsg::ShowContextMenu(_, sender, ..) => {
let _ = sender.send(ContextMenuResult::Ignored);
},
EmbedderMsg::ReadyToPresent(_webview_ids) => {
need_present = true;
},
EmbedderMsg::EventDelivered(event) => {
if let Some(webview) = webview_id.and_then(|id| self.get_mut(id)) {
EmbedderMsg::EventDelivered(webview_id, event) => {
if let Some(webview) = self.get_mut(webview_id) {
if let CompositorEventVariant::MouseButtonEvent = event {
webview.servo_webview.raise_to_top(true);
webview.servo_webview.focus();
}
};
},
EmbedderMsg::PlayGamepadHapticEffect(index, effect, effect_complete_sender) => {
EmbedderMsg::PlayGamepadHapticEffect(_, index, effect, effect_complete_sender) => {
match effect {
GamepadHapticEffectType::DualRumble(params) => {
self.play_haptic_effect(index, params, effect_complete_sender);
},
}
},
EmbedderMsg::StopGamepadHapticEffect(index, haptic_stop_sender) => {
EmbedderMsg::StopGamepadHapticEffect(_, index, haptic_stop_sender) => {
let stopped_successfully = self.stop_haptic_effect(index);
haptic_stop_sender
.send(stopped_successfully)
@ -762,12 +755,8 @@ impl WebViewManager {
}
/// Handle servoshell key bindings that may have been prevented by the page in the focused webview.
fn handle_overridable_key_bindings(
&mut self,
webview_id: Option<WebViewId>,
event: KeyboardEvent,
) {
let Some(webview) = webview_id.and_then(|id| self.get(id)) else {
fn handle_overridable_key_bindings(&mut self, webview_id: WebViewId, event: KeyboardEvent) {
let Some(webview) = self.get(webview_id) else {
return;
};

View file

@ -455,23 +455,21 @@ impl ServoGlue {
fn handle_servo_events(&mut self) -> Result<(), &'static str> {
let mut need_update = false;
let events: Vec<_> = self.servo.get_events().collect();
for (browser_id, event) in events {
match event {
EmbedderMsg::ChangePageTitle(title) => {
let messages: Vec<_> = self.servo.get_events().collect();
for message in messages {
match message {
EmbedderMsg::ChangePageTitle(_, title) => {
self.callbacks.host_callbacks.on_title_changed(title);
},
EmbedderMsg::AllowNavigationRequest(pipeline_id, url) => {
if let Some(_browser_id) = browser_id {
let data: bool = self
.callbacks
.host_callbacks
.on_allow_navigation(url.to_string());
self.servo.allow_navigation_response(pipeline_id, data);
need_update = true;
}
EmbedderMsg::AllowNavigationRequest(_, pipeline_id, url) => {
let data: bool = self
.callbacks
.host_callbacks
.on_allow_navigation(url.to_string());
self.servo.allow_navigation_response(pipeline_id, data);
need_update = true;
},
EmbedderMsg::HistoryChanged(entries, current) => {
EmbedderMsg::HistoryChanged(_, entries, current) => {
let can_go_back = current > 0;
let can_go_forward = current < entries.len() - 1;
self.callbacks
@ -481,19 +479,19 @@ impl ServoGlue {
.host_callbacks
.on_url_changed(entries[current].clone().to_string());
},
EmbedderMsg::LoadStart => {
EmbedderMsg::LoadStart(_) => {
self.callbacks.host_callbacks.on_load_started();
},
EmbedderMsg::LoadComplete => {
EmbedderMsg::LoadComplete(_) => {
self.callbacks.host_callbacks.on_load_ended();
},
EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
EmbedderMsg::GetSelectedBluetoothDevice(_, _, sender) => {
let _ = sender.send(None);
},
EmbedderMsg::AllowUnload(sender) => {
EmbedderMsg::AllowUnload(_, sender) => {
let _ = sender.send(true);
},
EmbedderMsg::ShowContextMenu(sender, title, items) => {
EmbedderMsg::ShowContextMenu(_, sender, title, items) => {
if self.context_menu_sender.is_some() {
warn!(
"Trying to show a context menu when a context menu is already active"
@ -506,7 +504,7 @@ impl ServoGlue {
.show_context_menu(title, items);
}
},
EmbedderMsg::Prompt(definition, origin) => {
EmbedderMsg::Prompt(_, definition, origin) => {
let cb = &self.callbacks.host_callbacks;
let trusted = origin == PromptOrigin::Trusted;
let res = match definition {
@ -533,7 +531,7 @@ impl ServoGlue {
.send_error(format!("Failed to send Prompt response: {e}"));
}
},
EmbedderMsg::AllowOpeningWebView(response_chan) => {
EmbedderMsg::AllowOpeningWebView(_, response_chan) => {
let new_webview = self.servo.new_auxiliary_webview();
let new_webview_id = new_webview.id();
self.webviews.insert(new_webview_id, new_webview);
@ -568,17 +566,17 @@ impl ServoGlue {
EmbedderMsg::WebViewBlurred => {
self.focused_webview_id = None;
},
EmbedderMsg::GetClipboardContents(sender) => {
EmbedderMsg::GetClipboardContents(_, sender) => {
let contents = self.callbacks.host_callbacks.get_clipboard_contents();
let _ = sender.send(contents.unwrap_or("".to_owned()));
},
EmbedderMsg::SetClipboardContents(text) => {
EmbedderMsg::SetClipboardContents(_, text) => {
self.callbacks.host_callbacks.set_clipboard_contents(text);
},
EmbedderMsg::Shutdown => {
self.callbacks.host_callbacks.on_shutdown_complete();
},
EmbedderMsg::PromptPermission(prompt, sender) => {
EmbedderMsg::PromptPermission(_, prompt, sender) => {
let message = match prompt {
PermissionPrompt::Request(permission_name) => {
format!("Do you want to grant permission for {:?}?", permission_name)
@ -601,15 +599,15 @@ impl ServoGlue {
let _ = sender.send(result);
},
EmbedderMsg::ShowIME(kind, text, multiline, bounds) => {
EmbedderMsg::ShowIME(_, kind, text, multiline, bounds) => {
self.callbacks
.host_callbacks
.on_ime_show(kind, text, multiline, bounds);
},
EmbedderMsg::HideIME => {
EmbedderMsg::HideIME(_) => {
self.callbacks.host_callbacks.on_ime_hide();
},
EmbedderMsg::MediaSessionEvent(event) => {
EmbedderMsg::MediaSessionEvent(_, event) => {
match event {
MediaSessionEvent::SetMetadata(metadata) => {
self.callbacks.host_callbacks.on_media_session_metadata(
@ -637,30 +635,31 @@ impl ServoGlue {
.host_callbacks
.on_devtools_started(port, token);
},
EmbedderMsg::Panic(reason, backtrace) => {
EmbedderMsg::RequestDevtoolsConnection(result_sender) => {
result_sender.send(true);
},
EmbedderMsg::Panic(_, reason, backtrace) => {
self.callbacks.host_callbacks.on_panic(reason, backtrace);
},
EmbedderMsg::ReadyToPresent(_webview_ids) => {
self.need_present = true;
},
EmbedderMsg::Keyboard(..) => {
error!("Received unexpected keyboard event");
},
EmbedderMsg::ResizeTo(size) => {
error!("Received resize event (to {size:?}). Currently only the user can resize windows");
EmbedderMsg::ResizeTo(_, size) => {
warn!("Received resize event (to {size:?}). Currently only the user can resize windows");
},
EmbedderMsg::Keyboard(..) |
EmbedderMsg::Status(..) |
EmbedderMsg::SelectFiles(..) |
EmbedderMsg::MoveTo(..) |
EmbedderMsg::SetCursor(..) |
EmbedderMsg::NewFavicon(..) |
EmbedderMsg::HeadParsed |
EmbedderMsg::HeadParsed(..) |
EmbedderMsg::SetFullscreenState(..) |
EmbedderMsg::ReportProfile(..) |
EmbedderMsg::EventDelivered(..) |
EmbedderMsg::PlayGamepadHapticEffect(..) |
EmbedderMsg::StopGamepadHapticEffect(..) |
EmbedderMsg::ClearClipboardContents |
EmbedderMsg::ClearClipboardContents(..) |
EmbedderMsg::WebResourceRequested(..) => {},
}
}