Rewild Your Web
18
fork

Configure Feed

Select the types of activity you want to include in your feed.

apis: P2P message ports

Signed-off-by: webbeef <me@webbeef.org>

webbeef 2e5d858f c2b1d4ca

+694 -87
+232 -58
patches/components/constellation/constellation.rs.patch
··· 31 31 }; 32 32 use crate::constellation_webview::ConstellationWebView; 33 33 use crate::event_loop::EventLoop; 34 - +use crate::pairing; 34 + +use crate::pairing::{P2pMessage, PairingService}; 35 35 use crate::pipeline::Pipeline; 36 36 use crate::process_manager::ProcessManager; 37 37 use crate::serviceworker::ServiceWorkerUnprivilegedContent; 38 - @@ -510,6 +512,22 @@ 38 + @@ -211,6 +213,9 @@ 39 + /// While a completion failed, another global requested to complete the transfer. 40 + /// We are still buffering messages, and awaiting the return of the buffer from the global who failed. 41 + CompletionRequested(MessagePortRouterId, VecDeque<PortMessageTask>), 42 + + /// The port is managed by a remote P2P peer. 43 + + /// Messages routed to this port are serialized and sent over the P2P link. 44 + + Remote(String), 45 + } 46 + 47 + #[derive(Debug)] 48 + @@ -510,6 +515,22 @@ 39 49 40 50 /// Whether accessibility trees are being built and sent to the underlying platform. 41 51 pub(crate) accessibility_active: bool, ··· 54 64 + embedder_error_listeners: FxHashSet<ScriptEventLoopId>, 55 65 + 56 66 + /// The P2P pairing service. 57 - + pairing: pairing::PairingService, 67 + + pairing: PairingService, 58 68 } 59 69 60 70 /// State needed to construct a constellation. 61 - @@ -729,6 +747,10 @@ 71 + @@ -729,6 +750,10 @@ 62 72 screenshot_readiness_requests: Vec::new(), 63 73 user_contents_for_manager_id: Default::default(), 64 74 accessibility_active: false, 65 75 + embedded_webview_to_iframe: FxHashMap::default(), 66 76 + active_ime_webview: None, 67 77 + embedder_error_listeners: Default::default(), 68 - + pairing: pairing::PairingService::new(), 78 + + pairing: PairingService::new(), 69 79 }; 70 80 71 81 constellation.run(); 72 - @@ -754,6 +776,18 @@ 82 + @@ -754,6 +779,18 @@ 73 83 fn clean_up_finished_script_event_loops(&mut self) { 74 84 self.event_loop_join_handles 75 85 .retain(|join_handle| !join_handle.is_finished()); ··· 88 98 self.event_loops 89 99 .retain(|event_loop| event_loop.upgrade().is_some()); 90 100 } 91 - @@ -1045,6 +1079,11 @@ 101 + @@ -1045,6 +1082,11 @@ 92 102 .get(&webview_id) 93 103 .and_then(|webview| webview.user_content_manager_id); 94 104 ··· 100 110 let new_pipeline_info = NewPipelineInfo { 101 111 parent_info: parent_pipeline_id, 102 112 new_pipeline_id, 103 - @@ -1055,6 +1094,13 @@ 113 + @@ -1055,6 +1097,13 @@ 104 114 viewport_details: initial_viewport_details, 105 115 user_content_manager_id, 106 116 theme, ··· 114 124 }; 115 125 let pipeline = match Pipeline::spawn(new_pipeline_info, event_loop, self, throttled) { 116 126 Ok(pipeline) => pipeline, 117 - @@ -1229,6 +1275,7 @@ 127 + @@ -1229,6 +1278,7 @@ 118 128 BackgroundHangMonitor(HangMonitorAlert), 119 129 Embedder(EmbedderToConstellationMessage), 120 130 FromSWManager(SWManagerMsg), ··· 122 132 RemoveProcess(usize), 123 133 } 124 134 // Get one incoming request. 125 - @@ -1249,6 +1296,15 @@ 135 + @@ -1249,6 +1299,15 @@ 126 136 sel.recv(&self.embedder_to_constellation_receiver); 127 137 sel.recv(&self.swmanager_receiver); 128 138 ··· 138 148 self.process_manager.register(&mut sel); 139 149 140 150 let request = { 141 - @@ -1277,9 +1333,13 @@ 151 + @@ -1277,9 +1336,13 @@ 142 152 .recv(&self.swmanager_receiver) 143 153 .expect("Unexpected SW channel panic in constellation") 144 154 .map(Request::FromSWManager), ··· 153 163 let _ = oper.recv(self.process_manager.receiver_at(process_index)); 154 164 Ok(Request::RemoveProcess(process_index)) 155 165 }, 156 - @@ -1305,6 +1365,9 @@ 166 + @@ -1305,6 +1368,9 @@ 157 167 Request::FromSWManager(message) => { 158 168 self.handle_request_from_swmanager(message); 159 169 }, ··· 163 173 Request::RemoveProcess(index) => self.process_manager.remove(index), 164 174 } 165 175 } 166 - @@ -1534,11 +1597,7 @@ 176 + @@ -1534,11 +1600,7 @@ 167 177 } 168 178 }, 169 179 EmbedderToConstellationMessage::PreferencesUpdated(updates) => { ··· 176 186 let _ = event_loop.send(ScriptThreadMessage::PreferencesUpdated( 177 187 updates 178 188 .iter() 179 - @@ -1565,6 +1624,18 @@ 189 + @@ -1565,6 +1627,18 @@ 180 190 EmbedderToConstellationMessage::SetAccessibilityActive(active) => { 181 191 self.set_accessibility_active(active); 182 192 }, ··· 195 205 } 196 206 } 197 207 198 - @@ -1762,7 +1833,13 @@ 208 + @@ -1762,7 +1836,13 @@ 199 209 return warn!("Attempt to add channel name from an unexpected origin."); 200 210 } 201 211 self.broadcast_channels ··· 210 220 }, 211 221 ScriptToConstellationMessage::RemoveBroadcastChannelNameInRouter( 212 222 router_id, 213 - @@ -1776,7 +1853,13 @@ 223 + @@ -1776,7 +1856,13 @@ 214 224 return warn!("Attempt to remove channel name from an unexpected origin."); 215 225 } 216 226 self.broadcast_channels ··· 225 235 }, 226 236 ScriptToConstellationMessage::RemoveBroadcastChannelRouter(router_id, origin) => { 227 237 if self 228 - @@ -1788,6 +1871,12 @@ 238 + @@ -1788,6 +1874,12 @@ 229 239 self.broadcast_channels 230 240 .remove_broadcast_channel_router(router_id); 231 241 }, ··· 238 248 ScriptToConstellationMessage::ScheduleBroadcast(router_id, message) => { 239 249 if self 240 250 .check_origin_against_pipeline(&source_pipeline_id, &message.origin) 241 - @@ -1797,8 +1886,15 @@ 251 + @@ -1797,8 +1889,15 @@ 242 252 "Attempt to schedule broadcast from an origin not matching the origin of the msg." 243 253 ); 244 254 } ··· 255 265 }, 256 266 ScriptToConstellationMessage::PipelineExited => { 257 267 self.handle_pipeline_exited(source_pipeline_id); 258 - @@ -1818,6 +1914,12 @@ 268 + @@ -1818,6 +1917,12 @@ 259 269 ScriptToConstellationMessage::CreateAuxiliaryWebView(load_info) => { 260 270 self.handle_script_new_auxiliary(load_info); 261 271 }, ··· 268 278 ScriptToConstellationMessage::ChangeRunningAnimationsState(animation_state) => { 269 279 self.handle_change_running_animations_state(source_pipeline_id, animation_state) 270 280 }, 271 - @@ -1984,6 +2086,29 @@ 281 + @@ -1984,6 +2089,29 @@ 272 282 new_value, 273 283 ); 274 284 }, ··· 298 308 ScriptToConstellationMessage::MediaSessionEvent(pipeline_id, event) => { 299 309 // Unlikely at this point, but we may receive events coming from 300 310 // different media sessions, so we set the active media session based 301 - @@ -2057,9 +2182,199 @@ 311 + @@ -2057,7 +2185,333 @@ 302 312 let _ = event_loop.send(ScriptThreadMessage::TriggerGarbageCollection); 303 313 } 304 314 }, ··· 449 459 + ScriptToConstellationMessage::PairingRejectPairing(id, callback) => { 450 460 + self.pairing.reject_pairing(&id, callback); 451 461 + }, 452 - } 453 - } 454 - 455 - + fn handle_pairing_event(&self, event: constellation_traits::PairingEvent) { 456 - + // Handle incoming P2P messages. 457 - + if let constellation_traits::PairingEvent::MessageReceived { ref from, ref data } = event { 458 - + if let Some((_from, message)) = self.pairing.handle_incoming_message(from, data) { 459 - + // Dispatch BroadcastChannelMessage locally. 460 - + if let pairing::P2pMessage::BroadcastChannelMessage { 461 - + ref origin, 462 - + ref name, 463 - + data: ref serialized, 464 - + } = message 465 - + { 466 - + info!("Remote broadcast from {from}: {origin} / {name}"); 467 - + let Some(origin) = servo_url::ServoUrl::parse(origin).ok().map(|u| u.origin()) 468 - + else { 469 - + warn!("Failed to parse origin: {origin}"); 462 + + ScriptToConstellationMessage::CreatePeerStream( 463 + + peer_id, 464 + + local_port_id, 465 + + remote_port_id, 466 + + callback, 467 + + ) => { 468 + + // Register the virtual remote port that only exists in the constellation, 469 + + // not in any GlobalScope. 470 + + self.message_ports.insert( 471 + + remote_port_id, 472 + + MessagePortInfo { 473 + + state: TransferState::Remote(peer_id.clone()), 474 + + entangled_with: Some(local_port_id), 475 + + }, 476 + + ); 477 + + 478 + + // Entangle the local port with the remote port in the constellation. 479 + + if let Some(info) = self.message_ports.get_mut(&local_port_id) { 480 + + info.entangled_with = Some(remote_port_id); 481 + + } 482 + + // Serialize port ID for the wire. 483 + + let port_id_bytes = match postcard::to_allocvec(&remote_port_id) { 484 + + Ok(bytes) => bytes, 485 + + Err(err) => { 486 + + let _ = callback.send(Err(format!("Failed to serialize port ID: {err}"))); 470 487 + return; 471 - + }; 472 - + let msg = constellation_traits::BroadcastChannelMsg { 473 - + origin, 474 - + channel_name: name.clone(), 475 - + data: constellation_traits::StructuredSerializedData { 476 - + serialized: serialized.clone(), 477 - + ..Default::default() 488 + + }, 489 + + }; 490 + + // Send port offer to the remote peer. 491 + + let stream_id = format!("ps-{}", rand::random::<u64>()); 492 + + self.pairing.send_message( 493 + + &peer_id, 494 + + &P2pMessage::PortOffer { 495 + + stream_id, 496 + + port_id: port_id_bytes, 497 + + from_peer: peer_id.clone(), 498 + + }, 499 + + ); 500 + + // TODO: wait for PortOfferAccepted before resolving. 501 + + // For now, resolve immediately. 502 + + let _ = callback.send(Ok(())); 503 + + }, 504 + + ScriptToConstellationMessage::PeerStreamResponse(stream_id, from_peer, accepted) => { 505 + + if accepted { 506 + + // Send PortOfferAccepted to the offering peer. 507 + + // For now, we don't have a stream_id → port mapping, so just send 508 + + // the acceptance with the stream_id. The offering side uses stream_id 509 + + // to correlate. 510 + + self.pairing.send_message( 511 + + &from_peer, 512 + + &P2pMessage::PortOfferAccepted { 513 + + stream_id, 514 + + port_id: vec![], 478 515 + }, 479 - + }; 480 - + self.broadcast_channels.broadcast_to_all(&msg); 516 + + ); 517 + + } else { 518 + + // Denied: send PortOfferDenied and clean up the Remote proxy. 519 + + self.pairing 520 + + .send_message(&from_peer, &P2pMessage::PortOfferDenied { stream_id }); 521 + + } 522 + + }, 523 + + } 524 + + } 525 + + 526 + + fn handle_pairing_event(&mut self, event: constellation_traits::PairingEvent) { 527 + + if let constellation_traits::PairingEvent::MessageReceived { ref from, ref data } = event { 528 + + if let Some((from, message)) = self.pairing.handle_incoming_message(from, data) { 529 + + match message { 530 + + P2pMessage::BroadcastChannelMessage { 531 + + ref origin, 532 + + ref name, 533 + + data: ref serialized, 534 + + } => { 535 + + let Some(origin) = 536 + + servo_url::ServoUrl::parse(origin).ok().map(|u| u.origin()) 537 + + else { 538 + + warn!("Failed to parse origin: {origin}"); 539 + + return; 540 + + }; 541 + + let msg = constellation_traits::BroadcastChannelMsg { 542 + + origin, 543 + + channel_name: name.clone(), 544 + + data: constellation_traits::StructuredSerializedData { 545 + + serialized: serialized.clone(), 546 + + ..Default::default() 547 + + }, 548 + + }; 549 + + self.broadcast_channels.broadcast_to_all(&msg); 550 + + }, 551 + + P2pMessage::PortOffer { 552 + + ref stream_id, 553 + + ref port_id, 554 + + .. 555 + + } => { 556 + + let Ok(remote_port_id) = 557 + + postcard::from_bytes::<base::id::MessagePortId>(port_id) 558 + + else { 559 + + warn!("Failed to deserialize port_id in PortOffer"); 560 + + return; 561 + + }; 562 + + // Register the remote port in the constellation. Messages sent 563 + + // TO this port ID will be forwarded over P2P back to the offering peer. 564 + + self.message_ports.insert( 565 + + remote_port_id, 566 + + MessagePortInfo { 567 + + state: TransferState::Remote(from.clone()), 568 + + entangled_with: None, 569 + + }, 570 + + ); 571 + + // Notify script threads to create a MessagePort and fire peerstream event. 572 + + // The script thread will report back via PeerStreamResponse whether 573 + + // the event was accepted or denied. 574 + + let remote_port_id_bytes = port_id.clone(); 575 + + for event_loop in self.event_loops() { 576 + + let _ = event_loop.send(ScriptThreadMessage::DispatchPeerStream( 577 + + from.clone(), 578 + + remote_port_id_bytes.clone(), 579 + + stream_id.clone(), 580 + + from.clone(), 581 + + )); 582 + + } 583 + + }, 584 + + P2pMessage::PortOfferAccepted { .. } => { 585 + + // The createPeerStream promise is resolved immediately with the 586 + + // local port, so there's nothing to do here. Messages sent before 587 + + // the remote side accepts are buffered by the P2P layer. 588 + + }, 589 + + P2pMessage::PortOfferDenied { ref stream_id } => { 590 + + warn!("Peer stream offer denied: {stream_id}"); 591 + + // TODO: close/disentangle the local port and clean up the Remote entry 592 + + }, 593 + + P2pMessage::PortMessage { 594 + + ref port_id, 595 + + ref task_data, 596 + + } => { 597 + + let Ok(remote_port_id) = 598 + + postcard::from_bytes::<base::id::MessagePortId>(port_id) 599 + + else { 600 + + warn!("Failed to deserialize port_id in PortMessage"); 601 + + return; 602 + + }; 603 + + let target_port_id = self 604 + + .message_ports 605 + + .get(&remote_port_id) 606 + + .and_then(|info| info.entangled_with) 607 + + .unwrap_or(remote_port_id); 608 + + match postcard::from_bytes::<constellation_traits::PortMessageTask>( 609 + + task_data, 610 + + ) { 611 + + Ok(task) => { 612 + + self.handle_reroute_messageport(target_port_id, task); 613 + + }, 614 + + Err(err) => { 615 + + warn!("Failed to deserialize remote PortMessageTask: {err}"); 616 + + }, 617 + + } 618 + + }, 619 + + P2pMessage::PortClose { ref port_id } => { 620 + + if let Ok(port_id) = 621 + + postcard::from_bytes::<base::id::MessagePortId>(port_id) 622 + + { 623 + + self.message_ports.remove(&port_id); 624 + + } 625 + + }, 626 + + _ => {}, 481 627 + } 482 628 + } 483 629 + return; ··· 486 632 + // Handle peer disconnect: clean up remote channel state. 487 633 + if let constellation_traits::PairingEvent::PeerExpired { ref id } = event { 488 634 + self.pairing.clear_remote_peer(id); 489 - + } 635 + } 490 636 + 491 637 + for event_loop in self.event_loops() { 492 638 + if self.embedder_error_listeners.contains(&event_loop.id()) { 493 639 + let _ = event_loop.send(ScriptThreadMessage::DispatchPairingEvent(event.clone())); 494 640 + } 495 641 + } 496 - + } 497 - + 642 + } 643 + 498 644 /// Check the origin of a message against that of the pipeline it came from. 499 - /// Note: this is still limited as a security check, 500 - /// see <https://github.com/servo/servo/issues/11722> 501 - @@ -3246,6 +3561,13 @@ 645 + @@ -2376,6 +2830,29 @@ 646 + TransferState::TransferInProgress(queue) => queue.push_back(task), 647 + TransferState::CompletionFailed(queue) => queue.push_back(task), 648 + TransferState::CompletionRequested(_, queue) => queue.push_back(task), 649 + + TransferState::Remote(peer_id) => { 650 + + // Serialize and send over P2P. 651 + + let port_id_bytes = match postcard::to_allocvec(&port_id) { 652 + + Ok(bytes) => bytes, 653 + + Err(err) => { 654 + + return warn!("Failed to serialize port_id for remote: {err}"); 655 + + }, 656 + + }; 657 + + match postcard::to_allocvec(&task) { 658 + + Ok(task_data) => { 659 + + self.pairing.send_message( 660 + + peer_id, 661 + + &P2pMessage::PortMessage { 662 + + port_id: port_id_bytes, 663 + + task_data, 664 + + }, 665 + + ); 666 + + }, 667 + + Err(err) => { 668 + + warn!("Failed to serialize PortMessageTask for remote port: {err}"); 669 + + }, 670 + + } 671 + + }, 672 + } 673 + } 674 + 675 + @@ -3246,6 +3723,13 @@ 502 676 /// <https://html.spec.whatwg.org/multipage/#destroy-a-top-level-traversable> 503 677 fn handle_close_top_level_browsing_context(&mut self, webview_id: WebViewId) { 504 678 debug!("{webview_id}: Closing"); ··· 512 686 let browsing_context_id = BrowsingContextId::from(webview_id); 513 687 // Step 5. Remove traversable from the user agent's top-level traversable set. 514 688 let browsing_context = 515 - @@ -3522,8 +3844,27 @@ 689 + @@ -3522,8 +4006,27 @@ 516 690 opener_webview_id, 517 691 opener_pipeline_id, 518 692 response_sender, ··· 540 714 let Some((webview_id_sender, webview_id_receiver)) = generic_channel::channel() else { 541 715 warn!("Failed to create channel"); 542 716 let _ = response_sender.send(None); 543 - @@ -3622,6 +3963,361 @@ 717 + @@ -3622,6 +4125,361 @@ 544 718 }); 545 719 } 546 720 ··· 902 1076 #[servo_tracing::instrument(skip_all)] 903 1077 fn handle_refresh_cursor(&self, pipeline_id: PipelineId) { 904 1078 let Some(pipeline) = self.pipelines.get(&pipeline_id) else { 905 - @@ -4747,7 +5443,7 @@ 1079 + @@ -4747,7 +5605,7 @@ 906 1080 } 907 1081 908 1082 #[servo_tracing::instrument(skip_all)] ··· 911 1085 // Send a flat projection of the history to embedder. 912 1086 // The final vector is a concatenation of the URLs of the past 913 1087 // entries, the current entry and the future entries. 914 - @@ -4850,9 +5546,23 @@ 1088 + @@ -4850,9 +5708,23 @@ 915 1089 ); 916 1090 self.embedder_proxy.send(EmbedderMsg::HistoryChanged( 917 1091 webview_id,
+37 -1
patches/components/constellation/pairing.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -0,0 +1,662 @@ 3 + @@ -0,0 +1,698 @@ 4 4 +// SPDX-License-Identifier: AGPL-3.0-or-later 5 5 + 6 6 +//! P2P pairing service integration with the constellation. ··· 36 36 + name: String, 37 37 + data: Vec<u8>, 38 38 + }, 39 + + /// Offer a MessagePort to a remote peer. 40 + + PortOffer { 41 + + /// Unique ID for this offer (used to correlate with PortOfferAccepted). 42 + + stream_id: String, 43 + + /// The serialized MessagePortId of the port on the offering side. 44 + + port_id: Vec<u8>, 45 + + /// The peer that is offering the port. 46 + + from_peer: String, 47 + + }, 48 + + /// Accept a port offer — the remote side created its port. 49 + + PortOfferAccepted { 50 + + stream_id: String, 51 + + /// The serialized MessagePortId of the newly created port on the accepting side. 52 + + port_id: Vec<u8>, 53 + + }, 54 + + /// Forward a MessagePort task (message) to a remote port. 55 + + PortMessage { 56 + + /// The serialized MessagePortId on the receiving side. 57 + + port_id: Vec<u8>, 58 + + task_data: Vec<u8>, 59 + + }, 60 + + /// Close/disentangle a remote port. 61 + + PortClose { 62 + + /// The serialized MessagePortId on the receiving side. 63 + + port_id: Vec<u8>, 64 + + }, 65 + + /// Deny a port offer — the remote side refused the stream. 66 + + PortOfferDenied { stream_id: String }, 39 67 +} 40 68 + 41 69 +impl P2pMessage { ··· 528 556 + }, 529 557 + P2pMessage::BroadcastChannelMessage { .. } => { 530 558 + // Return to constellation for local dispatch. 559 + + Some((from.to_owned(), message)) 560 + + }, 561 + + P2pMessage::PortOffer { .. } | 562 + + P2pMessage::PortOfferAccepted { .. } | 563 + + P2pMessage::PortMessage { .. } | 564 + + P2pMessage::PortClose { .. } | 565 + + P2pMessage::PortOfferDenied { .. } => { 566 + + // Return to constellation for port routing. 531 567 + Some((from.to_owned(), message)) 532 568 + }, 533 569 + }
+3 -1
patches/components/constellation/tracing.rs.patch
··· 36 36 Self::ActivateDocument => target!("ActivateDocument"), 37 37 Self::SetDocumentState(..) => target!("SetDocumentState"), 38 38 Self::SetFinalUrl(..) => target!("SetFinalUrl"), 39 - @@ -186,6 +194,43 @@ 39 + @@ -186,6 +194,45 @@ 40 40 target!("RespondToScreenshotReadinessRequest") 41 41 }, 42 42 Self::TriggerGarbageCollection => target!("TriggerGarbageCollection"), ··· 77 77 + Self::PairingRequestPairing(..) => target!("PairingRequestPairing"), 78 78 + Self::PairingAcceptPairing(..) => target!("PairingAcceptPairing"), 79 79 + Self::PairingRejectPairing(..) => target!("PairingRejectPairing"), 80 + + Self::CreatePeerStream(..) => target!("CreatePeerStream"), 81 + + Self::PeerStreamResponse(..) => target!("PeerStreamResponse"), 80 82 } 81 83 } 82 84 }
+27 -1
patches/components/script/dom/globalscope.rs.patch
··· 35 35 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")), 36 36 byte_length_queuing_strategy_size_function: OnceCell::new(), 37 37 count_queuing_strategy_size_function: OnceCell::new(), 38 - @@ -3128,6 +3142,16 @@ 38 + @@ -1139,6 +1153,25 @@ 39 + .send(ScriptToConstellationMessage::EntanglePorts(port1, port2)); 40 + } 41 + 42 + + /// Set a single port's entanglement without requiring the other port to be locally managed. 43 + + /// Used for cross-device ports where the remote port only exists in the constellation. 44 + + pub(crate) fn set_port_entanglement( 45 + + &self, 46 + + port_id: MessagePortId, 47 + + entangled_with: MessagePortId, 48 + + ) { 49 + + if let MessagePortState::Managed(_id, message_ports) = 50 + + &mut *self.message_port_state.borrow_mut() 51 + + { 52 + + if let Some(managed_port) = message_ports.get_mut(&port_id) { 53 + + managed_port.dom_port.entangle(entangled_with); 54 + + if let Some(port_impl) = managed_port.port_impl.as_mut() { 55 + + port_impl.entangle(entangled_with); 56 + + } 57 + + } 58 + + } 59 + + } 60 + + 61 + /// Handle the transfer of a port in the current task. 62 + pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl { 63 + if let MessagePortState::Managed(_id, message_ports) = 64 + @@ -3128,6 +3161,16 @@ 39 65 self.inherited_secure_context 40 66 } 41 67
+2 -1
patches/components/script/dom/mod.rs.patch
··· 16 16 pub(crate) mod keyboardevent; 17 17 pub(crate) mod location; 18 18 pub(crate) mod media; 19 - @@ -350,6 +352,9 @@ 19 + @@ -350,6 +352,10 @@ 20 20 pub(crate) mod pagetransitionevent; 21 21 pub(crate) mod paintsize; 22 22 pub(crate) mod paintworkletglobalscope; 23 23 +pub(crate) mod pairing; 24 24 +pub(crate) mod pairingpeerevent; 25 25 +pub(crate) mod peer; 26 + +pub(crate) mod peerstreamevent; 26 27 pub(crate) mod performance; 27 28 pub(crate) use self::performance::*; 28 29 pub(crate) mod permissions;
+89 -8
patches/components/script/dom/navigator.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -2,6 +2,7 @@ 3 + @@ -2,9 +2,11 @@ 4 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 6 ··· 8 8 use std::cell::Cell; 9 9 use std::convert::TryInto; 10 10 use std::ops::Deref; 11 - @@ -23,6 +24,7 @@ 11 + +use std::rc::Rc; 12 + use std::sync::LazyLock; 13 + 14 + use base::generic_channel; 15 + @@ -23,6 +25,7 @@ 12 16 use servo_url::ServoUrl; 13 17 14 18 use crate::body::Extractable; ··· 16 20 use crate::dom::bindings::cell::DomRefCell; 17 21 use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; 18 22 use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; 19 - @@ -38,6 +40,7 @@ 23 + @@ -38,6 +41,7 @@ 20 24 use crate::dom::clipboard::Clipboard; 21 25 use crate::dom::credentialmanagement::credentialscontainer::CredentialsContainer; 22 26 use crate::dom::csp::{GlobalCspReporting, Violation}; ··· 24 28 #[cfg(feature = "gamepad")] 25 29 use crate::dom::gamepad::Gamepad; 26 30 #[cfg(feature = "gamepad")] 27 - @@ -44,6 +47,7 @@ 31 + @@ -44,6 +48,7 @@ 28 32 use crate::dom::gamepad::gamepadevent::GamepadEventType; 29 33 use crate::dom::geolocation::Geolocation; 30 34 use crate::dom::globalscope::GlobalScope; ··· 32 36 use crate::dom::mediadevices::MediaDevices; 33 37 use crate::dom::mediasession::MediaSession; 34 38 use crate::dom::mimetypearray::MimeTypeArray; 35 - @@ -130,6 +134,8 @@ 39 + @@ -51,6 +56,7 @@ 40 + use crate::dom::performance::performanceresourcetiming::InitiatorType; 41 + use crate::dom::permissions::Permissions; 42 + use crate::dom::pluginarray::PluginArray; 43 + +use crate::dom::promise::Promise; 44 + use crate::dom::serviceworkercontainer::ServiceWorkerContainer; 45 + use crate::dom::servointernals::ServoInternals; 46 + use crate::dom::types::UserActivation; 47 + @@ -61,6 +67,7 @@ 48 + use crate::dom::xrsystem::XRSystem; 49 + use crate::fetch::RequestWithGlobalScope; 50 + use crate::network_listener::{FetchResponseListener, ResourceTimingListener, submit_timing}; 51 + +use crate::realms::InRealm; 52 + use crate::script_runtime::{CanGc, JSContext}; 53 + 54 + pub(super) fn hardware_concurrency() -> u64 { 55 + @@ -130,6 +137,8 @@ 36 56 has_gamepad_gesture: Cell<bool>, 37 57 servo_internals: MutNullableDom<ServoInternals>, 38 58 user_activation: MutNullableDom<UserActivation>, ··· 41 61 } 42 62 43 63 impl Navigator { 44 - @@ -156,6 +162,8 @@ 64 + @@ -156,6 +165,8 @@ 45 65 has_gamepad_gesture: Cell::new(false), 46 66 servo_internals: Default::default(), 47 67 user_activation: Default::default(), ··· 50 70 } 51 71 } 52 72 53 - @@ -168,6 +176,11 @@ 73 + @@ -168,6 +179,11 @@ 54 74 self.xr.get() 55 75 } 56 76 ··· 62 82 #[cfg(feature = "gamepad")] 63 83 pub(crate) fn get_gamepad(&self, index: usize) -> Option<DomRoot<Gamepad>> { 64 84 self.gamepads.borrow().get(index).and_then(|g| g.get()) 65 - @@ -559,6 +572,18 @@ 85 + @@ -559,6 +575,18 @@ 66 86 .or_init(|| ServoInternals::new(&self.global(), CanGc::note())) 67 87 } 68 88 ··· 81 101 /// <https://html.spec.whatwg.org/multipage/#dom-navigator-registerprotocolhandler> 82 102 fn RegisterProtocolHandler(&self, scheme: DOMString, url: USVString) -> Fallible<()> { 83 103 // Step 1. Let (normalizedScheme, normalizedURLString) be the result of 104 + @@ -602,6 +630,60 @@ 105 + self.user_activation 106 + .or_init(|| UserActivation::new(&self.global(), can_gc)) 107 + } 108 + + 109 + + fn CreatePeerStream( 110 + + &self, 111 + + peer_id: DOMString, 112 + + comp: InRealm, 113 + + can_gc: CanGc, 114 + + ) -> Fallible<Rc<Promise>> { 115 + + use base::id::MessagePortId; 116 + + use constellation_traits::ScriptToConstellationMessage; 117 + + 118 + + use crate::dom::messageport::MessagePort; 119 + + 120 + + let global = self.global(); 121 + + let promise = Promise::new_in_current_realm(comp, can_gc); 122 + + 123 + + // Create a local port and a virtual remote port ID. 124 + + // The remote port is NOT tracked in this global — it only exists 125 + + // in the constellation as a Remote proxy. 126 + + let port1 = MessagePort::new(&global, can_gc); 127 + + let remote_port_id = MessagePortId::new(); 128 + + 129 + + // Set port1's entanglement so postMessage knows where to route. 130 + + // We set it on both the DOM object and the MessagePortImpl. 131 + + global.track_message_port(&port1, None); 132 + + global.set_port_entanglement(*port1.message_port_id(), remote_port_id); 133 + + 134 + + // Tell the constellation to create the remote port and send the offer. 135 + + let callback = base::generic_channel::GenericCallback::new( 136 + + move |result: Result<Result<(), String>, _>| { 137 + + if let Ok(Err(e)) = result { 138 + + log::warn!("CreatePeerStream failed: {e}"); 139 + + } 140 + + }, 141 + + ) 142 + + .expect("Could not create callback"); 143 + + 144 + + let chan = global.script_to_constellation_chan(); 145 + + if chan 146 + + .send(ScriptToConstellationMessage::CreatePeerStream( 147 + + peer_id.to_string(), 148 + + *port1.message_port_id(), 149 + + remote_port_id, 150 + + callback, 151 + + )) 152 + + .is_err() 153 + + { 154 + + promise.reject_error(script_bindings::error::Error::Operation(None), can_gc); 155 + + return Ok(promise); 156 + + } 157 + + 158 + + // Resolve with port1 immediately. 159 + + promise.resolve_native(&port1, can_gc); 160 + + Ok(promise) 161 + + } 162 + } 163 + 164 + struct BeaconFetchListener {
+110
patches/components/script/dom/peerstreamevent.rs.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -0,0 +1,107 @@ 4 + +/* SPDX Id: AGPL-3.0-or-later */ 5 + + 6 + +use dom_struct::dom_struct; 7 + +use js::rust::HandleObject; 8 + +use script_bindings::error::Fallible; 9 + +use script_bindings::str::DOMString; 10 + +use stylo_atoms::Atom; 11 + + 12 + +use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; 13 + +use crate::dom::bindings::codegen::Bindings::PeerStreamBinding::{ 14 + + PeerStreamEventInit, PeerStreamEventMethods, 15 + +}; 16 + +use crate::dom::bindings::inheritance::Castable; 17 + +use crate::dom::bindings::reflector::reflect_dom_object_with_proto; 18 + +use crate::dom::bindings::root::{Dom, DomRoot}; 19 + +use crate::dom::event::Event; 20 + +use crate::dom::globalscope::GlobalScope; 21 + +use crate::dom::messageport::MessagePort; 22 + +use crate::dom::window::Window; 23 + +use crate::script_runtime::CanGc; 24 + + 25 + +#[dom_struct] 26 + +pub(crate) struct PeerStreamEvent { 27 + + event: Event, 28 + + port: Dom<MessagePort>, 29 + + peer_id: String, 30 + +} 31 + + 32 + +impl PeerStreamEvent { 33 + + fn new_inherited(port: &MessagePort, peer_id: String) -> PeerStreamEvent { 34 + + PeerStreamEvent { 35 + + event: Event::new_inherited(), 36 + + port: Dom::from_ref(port), 37 + + peer_id, 38 + + } 39 + + } 40 + + 41 + + pub(crate) fn new( 42 + + global: &GlobalScope, 43 + + type_: Atom, 44 + + bubbles: bool, 45 + + cancelable: bool, 46 + + port: &MessagePort, 47 + + peer_id: String, 48 + + can_gc: CanGc, 49 + + ) -> DomRoot<PeerStreamEvent> { 50 + + Self::new_with_proto( 51 + + global, None, type_, bubbles, cancelable, port, peer_id, can_gc, 52 + + ) 53 + + } 54 + + 55 + + fn new_with_proto( 56 + + global: &GlobalScope, 57 + + proto: Option<HandleObject>, 58 + + type_: Atom, 59 + + bubbles: bool, 60 + + cancelable: bool, 61 + + port: &MessagePort, 62 + + peer_id: String, 63 + + can_gc: CanGc, 64 + + ) -> DomRoot<PeerStreamEvent> { 65 + + let ev = reflect_dom_object_with_proto( 66 + + Box::new(PeerStreamEvent::new_inherited(port, peer_id)), 67 + + global, 68 + + proto, 69 + + can_gc, 70 + + ); 71 + + { 72 + + let event = ev.upcast::<Event>(); 73 + + event.init_event(type_, bubbles, cancelable); 74 + + } 75 + + ev 76 + + } 77 + +} 78 + + 79 + +impl PeerStreamEventMethods<crate::DomTypeHolder> for PeerStreamEvent { 80 + + fn Constructor( 81 + + window: &Window, 82 + + proto: Option<HandleObject>, 83 + + can_gc: CanGc, 84 + + type_: DOMString, 85 + + init: &PeerStreamEventInit, 86 + + ) -> Fallible<DomRoot<PeerStreamEvent>> { 87 + + Ok(PeerStreamEvent::new_with_proto( 88 + + window.upcast::<GlobalScope>(), 89 + + proto, 90 + + Atom::from(type_), 91 + + init.parent.bubbles, 92 + + init.parent.cancelable, 93 + + &init.port, 94 + + init.peerId.to_string(), 95 + + can_gc, 96 + + )) 97 + + } 98 + + 99 + + fn Port(&self) -> DomRoot<MessagePort> { 100 + + DomRoot::from_ref(&*self.port) 101 + + } 102 + + 103 + + fn PeerId(&self) -> DOMString { 104 + + DOMString::from(self.peer_id.clone()) 105 + + } 106 + + 107 + + fn IsTrusted(&self) -> bool { 108 + + self.upcast::<Event>().IsTrusted() 109 + + } 110 + +}
+14 -4
patches/components/script/dom/window.rs.patch
··· 83 83 // Step 6: Let userPromptHandler be WebDriver BiDi user prompt opened with this, 84 84 // "prompt", and message. 85 85 // TODO: Add support for WebDriver BiDi. 86 - @@ -3047,9 +3075,33 @@ 86 + @@ -1675,6 +1703,9 @@ 87 + // https://html.spec.whatwg.org/multipage/#windoweventhandlers 88 + window_event_handlers!(); 89 + 90 + + // PeerStream event handler 91 + + event_handler!(peerstream, GetOnpeerstream, SetOnpeerstream); 92 + + 93 + /// <https://developer.mozilla.org/en-US/docs/Web/API/Window/screen> 94 + fn Screen(&self, can_gc: CanGc) -> DomRoot<Screen> { 95 + self.screen.or_init(|| Screen::new(self, can_gc)) 96 + @@ -3047,9 +3078,33 @@ 87 97 &self, 88 98 input_event: &ConstellationInputEvent, 89 99 ) -> Option<HitTestResult> { ··· 120 130 } 121 131 122 132 #[expect(unsafe_code)] 123 - @@ -3068,8 +3120,25 @@ 133 + @@ -3068,8 +3123,25 @@ 124 134 // SAFETY: This is safe because `Window::query_elements_from_point` has ensured that 125 135 // layout has run and any OpaqueNodes that no longer refer to real nodes are gone. 126 136 let address = UntrustedNodeAddress(result.node.0 as *const c_void); ··· 147 157 cursor: result.cursor, 148 158 point_in_node: result.point_in_target, 149 159 point_in_frame, 150 - @@ -3750,6 +3819,8 @@ 160 + @@ -3750,6 +3822,8 @@ 151 161 player_context: WindowGLContext, 152 162 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>, 153 163 inherited_secure_context: Option<bool>, ··· 156 166 theme: Theme, 157 167 weak_script_thread: Weak<ScriptThread>, 158 168 ) -> DomRoot<Self> { 159 - @@ -3776,6 +3847,8 @@ 169 + @@ -3776,6 +3850,8 @@ 160 170 gpu_id_hub, 161 171 inherited_secure_context, 162 172 unminify_js,
+2 -1
patches/components/script/messaging.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -108,6 +108,9 @@ 3 + @@ -108,6 +108,10 @@ 4 4 ScriptThreadMessage::UpdatePinchZoomInfos(id, _) => Some(*id), 5 5 ScriptThreadMessage::SetAccessibilityActive(..) => None, 6 6 ScriptThreadMessage::TriggerGarbageCollection => None, 7 7 + ScriptThreadMessage::DispatchEmbeddedWebViewEvent { parent, .. } => Some(*parent), 8 8 + ScriptThreadMessage::DispatchServoError(..) => None, 9 9 + ScriptThreadMessage::DispatchPairingEvent(..) => None, 10 + + ScriptThreadMessage::DispatchPeerStream(..) => None, 10 11 }, 11 12 MixedMessage::FromScript(inner_msg) => match inner_msg { 12 13 MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
+126 -10
patches/components/script/script_thread.rs.patch
··· 1 1 --- original 2 2 +++ modified 3 - @@ -41,9 +41,9 @@ 3 + @@ -35,15 +35,15 @@ 4 + use base::cross_process_instant::CrossProcessInstant; 5 + use base::generic_channel; 6 + use base::id::{ 7 + - BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespace, ScriptEventLoopId, 8 + - TEST_WEBVIEW_ID, WebViewId, 9 + + BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespace, 10 + + ScriptEventLoopId, TEST_WEBVIEW_ID, WebViewId, 11 + }; 4 12 use canvas_traits::webgl::WebGLPipeline; 5 13 use chrono::{DateTime, Local}; 6 14 use constellation_traits::{ ··· 30 38 use servo_config::{opts, pref, prefs}; 31 39 use servo_url::{ImmutableOrigin, MutableOrigin, OriginSnapshot, ServoUrl}; 32 40 use storage_traits::StorageThreads; 33 - @@ -1941,11 +1942,22 @@ 41 + @@ -116,6 +117,8 @@ 42 + use crate::dom::bindings::codegen::Bindings::DocumentBinding::{ 43 + DocumentMethods, DocumentReadyState, 44 + }; 45 + +use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; 46 + +use crate::dom::bindings::codegen::Bindings::MessagePortBinding::MessagePortMethods; 47 + use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; 48 + use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; 49 + use crate::dom::bindings::conversions::{ 50 + @@ -135,9 +138,13 @@ 51 + RenderingUpdateReason, 52 + }; 53 + use crate::dom::element::Element; 54 + +use crate::dom::event::Event; 55 + +use crate::dom::eventtarget::EventTarget; 56 + use crate::dom::globalscope::GlobalScope; 57 + use crate::dom::html::htmliframeelement::{HTMLIFrameElement, IframeContext}; 58 + +use crate::dom::messageport::MessagePort; 59 + use crate::dom::node::{Node, NodeTraits}; 60 + +use crate::dom::peerstreamevent::PeerStreamEvent; 61 + use crate::dom::servoparser::{ParserContext, ServoParser}; 62 + use crate::dom::types::DebuggerGlobalScope; 63 + #[cfg(feature = "webgpu")] 64 + @@ -1941,11 +1948,22 @@ 34 65 self.handle_refresh_cursor(pipeline_id); 35 66 }, 36 67 ScriptThreadMessage::PreferencesUpdated(updates) => { ··· 57 88 }, 58 89 ScriptThreadMessage::ForwardKeyboardScroll(pipeline_id, scroll) => { 59 90 if let Some(document) = self.documents.borrow().find_document(pipeline_id) { 60 - @@ -1986,6 +1998,19 @@ 91 + @@ -1986,6 +2004,33 @@ 61 92 ScriptThreadMessage::TriggerGarbageCollection => unsafe { 62 93 JS_GC(*GlobalScope::get_cx(), GCReason::API); 63 94 }, ··· 73 104 + }, 74 105 + ScriptThreadMessage::DispatchPairingEvent(event) => { 75 106 + self.handle_dispatch_pairing_event(event, CanGc::from_cx(cx)); 107 + + }, 108 + + ScriptThreadMessage::DispatchPeerStream( 109 + + peer_id, 110 + + remote_port_id_bytes, 111 + + stream_id, 112 + + from_peer, 113 + + ) => { 114 + + self.handle_dispatch_peer_stream( 115 + + peer_id, 116 + + remote_port_id_bytes, 117 + + stream_id, 118 + + from_peer, 119 + + CanGc::from_cx(cx), 120 + + ); 76 121 + }, 77 122 } 78 123 } 79 124 80 - @@ -3064,6 +3089,9 @@ 125 + @@ -3064,6 +3109,9 @@ 81 126 .documents 82 127 .borrow() 83 128 .find_iframe(parent_pipeline_id, browsing_context_id); ··· 87 132 if let Some(frame_element) = frame_element { 88 133 frame_element.update_pipeline_id(new_pipeline_id, reason, cx); 89 134 } 90 - @@ -3083,6 +3111,7 @@ 135 + @@ -3083,6 +3131,7 @@ 91 136 // is no need to pass along existing opener information that 92 137 // will be discarded. 93 138 None, ··· 95 140 ); 96 141 } 97 142 } 98 - @@ -3359,6 +3388,60 @@ 143 + @@ -3359,6 +3408,131 @@ 99 144 } 100 145 } 101 146 ··· 153 198 + } 154 199 + } 155 200 + 201 + + /// Handle an incoming peer stream: create a local MessagePort and fire "peerstream" on Window. 202 + + /// If preventDefault() is called on the event, deny the offer. 203 + + fn handle_dispatch_peer_stream( 204 + + &self, 205 + + peer_id: String, 206 + + remote_port_id_bytes: Vec<u8>, 207 + + stream_id: String, 208 + + from_peer: String, 209 + + can_gc: CanGc, 210 + + ) { 211 + + let Ok(remote_port_id) = postcard::from_bytes::<MessagePortId>(&remote_port_id_bytes) 212 + + else { 213 + + log::warn!("Failed to deserialize remote port ID in DispatchPeerStream"); 214 + + return; 215 + + }; 216 + + 217 + + // Fire on all windows. If any handler calls preventDefault(), deny the offer. 218 + + // TODO: figure out a better design that doesn't dispatch on all the windows. 219 + + let mut accepted = false; 220 + + for (_, document) in self.documents.borrow().iter() { 221 + + let window = document.window(); 222 + + let global = window.upcast::<crate::dom::globalscope::GlobalScope>(); 223 + + let _ac = enter_realm(window); 224 + + 225 + + // Create a new local port and set its entanglement to the remote port. 226 + + let local_port = MessagePort::new(global, can_gc); 227 + + global.track_message_port(&local_port, None); 228 + + global.set_port_entanglement(*local_port.message_port_id(), remote_port_id); 229 + + global.start_message_port(local_port.message_port_id(), can_gc); 230 + + 231 + + // Tell the constellation to set bidirectional entanglement. 232 + + let _ = global.script_to_constellation_chan().send( 233 + + ScriptToConstellationMessage::EntanglePorts( 234 + + *local_port.message_port_id(), 235 + + remote_port_id, 236 + + ), 237 + + ); 238 + + 239 + + // Fire the cancelable "peerstream" event on Window. 240 + + let event = PeerStreamEvent::new( 241 + + global, 242 + + Atom::from("peerstream"), 243 + + false, 244 + + true, // cancelable 245 + + &local_port, 246 + + peer_id.clone(), 247 + + can_gc, 248 + + ); 249 + + event 250 + + .upcast::<Event>() 251 + + .fire(window.upcast::<EventTarget>(), can_gc); 252 + + 253 + + if !event.upcast::<Event>().DefaultPrevented() { 254 + + accepted = true; 255 + + } else { 256 + + // Clean up the port — the offer was denied. 257 + + local_port.Close(can_gc); 258 + + } 259 + + } 260 + + 261 + + // Report back to the constellation. 262 + + if let Some((_, document)) = self.documents.borrow().iter().next() { 263 + + let global = document 264 + + .window() 265 + + .upcast::<crate::dom::globalscope::GlobalScope>(); 266 + + let _ = global.script_to_constellation_chan().send( 267 + + ScriptToConstellationMessage::PeerStreamResponse(stream_id, from_peer, accepted), 268 + + ); 269 + + } 270 + + } 271 + + 156 272 fn ask_constellation_for_top_level_info( 157 273 &self, 158 274 sender_webview_id: WebViewId, 159 - @@ -3473,7 +3556,13 @@ 275 + @@ -3473,7 +3647,13 @@ 160 276 self.senders.pipeline_to_embedder_sender.clone(), 161 277 self.senders.constellation_sender.clone(), 162 278 incomplete.pipeline_id, ··· 171 287 incomplete.viewport_details, 172 288 origin.clone(), 173 289 final_url.clone(), 174 - @@ -3495,6 +3584,8 @@ 290 + @@ -3495,6 +3675,8 @@ 175 291 #[cfg(feature = "webgpu")] 176 292 self.gpu_id_hub.clone(), 177 293 incomplete.load_data.inherited_secure_context, ··· 180 296 incomplete.theme, 181 297 self.this.clone(), 182 298 ); 183 - @@ -3518,6 +3609,7 @@ 299 + @@ -3518,6 +3700,7 @@ 184 300 incomplete.webview_id, 185 301 incomplete.parent_info, 186 302 incomplete.opener, ··· 188 304 ); 189 305 if window_proxy.parent().is_some() { 190 306 // https://html.spec.whatwg.org/multipage/#navigating-across-documents:delaying-load-events-mode-2 191 - @@ -4291,6 +4383,24 @@ 307 + @@ -4291,6 +4474,24 @@ 192 308 document.event_handler().handle_refresh_cursor(); 193 309 } 194 310
+11
patches/components/script_bindings/codegen/Bindings.conf.patch
··· 12 12 'EventSource': { 13 13 'weakReferenceable': True, 14 14 }, 15 + @@ -668,8 +673,8 @@ 16 + }, 17 + 18 + 'Navigator': { 19 + - 'inRealms': ['GetVRDisplays'], 20 + - 'canGc': ['Languages', 'SendBeacon', 'UserActivation'], 21 + + 'inRealms': ['GetVRDisplays', 'CreatePeerStream'], 22 + + 'canGc': ['Languages', 'SendBeacon', 'UserActivation', 'CreatePeerStream'], 23 + }, 24 + 25 + 'Node': { 15 26 @@ -703,6 +708,11 @@ 16 27 'cx': ['CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient', 'GetTransform'], 17 28 },
+24
patches/components/script_bindings/webidls/PeerStream.webidl.patch
··· 1 + --- original 2 + +++ modified 3 + @@ -0,0 +1,21 @@ 4 + +/* SPDX Id: AGPL-3.0-or-later */ 5 + + 6 + +[Exposed=Window] 7 + +interface PeerStreamEvent : Event { 8 + + [Throws] constructor(DOMString type, PeerStreamEventInit eventInitDict); 9 + + readonly attribute MessagePort port; 10 + + readonly attribute DOMString peerId; 11 + +}; 12 + + 13 + +dictionary PeerStreamEventInit : EventInit { 14 + + required MessagePort port; 15 + + required DOMString peerId; 16 + +}; 17 + + 18 + +partial interface Navigator { 19 + + [Throws] Promise<MessagePort> createPeerStream(DOMString peerId); 20 + +}; 21 + + 22 + +partial interface Window { 23 + + attribute EventHandler onpeerstream; 24 + +};
+13 -1
patches/components/shared/constellation/from_script_message.rs.patch
··· 119 119 /// Mark a new document as active 120 120 ActivateDocument, 121 121 /// Set the document state for a pipeline (used by screenshot / reftests) 122 - @@ -726,6 +775,60 @@ 122 + @@ -726,6 +775,72 @@ 123 123 RespondToScreenshotReadinessRequest(ScreenshotReadinessResponse), 124 124 /// Request the constellation to force garbage collection in all `ScriptThread`'s. 125 125 TriggerGarbageCollection, ··· 177 177 + PairingAcceptPairing(String, GenericCallback<Result<(), String>>), 178 178 + /// Reject an incoming pairing request from a remote peer. 179 179 + PairingRejectPairing(String, GenericCallback<Result<(), String>>), 180 + + /// Create a peer stream: create a virtual remote port entangled with a local port, 181 + + /// and send the offer to a remote peer. 182 + + /// Args: peer_id, local_port_id, remote_port_id, callback. 183 + + CreatePeerStream( 184 + + String, 185 + + base::id::MessagePortId, 186 + + base::id::MessagePortId, 187 + + GenericCallback<Result<(), String>>, 188 + + ), 189 + + /// Response to a DispatchPeerStream — whether the peer stream was accepted or denied. 190 + + /// Args: stream_id, from_peer_id, accepted. 191 + + PeerStreamResponse(String, String, bool), 180 192 } 181 193 182 194 impl fmt::Debug for ScriptToConstellationMessage {
+4 -1
patches/components/shared/script/lib.rs.patch
··· 35 35 } 36 36 37 37 /// When a pipeline is closed, should its browsing context be discarded too? 38 - @@ -312,6 +320,21 @@ 38 + @@ -312,6 +320,24 @@ 39 39 SetAccessibilityActive(bool), 40 40 /// Force a garbage collection in this script thread. 41 41 TriggerGarbageCollection, ··· 54 54 + DispatchServoError(ServoErrorType, String), 55 55 + /// Dispatch a pairing event to all `navigator.embedder.pairing` instances in this script thread. 56 56 + DispatchPairingEvent(constellation_traits::PairingEvent), 57 + + /// Dispatch a peer stream event — a remote peer is offering a MessagePort. 58 + + /// Contains (peer_id, serialized remote port_id bytes, stream_id, from_peer_id). 59 + + DispatchPeerStream(String, Vec<u8>, String, String), 57 60 } 58 61 59 62 impl fmt::Debug for ScriptThreadMessage {