diff options
author | Delan Azabani <dazabani@igalia.com> | 2025-01-30 19:15:35 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-30 11:15:35 +0000 |
commit | 5e9de2cb61fbfd82b27343bf03439838458b9848 (patch) | |
tree | 64574624cda94237bbfc443a29b792229fde0ee2 /components/script/dom | |
parent | 9eeb602f7afca502753bb8211ab646c952951761 (diff) | |
download | servo-5e9de2cb61fbfd82b27343bf03439838458b9848.tar.gz servo-5e9de2cb61fbfd82b27343bf03439838458b9848.zip |
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>
Diffstat (limited to 'components/script/dom')
25 files changed, 196 insertions, 129 deletions
diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 42b18974b5f..9141ee17450 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -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), ); diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 745b5dd9aeb..ba4ac308ad0 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -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 { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 689a848caed..f7bfc88de82 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -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 diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs index 1d68817ace5..b75289497b8 100644 --- a/components/script/dom/eventsource.rs +++ b/components/script/dom/eventsource.rs @@ -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), diff --git a/components/script/dom/gamepadhapticactuator.rs b/components/script/dom/gamepadhapticactuator.rs index d152f633c02..cd93f3421bc 100644 --- a/components/script/dom/gamepadhapticactuator.rs +++ b/components/script/dom/gamepadhapticactuator.rs @@ -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); } } diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 62d9fee32bd..2a510c25668 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -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, diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index d3e540f562f..228e1490200 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -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())); } } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 36fa7b9ee67..8e563c16e54 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -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. diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index e8844084c68..e5c3270f27e 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -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(); diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 50d5e274c85..299be2d2156 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -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, diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index c7fd9462b21..b859f06007c 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -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, diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 1aaa0119760..ab00b5356f6 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -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(), diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index e660e3e4d93..c18f245eb87 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -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, diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 974b50a3949..d21a317bd47 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -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 diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index 1d7c8e63698..bcdf42ac63e 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -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, diff --git a/components/script/dom/request.rs b/components/script/dom/request.rs index 6f672660db5..70fa7b212e5 100644 --- a/components/script/dom/request.rs +++ b/components/script/dom/request.rs @@ -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()) diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index aa9184a3dc9..07c44cd11f7 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -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) diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs index 5e394816f44..c67a90372dc 100644 --- a/components/script/dom/servoparser/prefetch.rs +++ b/components/script/dom/servoparser/prefetch.rs @@ -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)); diff --git a/components/script/dom/textcontrol.rs b/components/script/dom/textcontrol.rs index 184138ab3c0..09f0365fed2 100644 --- a/components/script/dom/textcontrol.rs +++ b/components/script/dom/textcontrol.rs @@ -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 } } diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index ab4303bf863..ad54f06d84d 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -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 }); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index e8487f24b95..73ce02a40ab 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -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, diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 5f113b5f068..f26180bfc66 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -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 = diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 7db2123e36e..94b709a4fa6 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -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, diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs index 752aa4e5e9e..527fc47f3ad 100644 --- a/components/script/dom/worklet.rs +++ b/components/script/dom/worklet.rs @@ -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(), ) diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index e0eca131d65..5e2bb5abc27 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -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(), ) |