aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/canvas_state.rs26
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py4
-rw-r--r--components/script/dom/bindings/conversions.rs23
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs28
-rw-r--r--components/script/dom/htmlcanvaselement.rs5
-rw-r--r--components/script/dom/htmliframeelement.rs60
-rw-r--r--components/script/dom/imagedata.rs14
-rw-r--r--components/script/dom/messageevent.rs79
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/offscreencanvas.rs18
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs46
-rw-r--r--components/script/dom/paintrenderingcontext2d.rs3
-rw-r--r--components/script/dom/webgl2renderingcontext.rs234
-rw-r--r--components/script/dom/webglprogram.rs16
-rw-r--r--components/script/dom/webglrenderingcontext.rs21
-rw-r--r--components/script/dom/webgltransformfeedback.rs133
-rw-r--r--components/script/dom/webidls/HTMLIFrameElement.webidl4
-rw-r--r--components/script/dom/webidls/MessageEvent.webidl11
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl7
-rw-r--r--components/script/dom/webidls/WebGLTransformFeedback.webidl11
-rw-r--r--components/script/euclidext.rs43
-rw-r--r--components/script/lib.rs2
-rw-r--r--components/script/script_runtime.rs109
-rw-r--r--components/script/script_thread.rs24
24 files changed, 826 insertions, 96 deletions
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index 90630fb07c3..4b47308fa46 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -24,6 +24,7 @@ use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeDamage};
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::textmetrics::TextMetrics;
+use crate::euclidext::Size2DExt;
use crate::unpremultiplytable::UNPREMULTIPLY_TABLE;
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg};
use canvas_traits::canvas::{CompositionOrBlending, FillOrStrokeStyle, FillRule};
@@ -180,6 +181,19 @@ impl CanvasState {
.unwrap()
}
+ // https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions
+ pub fn set_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.reset_to_initial_state();
+ self.ipc_renderer
+ .send(CanvasMsg::Recreate(size, self.get_canvas_id()))
+ .unwrap();
+ }
+
+ pub fn reset_to_initial_state(&self) {
+ self.saved_states.borrow_mut().clear();
+ *self.state.borrow_mut() = CanvasContextState::new();
+ }
+
fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
if !([x, y, w, h].iter().all(|val| val.is_finite())) {
return None;
@@ -300,7 +314,7 @@ impl CanvasState {
}
}
- pub fn get_rect(&self, canvas_size: Size2D<u32>, rect: Rect<u32>) -> Vec<u8> {
+ pub fn get_rect(&self, canvas_size: Size2D<u64>, rect: Rect<u64>) -> Vec<u8> {
assert!(self.origin_is_clean());
assert!(Rect::from_size(canvas_size).contains_rect(&rect));
@@ -1019,7 +1033,7 @@ impl CanvasState {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
pub fn get_image_data(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
global: &GlobalScope,
sx: i32,
sy: i32,
@@ -1038,7 +1052,7 @@ impl CanvasState {
}
let (origin, size) = adjust_size_sign(Point2D::new(sx, sy), Size2D::new(sw, sh));
- let read_rect = match pixels::clip(origin, size, canvas_size) {
+ let read_rect = match pixels::clip(origin, size.to_u64(), canvas_size) {
Some(rect) => rect,
None => {
// All the pixels are outside the canvas surface.
@@ -1057,7 +1071,7 @@ impl CanvasState {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
pub fn put_image_data(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
imagedata: &ImageData,
dx: i32,
dy: i32,
@@ -1078,7 +1092,7 @@ impl CanvasState {
#[allow(unsafe_code)]
pub fn put_image_data_(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
imagedata: &ImageData,
dx: i32,
dy: i32,
@@ -1106,7 +1120,7 @@ impl CanvasState {
Point2D::new(dirty_x, dirty_y),
Size2D::new(dirty_width, dirty_height),
);
- let src_rect = match pixels::clip(src_origin, src_size, imagedata_size) {
+ let src_rect = match pixels::clip(src_origin, src_size.to_u64(), imagedata_size.to_u64()) {
Some(rect) => rect,
None => return,
};
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 77c3c776c3e..e660471364e 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -836,6 +836,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
descriptorType = descriptor.nativeType
elif isArgument:
descriptorType = descriptor.argumentType
+ elif descriptor.interface.identifier.name == "WindowProxy":
+ conversionFunction = "windowproxy_from_handlevalue"
if failureCode is None:
substitutions = {
@@ -2409,6 +2411,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'crate::dom::bindings::conversions::ConversionBehavior',
'crate::dom::bindings::conversions::StringificationBehavior',
'crate::dom::bindings::conversions::root_from_handlevalue',
+ 'crate::dom::bindings::conversions::windowproxy_from_handlevalue',
'std::ptr::NonNull',
'crate::dom::bindings::record::Record',
'crate::dom::bindings::num::Finite',
@@ -2419,6 +2422,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'crate::dom::bindings::trace::RootedTraceableBox',
'crate::dom::bindings::utils::find_enum_value',
'crate::dom::types::*',
+ 'crate::dom::windowproxy::WindowProxy',
'crate::script_runtime::JSContext as SafeJSContext',
'js::error::throw_type_error',
'js::rust::HandleValue',
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index c84adf64dbb..531ff6ea885 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -45,6 +45,7 @@ use crate::dom::htmlcollection::HTMLCollection;
use crate::dom::htmlformcontrolscollection::HTMLFormControlsCollection;
use crate::dom::htmloptionscollection::HTMLOptionsCollection;
use crate::dom::nodelist::NodeList;
+use crate::dom::windowproxy::WindowProxy;
use js::conversions::latin1_to_string;
pub use js::conversions::ConversionBehavior;
pub use js::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
@@ -55,10 +56,10 @@ use js::glue::{IsWrapper, UnwrapObjectDynamic};
use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING};
use js::jsapi::{Heap, JSContext, JSObject, JSString};
+use js::jsapi::{IsWindowProxy, JS_NewStringCopyN, JS_StringHasLatin1Chars};
use js::jsapi::{
JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength, JS_IsExceptionPending,
};
-use js::jsapi::{JS_NewStringCopyN, JS_StringHasLatin1Chars};
use js::jsval::{ObjectValue, StringValue, UndefinedValue};
use js::rust::wrappers::{JS_GetProperty, JS_HasProperty, JS_IsArrayObject};
use js::rust::{get_object_class, is_dom_class, is_dom_object, maybe_wrap_value, ToString};
@@ -74,7 +75,6 @@ pub trait IDLInterface {
}
/// A trait to mark an IDL interface as deriving from another one.
-#[rustc_on_unimplemented(message = "The IDL interface `{Self}` is not derived from `{T}`.")]
pub trait DerivedFrom<T: Castable>: Castable {}
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
@@ -634,3 +634,22 @@ where
Err(()) => Err(Error::JSFailed),
}
}
+
+/// Get a `DomRoot<T>` for a WindowProxy accessible from a `HandleValue`.
+/// Caller is responsible for throwing a JS exception if needed in case of error.
+pub unsafe fn windowproxy_from_handlevalue(
+ v: HandleValue,
+ _cx: *mut JSContext,
+) -> Result<DomRoot<WindowProxy>, ()> {
+ if !v.get().is_object() {
+ return Err(());
+ }
+ let object = v.get().to_object();
+ if !IsWindowProxy(object) {
+ return Err(());
+ }
+ let mut value = UndefinedValue();
+ GetProxyReservedSlot(object, 0, &mut value);
+ let ptr = value.to_private() as *const WindowProxy;
+ Ok(DomRoot::from_ref(&*ptr))
+}
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 9f6403bec5c..371b31bbdb0 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -22,9 +22,10 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::imagedata::ImageData;
use crate::dom::textmetrics::TextMetrics;
+use crate::euclidext::Size2DExt;
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg};
use dom_struct::dom_struct;
-use euclid::default::{Rect, Size2D};
+use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc::IpcSender;
use servo_url::ServoUrl;
use std::mem;
@@ -75,12 +76,13 @@ impl CanvasRenderingContext2D {
.borrow()
.get_ipc_renderer()
.send(CanvasMsg::Recreate(
- size,
+ size.to_u64(),
self.canvas_state.borrow().get_canvas_id(),
))
.unwrap();
}
+ // TODO: This duplicates functionality in canvas state
// https://html.spec.whatwg.org/multipage/#reset-the-rendering-context-to-its-default-state
fn reset_to_initial_state(&self) {
self.canvas_state
@@ -90,6 +92,15 @@ impl CanvasRenderingContext2D {
.clear();
*self.canvas_state.borrow().get_state().borrow_mut() = CanvasContextState::new();
}
+ /*
+ pub fn get_canvas_state(&self) -> Ref<CanvasState> {
+ self.canvas_state.borrow()
+ }
+ */
+
+ pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.canvas_state.borrow().set_bitmap_dimensions(size);
+ }
pub fn mark_as_dirty(&self) {
self.canvas_state
@@ -116,6 +127,7 @@ impl CanvasRenderingContext2D {
self.canvas_state.borrow().send_canvas_2d_msg(msg)
}
+ // TODO: Remove this
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
self.canvas_state.borrow().get_ipc_renderer().clone()
}
@@ -125,10 +137,14 @@ impl CanvasRenderingContext2D {
}
pub fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> {
+ let rect = Rect::new(
+ Point2D::new(rect.origin.x as u64, rect.origin.y as u64),
+ Size2D::new(rect.size.width as u64, rect.size.height as u64),
+ );
self.canvas_state.borrow().get_rect(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
rect,
)
}
@@ -469,7 +485,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().get_image_data(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
&self.global(),
sx,
sy,
@@ -483,7 +499,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().put_image_data(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
imagedata,
dx,
dy,
@@ -505,7 +521,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().put_image_data_(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
imagedata,
dx,
dy,
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 9e638539995..8924f8ddd1c 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -28,6 +28,7 @@ use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
use crate::dom::webglrenderingcontext::{
LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext,
};
+use crate::euclidext::Size2DExt;
use crate::script_runtime::JSContext;
use base64;
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromScriptMsg};
@@ -94,7 +95,9 @@ impl HTMLCanvasElement {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
- CanvasContext::Context2d(ref context) => context.set_bitmap_dimensions(size),
+ CanvasContext::Context2d(ref context) => {
+ context.set_canvas_bitmap_dimensions(size.to_u64())
+ },
CanvasContext::WebGL(ref context) => context.recreate(size),
CanvasContext::WebGL2(ref context) => context.recreate(size),
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index e58e65ea5bb..b70663a6949 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -130,10 +130,12 @@ impl HTMLIFrameElement {
let document = document_from_node(self);
- let mut load_blocker = self.load_blocker.borrow_mut();
- // Any oustanding load is finished from the point of view of the blocked
- // document; the new navigation will continue blocking it.
- LoadBlocker::terminate(&mut load_blocker);
+ {
+ let mut load_blocker = self.load_blocker.borrow_mut();
+ // Any oustanding load is finished from the point of view of the blocked
+ // document; the new navigation will continue blocking it.
+ LoadBlocker::terminate(&mut load_blocker);
+ }
if load_data.url.scheme() == "javascript" {
let window_proxy = self.GetContentWindow();
@@ -150,6 +152,7 @@ impl HTMLIFrameElement {
match load_data.js_eval_result {
Some(JsEvalResult::NoContent) => (),
_ => {
+ let mut load_blocker = self.load_blocker.borrow_mut();
*load_blocker = Some(LoadBlocker::new(
&*document,
LoadType::Subframe(load_data.url.clone()),
@@ -229,7 +232,30 @@ impl HTMLIFrameElement {
/// <https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes>
fn process_the_iframe_attributes(&self, mode: ProcessingMode) {
- // TODO: srcdoc
+ if self
+ .upcast::<Element>()
+ .has_attribute(&local_name!("srcdoc"))
+ {
+ let url = ServoUrl::parse("about:srcdoc").unwrap();
+ let document = document_from_node(self);
+ let window = window_from_node(self);
+ let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
+ let mut load_data = LoadData::new(
+ LoadOrigin::Script(document.origin().immutable().clone()),
+ url,
+ pipeline_id,
+ Some(Referrer::ReferrerUrl(document.url())),
+ document.get_referrer_policy(),
+ );
+ let element = self.upcast::<Element>();
+ load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
+ self.navigate_or_reload_child_browsing_context(
+ load_data,
+ NavigationType::InitialAboutBlank,
+ HistoryEntryReplacement::Disabled,
+ );
+ return;
+ }
let window = window_from_node(self);
@@ -480,6 +506,12 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-src
make_url_setter!(SetSrc, "src");
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_getter!(Srcdoc, "srcdoc");
+
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_setter!(SetSrcdoc, "srcdoc");
+
// https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
fn Sandbox(&self) -> DomRoot<DOMTokenList> {
self.sandbox
@@ -580,13 +612,29 @@ impl VirtualMethods for HTMLIFrameElement {
modes
}));
},
+ &local_name!("srcdoc") => {
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element:the-iframe-element-9
+ // "Whenever an iframe element with a non-null nested browsing context has its
+ // srcdoc attribute set, changed, or removed, the user agent must process the
+ // iframe attributes."
+ // but we can't check that directly, since the child browsing context
+ // may be in a different script thread. Instead, we check to see if the parent
+ // is in a document tree and has a browsing context, which is what causes
+ // the child browsing context to be created.
+
+ // trigger the processing of iframe attributes whenever "srcdoc" attribute is set, changed or removed
+ if self.upcast::<Node>().is_connected_with_browsing_context() {
+ debug!("iframe srcdoc modified while in browsing context.");
+ self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
+ }
+ },
&local_name!("src") => {
// https://html.spec.whatwg.org/multipage/#the-iframe-element
// "Similarly, whenever an iframe element with a non-null nested browsing context
// but with no srcdoc attribute specified has its src attribute set, changed, or removed,
// the user agent must process the iframe attributes,"
// but we can't check that directly, since the child browsing context
- // may be in a different script thread. Instread, we check to see if the parent
+ // may be in a different script thread. Instead, we check to see if the parent
// is in a document tree and has a browsing context, which is what causes
// the child browsing context to be created.
if self.upcast::<Node>().is_connected_with_browsing_context() {
diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs
index d89e5e36d1b..b09984e267f 100644
--- a/components/script/dom/imagedata.rs
+++ b/components/script/dom/imagedata.rs
@@ -169,8 +169,8 @@ impl ImageData {
}
#[allow(unsafe_code)]
- pub unsafe fn get_rect(&self, rect: Rect<u32>) -> Cow<[u8]> {
- pixels::rgba8_get_rect(self.as_slice(), self.get_size(), rect)
+ pub unsafe fn get_rect(&self, rect: Rect<u64>) -> Cow<[u8]> {
+ pixels::rgba8_get_rect(self.as_slice(), self.get_size().to_u64(), rect)
}
pub fn get_size(&self) -> Size2D<u32> {
@@ -194,3 +194,13 @@ impl ImageDataMethods for ImageData {
NonNull::new(self.data.get()).expect("got a null pointer")
}
}
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ return Size2D::new(self.width as u64, self.height as u64);
+ }
+}
diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs
index cb8ebaaebd1..3e9a7079605 100644
--- a/components/script/dom/messageevent.rs
+++ b/components/script/dom/messageevent.rs
@@ -5,9 +5,10 @@
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
+use crate::dom::bindings::codegen::UnionTypes::WindowProxyOrMessagePortOrServiceWorker;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
@@ -16,14 +17,39 @@ use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
+use crate::dom::serviceworker::ServiceWorker;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
-use js::jsapi::{Heap, JSObject};
+use js::jsapi::Heap;
use js::jsval::JSVal;
use js::rust::HandleValue;
use servo_atoms::Atom;
-use std::ptr::NonNull;
+
+#[must_root]
+#[derive(JSTraceable, MallocSizeOf)]
+enum SrcObject {
+ WindowProxy(Dom<WindowProxy>),
+ MessagePort(Dom<MessagePort>),
+ ServiceWorker(Dom<ServiceWorker>),
+}
+
+impl From<&WindowProxyOrMessagePortOrServiceWorker> for SrcObject {
+ #[allow(unrooted_must_root)]
+ fn from(src_object: &WindowProxyOrMessagePortOrServiceWorker) -> SrcObject {
+ match src_object {
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(blob) => {
+ SrcObject::WindowProxy(Dom::from_ref(&*blob))
+ },
+ WindowProxyOrMessagePortOrServiceWorker::MessagePort(stream) => {
+ SrcObject::MessagePort(Dom::from_ref(&*stream))
+ },
+ WindowProxyOrMessagePortOrServiceWorker::ServiceWorker(stream) => {
+ SrcObject::ServiceWorker(Dom::from_ref(&*stream))
+ },
+ }
+ }
+}
#[dom_struct]
pub struct MessageEvent {
@@ -31,7 +57,7 @@ pub struct MessageEvent {
#[ignore_malloc_size_of = "mozjs"]
data: Heap<JSVal>,
origin: DOMString,
- source: Option<Dom<WindowProxy>>,
+ source: Option<SrcObject>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
}
@@ -52,14 +78,14 @@ impl MessageEvent {
global: &GlobalScope,
data: HandleValue,
origin: DOMString,
- source: Option<&WindowProxy>,
+ source: Option<&WindowProxyOrMessagePortOrServiceWorker>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
let ev = Box::new(MessageEvent {
event: Event::new_inherited(),
data: Heap::default(),
- source: source.map(Dom::from_ref),
+ source: source.map(|source| source.into()),
origin,
lastEventId,
ports,
@@ -77,7 +103,7 @@ impl MessageEvent {
cancelable: bool,
data: HandleValue,
origin: DOMString,
- source: Option<&WindowProxy>,
+ source: Option<&WindowProxyOrMessagePortOrServiceWorker>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
@@ -94,10 +120,6 @@ impl MessageEvent {
type_: DOMString,
init: RootedTraceableBox<MessageEventBinding::MessageEventInit>,
) -> Fallible<DomRoot<MessageEvent>> {
- let source = init
- .source
- .as_ref()
- .and_then(|inner| inner.as_ref().map(|source| source.window_proxy()));
let ev = MessageEvent::new(
global,
Atom::from(type_),
@@ -105,9 +127,9 @@ impl MessageEvent {
init.parent.cancelable,
init.data.handle(),
init.origin.clone(),
- source.as_ref().map(|source| &**source),
+ init.source.as_ref(),
init.lastEventId.clone(),
- init.ports.clone().unwrap_or(vec![]),
+ init.ports.clone(),
);
Ok(ev)
}
@@ -129,7 +151,11 @@ impl MessageEvent {
false,
message,
DOMString::from(origin.unwrap_or("")),
- source,
+ source
+ .map(|source| {
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(DomRoot::from_ref(source))
+ })
+ .as_ref(),
DOMString::new(),
ports,
);
@@ -138,10 +164,6 @@ impl MessageEvent {
pub fn dispatch_error(target: &EventTarget, scope: &GlobalScope) {
let init = MessageEventBinding::MessageEventInit::empty();
- let source = init
- .source
- .as_ref()
- .and_then(|inner| inner.as_ref().map(|source| source.window_proxy()));
let messageevent = MessageEvent::new(
scope,
atom!("messageerror"),
@@ -149,9 +171,9 @@ impl MessageEvent {
init.parent.cancelable,
init.data.handle(),
init.origin.clone(),
- source.as_ref().map(|source| &**source),
+ init.source.as_ref(),
init.lastEventId.clone(),
- init.ports.clone().unwrap_or(vec![]),
+ init.ports.clone(),
);
messageevent.upcast::<Event>().fire(target);
}
@@ -169,10 +191,19 @@ impl MessageEventMethods for MessageEvent {
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-source
- fn GetSource(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
- self.source
- .as_ref()
- .and_then(|source| NonNull::new(source.reflector().get_jsobject().get()))
+ fn GetSource(&self) -> Option<WindowProxyOrMessagePortOrServiceWorker> {
+ match &self.source {
+ Some(SrcObject::WindowProxy(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(DomRoot::from_ref(&*i)),
+ ),
+ Some(SrcObject::MessagePort(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::MessagePort(DomRoot::from_ref(&*i)),
+ ),
+ Some(SrcObject::ServiceWorker(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::ServiceWorker(DomRoot::from_ref(&*i)),
+ ),
+ None => None,
+ }
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid>
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 302ae5baad4..16d2c6fb686 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -532,6 +532,7 @@ pub mod webglshader;
pub mod webglshaderprecisionformat;
pub mod webglsync;
pub mod webgltexture;
+pub mod webgltransformfeedback;
pub mod webgluniformlocation;
pub mod webglvertexarrayobjectoes;
pub mod websocket;
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index 142379519fb..69c1114768c 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -92,11 +92,9 @@ impl OffscreenCanvas {
OffscreenCanvasContext::OffscreenContext2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
};
}
- let size = self.get_size();
let context = OffscreenCanvasRenderingContext2D::new(
&self.global(),
self,
- size,
self.placeholder.as_ref().map(|c| &**c),
);
*self.context.borrow_mut() = Some(OffscreenCanvasContext::OffscreenContext2d(
@@ -136,6 +134,14 @@ impl OffscreenCanvasMethods for OffscreenCanvas {
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-width
fn SetWidth(&self, value: u64) {
self.width.set(value);
+
+ if let Some(canvas_context) = self.context() {
+ match &*canvas_context {
+ OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
+ rendering_context.set_canvas_bitmap_dimensions(self.get_size());
+ },
+ }
+ }
}
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height
@@ -146,5 +152,13 @@ impl OffscreenCanvasMethods for OffscreenCanvas {
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height
fn SetHeight(&self, value: u64) {
self.height.set(value);
+
+ if let Some(canvas_context) = self.context() {
+ match &*canvas_context {
+ OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
+ rendering_context.set_canvas_bitmap_dimensions(self.get_size());
+ },
+ }
+ }
}
}
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index 04e0a13032c..077752d9d6e 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -30,44 +30,32 @@ use euclid::default::Size2D;
#[dom_struct]
pub struct OffscreenCanvasRenderingContext2D {
reflector_: Reflector,
- canvas: Option<Dom<OffscreenCanvas>>,
+ canvas: Dom<OffscreenCanvas>,
canvas_state: DomRefCell<CanvasState>,
htmlcanvas: Option<Dom<HTMLCanvasElement>>,
- width: u32,
- height: u32,
}
impl OffscreenCanvasRenderingContext2D {
fn new_inherited(
global: &GlobalScope,
- canvas: Option<&OffscreenCanvas>,
- size: Size2D<u64>,
+ canvas: &OffscreenCanvas,
htmlcanvas: Option<&HTMLCanvasElement>,
) -> OffscreenCanvasRenderingContext2D {
OffscreenCanvasRenderingContext2D {
reflector_: Reflector::new(),
- canvas: canvas.map(Dom::from_ref),
+ canvas: Dom::from_ref(canvas),
htmlcanvas: htmlcanvas.map(Dom::from_ref),
- canvas_state: DomRefCell::new(CanvasState::new(
- global,
- Size2D::new(size.width as u64, size.height as u64),
- )),
- width: size.width as u32,
- height: size.height as u32,
+ canvas_state: DomRefCell::new(CanvasState::new(global, canvas.get_size())),
}
}
pub fn new(
global: &GlobalScope,
canvas: &OffscreenCanvas,
- size: Size2D<u64>,
htmlcanvas: Option<&HTMLCanvasElement>,
) -> DomRoot<OffscreenCanvasRenderingContext2D> {
let boxed = Box::new(OffscreenCanvasRenderingContext2D::new_inherited(
- global,
- Some(canvas),
- size,
- htmlcanvas,
+ global, canvas, htmlcanvas,
));
reflect_dom_object(
boxed,
@@ -75,12 +63,21 @@ impl OffscreenCanvasRenderingContext2D {
OffscreenCanvasRenderingContext2DBinding::Wrap,
)
}
+ /*
+ pub fn get_canvas_state(&self) -> Ref<CanvasState> {
+ self.canvas_state.borrow()
+ }
+ */
+
+ pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.canvas_state.borrow().set_bitmap_dimensions(size);
+ }
}
impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/offscreencontext2d-canvas
fn Canvas(&self) -> DomRoot<OffscreenCanvas> {
- DomRoot::from_ref(self.canvas.as_ref().expect("No canvas."))
+ DomRoot::from_ref(&self.canvas)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fillrect
@@ -315,7 +312,7 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
fn GetImageData(&self, sx: i32, sy: i32, sw: i32, sh: i32) -> Fallible<DomRoot<ImageData>> {
self.canvas_state.borrow().get_image_data(
- Size2D::new(self.width, self.height),
+ self.canvas.get_size(),
&self.global(),
sx,
sy,
@@ -326,12 +323,9 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
fn PutImageData(&self, imagedata: &ImageData, dx: i32, dy: i32) {
- self.canvas_state.borrow().put_image_data(
- Size2D::new(self.width, self.height),
- imagedata,
- dx,
- dy,
- )
+ self.canvas_state
+ .borrow()
+ .put_image_data(self.canvas.get_size(), imagedata, dx, dy)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
@@ -347,7 +341,7 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
dirty_height: i32,
) {
self.canvas_state.borrow().put_image_data_(
- Size2D::new(self.width, self.height),
+ self.canvas.get_size(),
imagedata,
dx,
dy,
diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs
index 1bbb52d05fe..e4b0a3cf71e 100644
--- a/components/script/dom/paintrenderingcontext2d.rs
+++ b/components/script/dom/paintrenderingcontext2d.rs
@@ -21,6 +21,7 @@ use crate::dom::canvasgradient::CanvasGradient;
use crate::dom::canvaspattern::CanvasPattern;
use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
+use crate::euclidext::Size2DExt;
use canvas_traits::canvas::CanvasImageData;
use canvas_traits::canvas::CanvasMsg;
use canvas_traits::canvas::FromLayoutMsg;
@@ -75,7 +76,7 @@ impl PaintRenderingContext2D {
let size = size * device_pixel_ratio;
self.device_pixel_ratio.set(device_pixel_ratio);
self.context
- .set_bitmap_dimensions(size.to_untyped().to_u32());
+ .set_canvas_bitmap_dimensions(size.to_untyped().to_u64());
self.scale_by_device_pixel_ratio();
}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index beff6ec6bfd..d9a3e81b46a 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -11,8 +11,8 @@ use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
use crate::dom::bindings::codegen::UnionTypes::Float32ArrayOrUnrestrictedFloatSequence;
use crate::dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use crate::dom::bindings::codegen::UnionTypes::Int32ArrayOrLongSequence;
-use crate::dom::bindings::conversions::ToJSValConvertible;
use crate::dom::bindings::error::{ErrorResult, Fallible};
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
@@ -32,8 +32,10 @@ use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webglsync::WebGLSync;
use crate::dom::webgltexture::WebGLTexture;
+use crate::dom::webgltransformfeedback::WebGLTransformFeedback;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use crate::dom::window::Window;
+use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{
@@ -62,6 +64,7 @@ pub struct WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom<WebGLBuffer>,
bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
+ current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
}
fn typedarray_elem_size(typeid: Type) -> usize {
@@ -100,6 +103,7 @@ impl WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom::new(None),
bound_transform_feedback_buffer: MutNullableDom::new(None),
bound_uniform_buffer: MutNullableDom::new(None),
+ current_transform_feedback: MutNullableDom::new(None),
})
}
@@ -210,6 +214,9 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::UNIFORM_BUFFER_BINDING => unsafe {
optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get())
},
+ constants::TRANSFORM_FEEDBACK_BINDING => unsafe {
+ optional_root_object_to_js_or_null!(*cx, self.current_transform_feedback.get())
+ },
_ => self.base.GetParameter(cx, parameter),
}
}
@@ -824,7 +831,24 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetProgramParameter(&self, cx: JSContext, program: &WebGLProgram, param_id: u32) -> JSVal {
- self.base.GetProgramParameter(cx, program, param_id)
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return NullValue()
+ );
+ if program.is_deleted() {
+ self.base.webgl_error(InvalidOperation);
+ return NullValue();
+ }
+ match param_id {
+ constants::TRANSFORM_FEEDBACK_VARYINGS => {
+ Int32Value(program.transform_feedback_varyings_length())
+ },
+ constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
+ Int32Value(program.transform_feedback_buffer_mode())
+ },
+ _ => self.base.GetProgramParameter(cx, program, param_id),
+ }
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@@ -1721,6 +1745,212 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
},
}
}
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
+ Some(WebGLTransformFeedback::new(&self.base))
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
+ if let Some(tf) = tf {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
+ if tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ tf.delete(false);
+ self.current_transform_feedback.set(None);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
+ match tf {
+ Some(tf) => {
+ if !tf.is_valid() {
+ return false;
+ }
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(tf),
+ return false
+ );
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.base
+ .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
+ receiver.recv().unwrap()
+ },
+ None => false,
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
+ if target != constants::TRANSFORM_FEEDBACK {
+ self.base.webgl_error(InvalidEnum);
+ return;
+ }
+ match tf {
+ Some(transform_feedback) => {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(transform_feedback),
+ return
+ );
+ if !transform_feedback.is_valid() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if current_tf.is_active() && !current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ }
+ transform_feedback.bind(&self.base, target);
+ self.current_transform_feedback
+ .set(Some(transform_feedback));
+ },
+ None => self
+ .base
+ .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn BeginTransformFeedback(&self, primitiveMode: u32) {
+ match primitiveMode {
+ constants::POINTS | constants::LINES | constants::TRIANGLES => {},
+ _ => {
+ self.base.webgl_error(InvalidEnum);
+ return;
+ },
+ };
+ let current_tf = match self.current_transform_feedback.get() {
+ Some(current_tf) => current_tf,
+ None => {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ },
+ };
+ if current_tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ };
+ let program = match self.base.current_program() {
+ Some(program) => program,
+ None => {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ },
+ };
+ if !program.is_linked() || program.transform_feedback_varyings_length() != 0 {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ };
+ current_tf.begin(&self.base, primitiveMode);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn EndTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.end(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn ResumeTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() || !current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.resume(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn PauseTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() || current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.pause(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn TransformFeedbackVaryings(
+ &self,
+ program: &WebGLProgram,
+ varyings: Vec<DOMString>,
+ bufferMode: u32,
+ ) {
+ handle_potential_webgl_error!(self.base, program.validate(), return);
+ let strs = varyings
+ .iter()
+ .map(|name| String::from(name.to_owned()))
+ .collect::<Vec<String>>();
+ match bufferMode {
+ constants::INTERLEAVED_ATTRIBS => {
+ self.base
+ .send_command(WebGLCommand::TransformFeedbackVaryings(
+ program.id(),
+ strs,
+ bufferMode,
+ ));
+ },
+ constants::SEPARATE_ATTRIBS => {
+ let max_tf_sp_att =
+ self.base.limits().max_transform_feedback_separate_attribs as usize;
+ if strs.len() >= max_tf_sp_att {
+ self.base.webgl_error(InvalidValue);
+ return;
+ }
+ self.base
+ .send_command(WebGLCommand::TransformFeedbackVaryings(
+ program.id(),
+ strs,
+ bufferMode,
+ ));
+ },
+ _ => self.base.webgl_error(InvalidEnum),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn GetTransformFeedbackVarying(
+ &self,
+ program: &WebGLProgram,
+ index: u32,
+ ) -> Option<DomRoot<WebGLActiveInfo>> {
+ handle_potential_webgl_error!(self.base, program.validate(), return None);
+ if index >= program.transform_feedback_varyings_length() as u32 {
+ self.base.webgl_error(InvalidValue);
+ return None;
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.base
+ .send_command(WebGLCommand::GetTransformFeedbackVarying(
+ program.id(),
+ index,
+ sender,
+ ));
+ let (size, ty, name) = receiver.recv().unwrap();
+ Some(WebGLActiveInfo::new(
+ self.base.global().as_window(),
+ size,
+ ty,
+ DOMString::from(name),
+ ))
+ }
}
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 6863bc89e53..e4f5f89c6d3 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -34,6 +34,8 @@ pub struct WebGLProgram {
vertex_shader: MutNullableDom<WebGLShader>,
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>,
+ transform_feedback_varyings_length: Cell<i32>,
+ transform_feedback_mode: Cell<i32>,
}
impl WebGLProgram {
@@ -50,6 +52,8 @@ impl WebGLProgram {
vertex_shader: Default::default(),
active_attribs: DomRefCell::new(vec![].into()),
active_uniforms: DomRefCell::new(vec![].into()),
+ transform_feedback_varyings_length: Default::default(),
+ transform_feedback_mode: Default::default(),
}
}
@@ -187,6 +191,10 @@ impl WebGLProgram {
self.linked.set(link_info.linked);
self.link_called.set(true);
+ self.transform_feedback_varyings_length
+ .set(link_info.transform_feedback_length);
+ self.transform_feedback_mode
+ .set(link_info.transform_feedback_mode);
*self.active_attribs.borrow_mut() = link_info.active_attribs;
*self.active_uniforms.borrow_mut() = link_info.active_uniforms;
Ok(())
@@ -444,6 +452,14 @@ impl WebGLProgram {
pub fn link_generation(&self) -> u64 {
self.link_generation.get()
}
+
+ pub fn transform_feedback_varyings_length(&self) -> i32 {
+ self.transform_feedback_varyings_length.get()
+ }
+
+ pub fn transform_feedback_buffer_mode(&self) -> i32 {
+ self.transform_feedback_mode.get()
+ }
}
impl Drop for WebGLProgram {
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index f0e4887858c..c843ab578d1 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -1165,6 +1165,10 @@ impl WebGLRenderingContext {
slot.set(buffer);
}
+
+ pub fn current_program(&self) -> Option<DomRoot<WebGLProgram>> {
+ self.current_program.get()
+ }
}
#[cfg(not(feature = "webgl_backtrace"))]
@@ -2959,11 +2963,16 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let src_origin = Point2D::new(x, y);
let src_size = Size2D::new(width as u32, height as u32);
let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
- let src_rect = match pixels::clip(src_origin, src_size, fb_size) {
+ let src_rect = match pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()) {
Some(rect) => rect,
None => return,
};
+ // Note: we're casting a Rect<u64> back into a Rect<u32> here, but it's okay because
+ // it used u32 data types to begin with. It just got converted to Rect<u64> in
+ // pixels::clip
+ let src_rect = src_rect.to_u32();
+
let mut dest_offset = 0;
if x < 0 {
dest_offset += -x * bytes_per_pixel;
@@ -4481,3 +4490,13 @@ impl WebGLMessageSender {
self.wake_after_send(|| self.sender.send_dom_to_texture(command))
}
}
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ return Size2D::new(self.width as u64, self.height as u64);
+ }
+}
diff --git a/components/script/dom/webgltransformfeedback.rs b/components/script/dom/webgltransformfeedback.rs
new file mode 100644
index 00000000000..a58a8e43577
--- /dev/null
+++ b/components/script/dom/webgltransformfeedback.rs
@@ -0,0 +1,133 @@
+/* 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::WebGLTransformFeedbackBinding;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::webglobject::WebGLObject;
+use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use canvas_traits::webgl::{webgl_channel, WebGLCommand};
+use dom_struct::dom_struct;
+use std::cell::Cell;
+
+#[dom_struct]
+pub struct WebGLTransformFeedback {
+ webgl_object: WebGLObject,
+ id: u32,
+ marked_for_deletion: Cell<bool>,
+ has_been_bound: Cell<bool>,
+ is_active: Cell<bool>,
+ is_paused: Cell<bool>,
+}
+
+impl WebGLTransformFeedback {
+ fn new_inherited(context: &WebGLRenderingContext, id: u32) -> Self {
+ Self {
+ webgl_object: WebGLObject::new_inherited(context),
+ id,
+ marked_for_deletion: Cell::new(false),
+ has_been_bound: Cell::new(false),
+ is_active: Cell::new(false),
+ is_paused: Cell::new(false),
+ }
+ }
+
+ pub fn new(context: &WebGLRenderingContext) -> DomRoot<Self> {
+ let (sender, receiver) = webgl_channel().unwrap();
+ context.send_command(WebGLCommand::CreateTransformFeedback(sender));
+ let id = receiver.recv().unwrap();
+
+ reflect_dom_object(
+ Box::new(WebGLTransformFeedback::new_inherited(context, id)),
+ &*context.global(),
+ WebGLTransformFeedbackBinding::Wrap,
+ )
+ }
+}
+
+impl WebGLTransformFeedback {
+ pub fn bind(&self, context: &WebGLRenderingContext, target: u32) {
+ context.send_command(WebGLCommand::BindTransformFeedback(target, self.id()));
+ self.has_been_bound.set(true);
+ }
+
+ pub fn begin(&self, context: &WebGLRenderingContext, primitive_mode: u32) {
+ if self.has_been_bound.get() && !self.is_active() {
+ context.send_command(WebGLCommand::BeginTransformFeedback(primitive_mode));
+ self.set_active(true);
+ }
+ }
+
+ pub fn end(&self, context: &WebGLRenderingContext) {
+ if self.has_been_bound.get() && self.is_active() {
+ if self.is_paused() {
+ context.send_command(WebGLCommand::ResumeTransformFeedback());
+ }
+ context.send_command(WebGLCommand::EndTransformFeedback());
+ self.set_active(false);
+ }
+ }
+
+ pub fn resume(&self, context: &WebGLRenderingContext) {
+ if self.is_active() && self.is_paused() {
+ context.send_command(WebGLCommand::ResumeTransformFeedback());
+ self.set_pause(false);
+ }
+ }
+
+ pub fn pause(&self, context: &WebGLRenderingContext) {
+ if self.is_active() && !self.is_paused() {
+ context.send_command(WebGLCommand::PauseTransformFeedback());
+ self.set_pause(true);
+ }
+ }
+
+ pub fn id(&self) -> u32 {
+ self.id
+ }
+
+ pub fn is_valid(&self) -> bool {
+ !self.marked_for_deletion.get()
+ }
+
+ pub fn is_active(&self) -> bool {
+ self.is_active.get()
+ }
+
+ pub fn is_paused(&self) -> bool {
+ self.is_paused.get()
+ }
+
+ pub fn delete(&self, fallible: bool) {
+ if self.is_valid() && self.id() != 0 {
+ self.marked_for_deletion.set(true);
+ let context = self.upcast::<WebGLObject>().context();
+ let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
+ if fallible {
+ context.send_command_ignored(cmd);
+ } else {
+ context.send_command(cmd);
+ }
+ }
+ }
+
+ pub fn set_active(&self, value: bool) {
+ if self.is_valid() && self.has_been_bound.get() {
+ self.is_active.set(value);
+ }
+ }
+
+ pub fn set_pause(&self, value: bool) {
+ if self.is_valid() && self.is_active() {
+ self.is_active.set(value);
+ }
+ }
+}
+
+impl Drop for WebGLTransformFeedback {
+ fn drop(&mut self) {
+ self.delete(true);
+ }
+}
diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl
index acc4f0f201d..b9dd97bdea6 100644
--- a/components/script/dom/webidls/HTMLIFrameElement.webidl
+++ b/components/script/dom/webidls/HTMLIFrameElement.webidl
@@ -9,8 +9,8 @@ interface HTMLIFrameElement : HTMLElement {
[CEReactions]
attribute USVString src;
- // [CEReactions]
- // attribute DOMString srcdoc;
+ [CEReactions]
+ attribute DOMString srcdoc;
[CEReactions]
attribute DOMString name;
diff --git a/components/script/dom/webidls/MessageEvent.webidl b/components/script/dom/webidls/MessageEvent.webidl
index 63dd9019cc9..1d4699cbe3c 100644
--- a/components/script/dom/webidls/MessageEvent.webidl
+++ b/components/script/dom/webidls/MessageEvent.webidl
@@ -9,9 +9,7 @@ interface MessageEvent : Event {
readonly attribute any data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
- // FIXME(#22617): WindowProxy is not exposed in Worker globals
- readonly attribute object? source;
- //readonly attribute (WindowProxy or MessagePort)? source;
+ readonly attribute MessageEventSource? source;
readonly attribute /*FrozenArray<MessagePort>*/any ports;
};
@@ -20,9 +18,8 @@ dictionary MessageEventInit : EventInit {
DOMString origin = "";
DOMString lastEventId = "";
//DOMString channel;
- Window? source;
- //(WindowProxy or MessagePort)? source;
- sequence<MessagePort> ports;
+ MessageEventSource? source = null;
+ sequence<MessagePort> ports = [];
};
-typedef (/*WindowProxy or */MessagePort or ServiceWorker) MessageEventSource;
+typedef (WindowProxy or MessagePort or ServiceWorker) MessageEventSource;
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index c171a9bb866..312c7b78211 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -12,9 +12,6 @@ typedef long long GLint64;
typedef unsigned long long GLuint64;
-// interface WebGLTransformFeedback : WebGLObject {
-// };
-
// interface WebGLVertexArrayObject : WebGLObject {
// };
@@ -544,7 +541,7 @@ interface mixin WebGL2RenderingContextBase
any getSyncParameter(WebGLSync sync, GLenum pname);
/* Transform Feedback */
- /*WebGLTransformFeedback? createTransformFeedback();
+ WebGLTransformFeedback? createTransformFeedback();
void deleteTransformFeedback(WebGLTransformFeedback? tf);
[WebGLHandlesContextLoss] GLboolean isTransformFeedback(WebGLTransformFeedback? tf);
void bindTransformFeedback (GLenum target, WebGLTransformFeedback? tf);
@@ -553,7 +550,7 @@ interface mixin WebGL2RenderingContextBase
void transformFeedbackVaryings(WebGLProgram program, sequence<DOMString> varyings, GLenum bufferMode);
WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram program, GLuint index);
void pauseTransformFeedback();
- void resumeTransformFeedback();*/
+ void resumeTransformFeedback();
/* Uniform Buffer Objects and Transform Feedback Buffers */
// void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
diff --git a/components/script/dom/webidls/WebGLTransformFeedback.webidl b/components/script/dom/webidls/WebGLTransformFeedback.webidl
new file mode 100644
index 00000000000..871c0f15c7b
--- /dev/null
+++ b/components/script/dom/webidls/WebGLTransformFeedback.webidl
@@ -0,0 +1,11 @@
+/* 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/. */
+//
+// WebGL IDL definitions scraped from the Khronos specification:
+// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+//
+
+[Exposed=(Window), Pref="dom.webgl2.enabled"]
+interface WebGLTransformFeedback : WebGLObject {
+};
diff --git a/components/script/euclidext.rs b/components/script/euclidext.rs
new file mode 100644
index 00000000000..39de2aa2ccb
--- /dev/null
+++ b/components/script/euclidext.rs
@@ -0,0 +1,43 @@
+/* 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 euclid::default::{Rect, Size2D};
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<f32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+impl Size2DExt for Size2D<f64> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+pub trait RectExt {
+ fn to_u64(&self) -> Rect<u64>;
+}
+
+impl RectExt for Rect<f64> {
+ fn to_u64(&self) -> Rect<u64> {
+ self.cast()
+ }
+}
+
+impl RectExt for Rect<u32> {
+ fn to_u64(&self) -> Rect<u64> {
+ self.cast()
+ }
+}
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 48f42cd7a38..87eec7cab02 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -6,7 +6,6 @@
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![feature(inner_deref)]
-#![feature(on_unimplemented)]
#![feature(plugin)]
#![deny(unsafe_code)]
#![allow(non_snake_case)]
@@ -66,6 +65,7 @@ mod dom;
mod canvas_state;
#[warn(deprecated)]
mod compartments;
+mod euclidext;
#[warn(deprecated)]
pub mod fetch;
#[warn(deprecated)]
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 10198050ace..f240bb170d6 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -7,9 +7,14 @@
#![allow(dead_code)]
+use crate::body::BodyOperations;
use crate::dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
+use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseBinding::ResponseMethods;
+use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
use crate::dom::bindings::conversions::get_dom_class;
use crate::dom::bindings::conversions::private_from_object;
+use crate::dom::bindings::conversions::root_from_handleobject;
+use crate::dom::bindings::error::{throw_dom_exception, Error};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::{trace_refcounted_objects, LiveDOMReferences};
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
@@ -23,6 +28,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::promiserejectionevent::PromiseRejectionEvent;
+use crate::dom::response::Response;
use crate::microtask::{EnqueuedPromiseCallback, Microtask, MicrotaskQueue};
use crate::script_thread::trace_thread;
use crate::task::TaskBox;
@@ -31,6 +37,10 @@ use js::glue::{CollectServoSizes, CreateJobQueue, DeleteJobQueue, JobQueueTraps,
use js::glue::{RUST_js_GetErrorMessage, StreamConsumerConsumeChunk, StreamConsumerStreamEnd};
use js::glue::{StreamConsumerNoteResponseURLs, StreamConsumerStreamError};
use js::jsapi::ContextOptionsRef;
+use js::jsapi::Dispatchable;
+use js::jsapi::InitConsumeStreamCallback;
+use js::jsapi::InitDispatchToEventLoop;
+use js::jsapi::MimeType;
use js::jsapi::StreamConsumer as JSStreamConsumer;
use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress};
use js::jsapi::{HandleObject, Heap, JobQueue};
@@ -46,6 +56,7 @@ use js::jsval::UndefinedValue;
use js::panic::wrap_panic;
use js::rust::wrappers::{GetPromiseIsHandled, JS_GetPromiseResult};
use js::rust::Handle;
+use js::rust::HandleObject as RustHandleObject;
use js::rust::IntoHandle;
use js::rust::JSEngine;
use js::rust::ParentRuntime;
@@ -424,6 +435,16 @@ unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime {
// Pre barriers aren't working correctly at the moment
DisableIncrementalGC(cx);
+ unsafe extern "C" fn dispatch_to_event_loop(
+ _closure: *mut c_void,
+ _dispatchable: *mut Dispatchable,
+ ) -> bool {
+ false
+ }
+ InitDispatchToEventLoop(cx, Some(dispatch_to_event_loop), ptr::null_mut());
+
+ InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error));
+
let microtask_queue = Rc::new(MicrotaskQueue::default());
let job_queue = CreateJobQueue(
&JOB_QUEUE_TRAPS,
@@ -825,8 +846,94 @@ impl StreamConsumer {
}
}
+/// Implements the steps to compile webassembly response mentioned here
+/// <https://webassembly.github.io/spec/web-api/#compile-a-potential-webassembly-response>
+#[allow(unsafe_code)]
+unsafe extern "C" fn consume_stream(
+ _cx: *mut RawJSContext,
+ obj: HandleObject,
+ _mimeType: MimeType,
+ _consumer: *mut JSStreamConsumer,
+) -> bool {
+ let cx = JSContext::from_ptr(_cx);
+ let global = GlobalScope::from_context(*cx);
+
+ //Step 2.1 Upon fulfillment of source, store the Response with value unwrappedSource.
+ if let Ok(unwrapped_source) =
+ root_from_handleobject::<Response>(RustHandleObject::from_raw(obj), *cx)
+ {
+ //Step 2.2 Let mimeType be the result of extracting a MIME type from response’s header list.
+ let mimetype = unwrapped_source.Headers().extract_mime_type();
+
+ //Step 2.3 If mimeType is not `application/wasm`, return with a TypeError and abort these substeps.
+ match &mimetype[..] {
+ b"application/wasm" | b"APPLICATION/wasm" | b"APPLICATION/WASM" => {},
+ _ => {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response has unsupported MIME type".to_string()),
+ );
+ return false;
+ },
+ }
+
+ //Step 2.4 If response is not CORS-same-origin, return with a TypeError and abort these substeps.
+ match unwrapped_source.Type() {
+ DOMResponseType::Basic | DOMResponseType::Cors | DOMResponseType::Default => {},
+ _ => {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response.type must be 'basic', 'cors' or 'default'".to_string()),
+ );
+ return false;
+ },
+ }
+
+ //Step 2.5 If response’s status is not an ok status, return with a TypeError and abort these substeps.
+ if !unwrapped_source.Ok() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response does not have ok status".to_string()),
+ );
+ return false;
+ }
+
+ // Step 2.6.1 If response body is locked, return with a TypeError and abort these substeps.
+ if unwrapped_source.is_locked() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("There was an error consuming the Response".to_string()),
+ );
+ return false;
+ }
+
+ // Step 2.6.2 If response body is alreaady consumed, return with a TypeError and abort these substeps.
+ if unwrapped_source.get_body_used() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response already consumed".to_string()),
+ );
+ return false;
+ }
+ } else {
+ //Step 3 Upon rejection of source, return with reason.
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("expected Response or Promise resolving to Response".to_string()),
+ );
+ return false;
+ }
+ return true;
+}
+
#[allow(unsafe_code)]
-unsafe extern "C" fn report_stream_error_callback(_cx: *mut JSContext, error_code: usize) {
+unsafe extern "C" fn report_stream_error(_cx: *mut RawJSContext, error_code: usize) {
error!(
"Error initializing StreamConsumer: {:?}",
RUST_js_GetErrorMessage(ptr::null_mut(), error_code as u32)
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 191df335ec5..20ac88b7bc1 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -2430,6 +2430,8 @@ impl ScriptThread {
);
if load_data.url.as_str() == "about:blank" {
self.start_page_load_about_blank(new_load, load_data.js_eval_result);
+ } else if load_data.url.as_str() == "about:srcdoc" {
+ self.page_load_about_srcdoc(new_load, load_data.srcdoc);
} else {
self.pre_page_load(new_load, load_data);
}
@@ -3177,7 +3179,8 @@ impl ScriptThread {
self.timer_event_chan.clone(),
);
- let origin = if final_url.as_str() == "about:blank" {
+ let origin = if final_url.as_str() == "about:blank" || final_url.as_str() == "about:srcdoc"
+ {
incomplete.origin.clone()
} else {
MutableOrigin::new(final_url.origin())
@@ -3838,6 +3841,25 @@ impl ScriptThread {
context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
}
+ /// Synchronously parse a srcdoc document from a giving HTML string.
+ fn page_load_about_srcdoc(&self, incomplete: InProgressLoad, src_doc: String) {
+ let id = incomplete.pipeline_id;
+
+ self.incomplete_loads.borrow_mut().push(incomplete);
+
+ let url = ServoUrl::parse("about:srcdoc").unwrap();
+ let mut context = ParserContext::new(id, url.clone());
+
+ let mut meta = Metadata::default(url);
+ meta.set_content_type(Some(&mime::TEXT_HTML));
+
+ let chunk = src_doc.into_bytes();
+
+ context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
+ context.process_response_chunk(chunk);
+ context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
+ }
+
fn handle_css_error_reporting(
&self,
pipeline_id: PipelineId,