diff options
author | ecoal95 <ecoal95@gmail.com> | 2015-05-25 14:47:23 +0200 |
---|---|---|
committer | ecoal95 <ecoal95@gmail.com> | 2015-06-01 15:29:38 +0200 |
commit | b3ac3467494377569997126103005382793d8081 (patch) | |
tree | eb0117a3dd980e6ff8b8657ecbab176faf229cb5 /components/script/dom | |
parent | b1a773a15bd2e022aa45c3672e51467e994badfe (diff) | |
download | servo-b3ac3467494377569997126103005382793d8081.tar.gz servo-b3ac3467494377569997126103005382793d8081.zip |
Add WebGLContextAttributes support
This commit also:
* Allows to return non-rootable dictionaries from
Codegen.
* Merges the two context types in an enum type.
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 29 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 24 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 6 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 160 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 36 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLCanvasElement.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGLRenderingContext.webidl | 2 |
7 files changed, 187 insertions, 72 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index d44db4078b4..9f965a9c7e8 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1165,6 +1165,15 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): return CGGeneric("*mut JSObject") if returnType.isSequence(): raise TypeError("We don't support sequence return values") + if returnType.isDictionary(): + nullable = returnType.nullable() + dictName = returnType.inner.name if nullable else returnType.name + result = CGGeneric(dictName) + if typeNeedsRooting(returnType, descriptorProvider): + raise TypeError("We don't support rootable dictionaries return values") + if nullable: + result = CGWrapper(result, pre="Option<", post=">") + return result raise TypeError("Don't know how to declare return value for %s" % returnType) @@ -4517,7 +4526,14 @@ class CGDictionary(CGThing): conversion = self.getMemberConversion(memberInfo) return CGGeneric("%s: %s,\n" % (name, conversion.define())) + def memberInsert(memberInfo): + member, _ = memberInfo + name = self.makeMemberName(member.identifier.name) + insertion = ("set_dictionary_property(cx, obj, \"%s\", &mut self.%s.to_jsval(cx)).unwrap();" % (name, name)) + return CGGeneric("%s\n" % insertion) + memberInits = CGList([memberInit(m) for m in self.memberInfo]) + memberInserts = CGList([memberInsert(m) for m in self.memberInfo]) return string.Template( "impl ${selfName} {\n" @@ -4538,10 +4554,19 @@ class CGDictionary(CGThing): "${initMembers}" " })\n" " }\n" - "}").substitute({ + "}\n" + "\n" + "impl ToJSValConvertible for ${selfName} {\n" + " fn to_jsval(&self, cx: *mut JSContext) -> JSVal {\n" + " let obj = unsafe { JS_NewObject(cx, 0 as *const JSClass, 0 as *const JSObject, 0 as *const JSObject) };\n" + "${insertMembers}" + " ObjectOrNullValue(obj)\n" + " }\n" + "}\n").substitute({ "selfName": self.makeClassName(d), "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(), "initMembers": CGIndenter(memberInits, indentLevel=12).define(), + "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(), }) @staticmethod @@ -4590,6 +4615,7 @@ class CGDictionary(CGThing): return CGGeneric(conversion) + @staticmethod def makeIdName(name): return name + "_id" @@ -4750,6 +4776,7 @@ class CGBindingRoot(CGThing): 'dom::bindings::utils::{Reflectable}', 'dom::bindings::utils::throwing_constructor', 'dom::bindings::utils::get_dictionary_property', + 'dom::bindings::utils::set_dictionary_property', 'dom::bindings::utils::{NativeProperties, NativePropertyHooks}', 'dom::bindings::utils::ConstantVal::{IntVal, UintVal}', 'dom::bindings::utils::NonNullJSNative', diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 612cba46f35..f53451352cc 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -29,7 +29,7 @@ use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAn use js::jsapi::JSHandleObject; use js::jsapi::JS_GetFunctionObject; use js::jsapi::{JS_HasPropertyById, JS_GetPrototype}; -use js::jsapi::{JS_GetProperty, JS_HasProperty}; +use js::jsapi::{JS_GetProperty, JS_HasProperty, JS_SetProperty}; use js::jsapi::{JS_DefineFunctions, JS_DefineProperty}; use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot}; use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass}; @@ -510,7 +510,6 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool { pub fn get_dictionary_property(cx: *mut JSContext, object: *mut JSObject, property: &str) -> Result<Option<JSVal>, ()> { - use std::ffi::CString; fn has_property(cx: *mut JSContext, object: *mut JSObject, property: &CString, found: &mut JSBool) -> bool { unsafe { @@ -546,6 +545,27 @@ pub fn get_dictionary_property(cx: *mut JSContext, Ok(Some(value)) } +/// Set the property with name `property` from `object`. +/// Returns `Err(())` on JSAPI failure, or null object, +/// and Ok(()) otherwise +pub fn set_dictionary_property(cx: *mut JSContext, + object: *mut JSObject, + property: &str, + value: &mut JSVal) -> Result<(), ()> { + if object.is_null() { + return Err(()); + } + + let property = CString::new(property).unwrap(); + unsafe { + if JS_SetProperty(cx, object, property.as_ptr(), value) == 0 { + return Err(()); + } + } + + Ok(()) +} + /// Returns whether `proxy` has a property `id` on its prototype. pub fn has_property_on_prototype(cx: *mut JSContext, proxy: *mut JSObject, id: jsid) -> bool { diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 7ddce7791c9..b1961188e1e 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -214,7 +214,11 @@ impl CanvasRenderingContext2D { let msg = if self.canvas.root().r() == canvas { CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled)) } else { // Source and target canvases are different - let context = canvas.get_2d_context().root(); + let context = match canvas.get_or_init_2d_context() { + Some(context) => context.root(), + None => return Err(InvalidState), + }; + let renderer = context.r().get_renderer(); let (sender, receiver) = channel::<Vec<u8>>(); // Reads pixels from source image diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 3a4d7c15d18..0b2456f3f54 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -10,8 +10,9 @@ use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElemen use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext; +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, JSRef, LayoutJS, MutNullableHeap, Rootable}; +use dom::bindings::js::{JS, JSRef, LayoutJS, MutNullableHeap, HeapGCValue, Rootable}; use dom::bindings::js::Temporary; use dom::bindings::js::Unrooted; use dom::bindings::utils::{Reflectable}; @@ -26,6 +27,9 @@ use dom::virtualmethods::VirtualMethods; use dom::webglrenderingcontext::{WebGLRenderingContext, LayoutCanvasWebGLRenderingContextHelpers}; use util::str::{DOMString, parse_unsigned_integer}; +use js::jsapi::{JSContext}; +use js::jsval::JSVal; +use offscreen_gl_context::GLContextAttributes; use geom::size::Size2D; @@ -36,11 +40,20 @@ use std::sync::mpsc::Sender; const DEFAULT_WIDTH: u32 = 300; const DEFAULT_HEIGHT: u32 = 150; +#[jstraceable] +#[must_root] +#[derive(Clone, Copy)] +pub enum CanvasContext { + Context2d(JS<CanvasRenderingContext2D>), + WebGL(JS<WebGLRenderingContext>), +} + +impl HeapGCValue for CanvasContext {} + #[dom_struct] pub struct HTMLCanvasElement { htmlelement: HTMLElement, - context_2d: MutNullableHeap<JS<CanvasRenderingContext2D>>, - context_webgl: MutNullableHeap<JS<WebGLRenderingContext>>, + context: MutNullableHeap<CanvasContext>, width: Cell<u32>, height: Cell<u32>, } @@ -60,8 +73,7 @@ impl HTMLCanvasElement { HTMLCanvasElement { htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLCanvasElement, localName, prefix, document), - context_2d: Default::default(), - context_webgl: Default::default(), + context: Default::default(), width: Cell::new(DEFAULT_WIDTH), height: Cell::new(DEFAULT_HEIGHT), } @@ -77,11 +89,11 @@ impl HTMLCanvasElement { fn recreate_contexts(&self) { let size = self.get_size(); - if let Some(context) = self.context_2d.get() { - context.root().r().recreate(size) - } - if let Some(context) = self.context_webgl.get() { - context.root().r().recreate(size) + if let Some(context) = self.context.get() { + match context { + CanvasContext::Context2d(context) => context.root().r().recreate(size), + CanvasContext::WebGL(context) => context.root().r().recreate(size), + } } } @@ -103,12 +115,13 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> { #[allow(unsafe_code)] unsafe fn get_renderer(&self) -> Option<Sender<CanvasMsg>> { let ref canvas = *self.unsafe_get(); - if canvas.context_2d.get().is_some() { - let context = canvas.context_2d.get_inner_as_layout(); - context.map(|cx| cx.get_renderer()) - } else if canvas.context_webgl.get().is_some() { - let context = canvas.context_webgl.get_inner_as_layout(); - context.map(|cx| cx.get_renderer()) + if let Some(context) = canvas.context.get() { + match context { + CanvasContext::Context2d(context) + => Some(context.to_layout().get_renderer()), + CanvasContext::WebGL(context) + => Some(context.to_layout().get_renderer()), + } } else { None } @@ -126,29 +139,58 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> { } pub trait HTMLCanvasElementHelpers { - fn get_2d_context(self) -> Temporary<CanvasRenderingContext2D>; - fn get_webgl_context(self) -> Temporary<WebGLRenderingContext>; + fn get_or_init_2d_context(self) -> Option<Temporary<CanvasRenderingContext2D>>; + fn get_or_init_webgl_context(self, + cx: *mut JSContext, + attrs: Option<&JSVal>) -> Option<Temporary<WebGLRenderingContext>>; fn is_valid(self) -> bool; } impl<'a> HTMLCanvasElementHelpers for JSRef<'a, HTMLCanvasElement> { - fn get_2d_context(self) -> Temporary<CanvasRenderingContext2D> { - let context = self.GetContext(String::from_str("2d")); - match context.unwrap() { - CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D(context) => { - Temporary::from_unrooted(context) - } - _ => panic!("Wrong Context Type: Expected 2d context"), + fn get_or_init_2d_context(self) -> Option<Temporary<CanvasRenderingContext2D>> { + if self.context.get().is_none() { + let window = window_from_node(self).root(); + let size = self.get_size(); + let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size); + self.context.set(Some(CanvasContext::Context2d(JS::from_rooted(context)))); + } + + match self.context.get().unwrap() { + CanvasContext::Context2d(context) => Some(Temporary::from_rooted(context)), + _ => None, } } - fn get_webgl_context(self) -> Temporary<WebGLRenderingContext> { - let context = self.GetContext(String::from_str("webgl")); - match context.unwrap() { - CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext(context) => { - Temporary::from_unrooted(context) - }, - _ => panic!("Wrong Context Type: Expected webgl context"), + fn get_or_init_webgl_context(self, + cx: *mut JSContext, + attrs: Option<&JSVal>) -> Option<Temporary<WebGLRenderingContext>> { + if self.context.get().is_none() { + let window = window_from_node(self).root(); + let size = self.get_size(); + + let attrs = if let Some(webgl_attributes) = attrs { + if let Ok(ref attrs) = WebGLContextAttributes::new(cx, *webgl_attributes) { + From::from(attrs) + } else { + debug!("Unexpected error on conversion of WebGLContextAttributes"); + return None; + } + } else { + GLContextAttributes::default() + }; + + let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs); + + self.context.set(maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(ctx)))); + } + + if let Some(context) = self.context.get() { + match context { + CanvasContext::WebGL(context) => Some(Temporary::from_rooted(context)), + _ => None, + } + } else { + None } } @@ -176,39 +218,21 @@ impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> { elem.set_uint_attribute(&atom!("height"), height) } - fn GetContext(self, id: DOMString) -> Option<CanvasRenderingContext2DOrWebGLRenderingContext> { + fn GetContext(self, + cx: *mut JSContext, + id: DOMString, + attributes: Vec<JSVal>) + -> Option<CanvasRenderingContext2DOrWebGLRenderingContext> { match &*id { "2d" => { - if self.context_webgl.get().is_some() { - debug!("Trying to get a 2d context for a canvas with an already initialized WebGL context"); - return None; - } - - let context_2d = self.context_2d.or_init(|| { - let window = window_from_node(self).root(); - let size = self.get_size(); - CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size) - }); - Some( - CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D( - Unrooted::from_temporary(context_2d))) + self.get_or_init_2d_context() + .map(|ctx| CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D( + Unrooted::from_temporary(ctx))) } "webgl" | "experimental-webgl" => { - if self.context_2d.get().is_some() { - debug!("Trying to get a WebGL context for a canvas with an already initialized 2d context"); - return None; - } - - if !self.context_webgl.get().is_some() { - let window = window_from_node(self).root(); - let size = self.get_size(); - - self.context_webgl.set( - WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size).map(JS::from_rooted)) - } - - self.context_webgl.get().map( |ctx| - CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext(Unrooted::from_js(ctx))) + self.get_or_init_webgl_context(cx, attributes.get(0)) + .map(|ctx| CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext( + Unrooted::from_temporary(ctx))) } _ => None } @@ -266,3 +290,17 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLCanvasElement> { } } } + +impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes { + fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes { + GLContextAttributes { + alpha: attrs.alpha, + depth: attrs.depth, + stencil: attrs.stencil, + antialias: attrs.antialias, + premultiplied_alpha: attrs.premultipliedAlpha, + preserve_drawing_buffer: attrs.preserveDrawingBuffer, + } + } +} + diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index ee64fe73de0..462c3859d17 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -6,7 +6,7 @@ use canvas::webgl_paint_task::WebGLPaintTask; use canvas_traits::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{ - WebGLRenderingContextMethods, WebGLRenderingContextConstants}; + WebGLContextAttributes, WebGLRenderingContextMethods, WebGLRenderingContextConstants}; use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; @@ -23,6 +23,7 @@ use std::mem; use std::ptr; use std::sync::mpsc::{channel, Sender}; use util::str::DOMString; +use offscreen_gl_context::GLContextAttributes; #[dom_struct] pub struct WebGLRenderingContext { @@ -33,9 +34,12 @@ pub struct WebGLRenderingContext { } impl WebGLRenderingContext { - fn new_inherited(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>) + fn new_inherited(global: GlobalRef, + canvas: JSRef<HTMLCanvasElement>, + size: Size2D<i32>, + attrs: GLContextAttributes) -> Result<WebGLRenderingContext, &'static str> { - let chan = try!(WebGLPaintTask::start(size)); + let chan = try!(WebGLPaintTask::start(size, attrs)); Ok(WebGLRenderingContext { reflector_: Reflector::new(), @@ -45,9 +49,9 @@ impl WebGLRenderingContext { }) } - pub fn new(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>) + pub fn new(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>, attrs: GLContextAttributes) -> Option<Temporary<WebGLRenderingContext>> { - match WebGLRenderingContext::new_inherited(global, canvas, size) { + match WebGLRenderingContext::new_inherited(global, canvas, size, attrs) { Ok(ctx) => Some(reflect_dom_object(box ctx, global, WebGLRenderingContextBinding::Wrap)), Err(msg) => { @@ -69,6 +73,28 @@ impl Drop for WebGLRenderingContext { } impl<'a> WebGLRenderingContextMethods for JSRef<'a, WebGLRenderingContext> { + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.2 + fn GetContextAttributes(self) -> Option<WebGLContextAttributes> { + let (sender, receiver) = channel(); + + // If the send does not succeed, assume context lost + if let Err(_) = self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetContextAttributes(sender))) { + return None; + } + let attrs = receiver.recv().unwrap(); + + Some(WebGLContextAttributes { + alpha: attrs.alpha, + antialias: attrs.antialias, + depth: attrs.depth, + failIfMajorPerformanceCaveat: false, + preferLowPowerToHighPerformance: false, + premultipliedAlpha: attrs.premultiplied_alpha, + preserveDrawingBuffer: attrs.preserve_drawing_buffer, + stencil: attrs.stencil + }) + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 fn AttachShader(self, program: Option<JSRef<WebGLProgram>>, shader: Option<JSRef<WebGLShader>>) { let program_id = match program { diff --git a/components/script/dom/webidls/HTMLCanvasElement.webidl b/components/script/dom/webidls/HTMLCanvasElement.webidl index 882e3f031c7..cb2bea70d76 100644 --- a/components/script/dom/webidls/HTMLCanvasElement.webidl +++ b/components/script/dom/webidls/HTMLCanvasElement.webidl @@ -12,7 +12,7 @@ interface HTMLCanvasElement : HTMLElement { [Pure] attribute unsigned long height; - RenderingContext? getContext(DOMString contextId); + RenderingContext? getContext(DOMString contextId, any... arguments); //boolean probablySupportsContext(DOMString contextId, any... arguments); //void setContext(RenderingContext context); diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 0aeb3077ee5..9409d1500d8 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -481,7 +481,7 @@ interface WebGLRenderingContextBase //readonly attribute GLsizei drawingBufferWidth; //readonly attribute GLsizei drawingBufferHeight; - //[WebGLHandlesContextLoss] WebGLContextAttributes? getContextAttributes(); + [WebGLHandlesContextLoss] WebGLContextAttributes? getContextAttributes(); //[WebGLHandlesContextLoss] boolean isContextLost(); //sequence<DOMString>? getSupportedExtensions(); |