aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorecoal95 <ecoal95@gmail.com>2015-05-25 14:47:23 +0200
committerecoal95 <ecoal95@gmail.com>2015-06-01 15:29:38 +0200
commitb3ac3467494377569997126103005382793d8081 (patch)
treeeb0117a3dd980e6ff8b8657ecbab176faf229cb5 /components/script/dom
parentb1a773a15bd2e022aa45c3672e51467e994badfe (diff)
downloadservo-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.py29
-rw-r--r--components/script/dom/bindings/utils.rs24
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs6
-rw-r--r--components/script/dom/htmlcanvaselement.rs160
-rw-r--r--components/script/dom/webglrenderingcontext.rs36
-rw-r--r--components/script/dom/webidls/HTMLCanvasElement.webidl2
-rw-r--r--components/script/dom/webidls/WebGLRenderingContext.webidl2
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();