diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index d4f2f38da7e..b546092a4ac 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -23,6 +23,7 @@ compositionstart compositionupdate controllerchange cursive +datachannel date datetime-local dir diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index e4464d570df..24de0ab650a 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -487,6 +487,7 @@ pub mod readablestream; pub mod request; pub mod response; pub mod rtcdatachannel; +pub mod rtcdatachannelevent; pub mod rtcerror; pub mod rtcerrorevent; pub mod rtcicecandidate; diff --git a/components/script/dom/rtcdatachannel.rs b/components/script/dom/rtcdatachannel.rs index 9d51cef77fd..3daa4b0fd85 100644 --- a/components/script/dom/rtcdatachannel.rs +++ b/components/script/dom/rtcdatachannel.rs @@ -50,6 +50,7 @@ impl RTCDataChannel { webrtc_controller: &DomRefCell>, label: USVString, options: &RTCDataChannelInit, + channel: Option>, ) -> RTCDataChannel { let webrtc = webrtc_controller.borrow(); let webrtc = webrtc.as_ref().unwrap(); @@ -59,8 +60,12 @@ impl RTCDataChannel { let mut init: WebRtcDataChannelInit = options.into(); init.label = label.to_string(); - webrtc.create_data_channel(init, sender); - let channel = receiver.recv().unwrap(); + let channel = if channel.is_none() { + webrtc.create_data_channel(init, sender); + receiver.recv().unwrap() + } else { + channel.unwrap() + }; let rtc_data_channel = RTCDataChannel { eventtarget: EventTarget::new_inherited(), @@ -140,12 +145,14 @@ impl RTCDataChannel { webrtc_controller: &DomRefCell>, label: USVString, options: &RTCDataChannelInit, + channel: Option>, ) -> DomRoot { reflect_dom_object( Box::new(RTCDataChannel::new_inherited( webrtc_controller, label, options, + channel, )), global, ) diff --git a/components/script/dom/rtcdatachannelevent.rs b/components/script/dom/rtcdatachannelevent.rs new file mode 100644 index 00000000000..cd5239eff79 --- /dev/null +++ b/components/script/dom/rtcdatachannelevent.rs @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; +use crate::dom::bindings::codegen::Bindings::RTCDataChannelEventBinding::RTCDataChannelEventInit; +use crate::dom::bindings::codegen::Bindings::RTCDataChannelEventBinding::RTCDataChannelEventMethods; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; +use crate::dom::event::Event; +use crate::dom::globalscope::GlobalScope; +use crate::dom::rtcdatachannel::RTCDataChannel; +use crate::dom::window::Window; +use dom_struct::dom_struct; +use servo_atoms::Atom; + +#[dom_struct] +pub struct RTCDataChannelEvent { + event: Event, + channel: Dom, +} + +impl RTCDataChannelEvent { + fn new_inherited(channel: &RTCDataChannel) -> RTCDataChannelEvent { + RTCDataChannelEvent { + event: Event::new_inherited(), + channel: Dom::from_ref(channel), + } + } + + pub fn new( + global: &GlobalScope, + type_: Atom, + bubbles: bool, + cancelable: bool, + channel: &RTCDataChannel, + ) -> DomRoot { + let event = reflect_dom_object( + Box::new(RTCDataChannelEvent::new_inherited(&channel)), + global, + ); + { + let event = event.upcast::(); + event.init_event(type_, bubbles, cancelable); + } + event + } + + pub fn Constructor( + window: &Window, + type_: DOMString, + init: &RTCDataChannelEventInit, + ) -> DomRoot { + RTCDataChannelEvent::new( + &window.global(), + Atom::from(type_), + init.parent.bubbles, + init.parent.cancelable, + &init.channel, + ) + } +} + +impl RTCDataChannelEventMethods for RTCDataChannelEvent { + fn Channel(&self) -> DomRoot { + DomRoot::from_ref(&*self.channel) + } + + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs index 5ce0b109bbd..2e7f05f4873 100644 --- a/components/script/dom/rtcpeerconnection.rs +++ b/components/script/dom/rtcpeerconnection.rs @@ -29,6 +29,7 @@ use crate::dom::mediastream::MediaStream; use crate::dom::mediastreamtrack::MediaStreamTrack; use crate::dom::promise::Promise; use crate::dom::rtcdatachannel::RTCDataChannel; +use crate::dom::rtcdatachannelevent::RTCDataChannelEvent; use crate::dom::rtcicecandidate::RTCIceCandidate; use crate::dom::rtcpeerconnectioniceevent::RTCPeerConnectionIceEvent; use crate::dom::rtcsessiondescription::RTCSessionDescription; @@ -44,7 +45,7 @@ use servo_media::streams::registry::MediaStreamId; use servo_media::streams::MediaStreamType; use servo_media::webrtc::{ BundlePolicy, GatheringState, IceCandidate, IceConnectionState, SdpType, SessionDescription, - SignalingState, WebRtcController, WebRtcSignaller, + SignalingState, WebRtcController, WebRtcDataChannelBackend, WebRtcSignaller, }; use servo_media::ServoMedia; @@ -145,6 +146,18 @@ impl WebRtcSignaller for RTCSignaller { ); } + fn on_data_channel(&self, channel: Box) { + // XXX(ferjm) get label and options from channel properties. + let this = self.trusted.clone(); + let _ = self.task_source.queue_with_canceller( + task!(on_data_channel: move || { + let this = this.root(); + this.on_data_channel(channel); + }), + &self.canceller, + ); + } + fn close(&self) { // do nothing } @@ -259,6 +272,24 @@ impl RTCPeerConnection { event.upcast::().fire(self.upcast()); } + fn on_data_channel(&self, channel: Box) { + if self.closed.get() { + return; + } + + let channel = RTCDataChannel::new( + &self.global(), + &self.controller, + USVString::from("".to_owned()), + &RTCDataChannelInit::empty(), + Some(channel), + ); + + let event = + RTCDataChannelEvent::new(&self.global(), atom!("datachannel"), false, false, &channel); + event.upcast::().fire(self.upcast()); + } + /// https://www.w3.org/TR/webrtc/#update-ice-gathering-state fn update_gathering_state(&self, state: GatheringState) { // step 1 @@ -646,7 +677,13 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { label: USVString, dataChannelDict: &RTCDataChannelInit, ) -> DomRoot { - RTCDataChannel::new(&self.global(), &self.controller, label, dataChannelDict) + RTCDataChannel::new( + &self.global(), + &self.controller, + label, + dataChannelDict, + None, + ) } } diff --git a/components/script/dom/webidls/RTCDataChannelEvent.webidl b/components/script/dom/webidls/RTCDataChannelEvent.webidl new file mode 100644 index 00000000000..5b1cde9e723 --- /dev/null +++ b/components/script/dom/webidls/RTCDataChannelEvent.webidl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + + // https://www.w3.org/TR/webrtc/#rtcdatachannelevent + + [Exposed=Window] +interface RTCDataChannelEvent : Event { + constructor(DOMString type, RTCDataChannelEventInit eventInitDict); + readonly attribute RTCDataChannel channel; +}; + +dictionary RTCDataChannelEventInit : EventInit { + required RTCDataChannel channel; +}; \ No newline at end of file