/* 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 http://mozilla.org/MPL/2.0/. */ use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::MutNullableDom; use crate::dom::bindings::trace::JSTraceable; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use js::jsapi::JSObject; use malloc_size_of::MallocSizeOf; use std::any::Any; use std::ptr::NonNull; /// Trait used internally by WebGLExtensions to store and /// handle the different WebGL extensions in a common list. pub trait WebGLExtensionWrapper: JSTraceable + MallocSizeOf { fn instance_or_init( &self, ctx: &WebGLRenderingContext, ext: &WebGLExtensions, ) -> NonNull; fn spec(&self) -> WebGLExtensionSpec; fn is_supported(&self, _: &WebGLExtensions) -> bool; fn is_enabled(&self) -> bool; fn enable(&self, ext: &WebGLExtensions); fn name(&self) -> &'static str; fn as_any(&self) -> &Any; } #[must_root] #[derive(JSTraceable, MallocSizeOf)] pub struct TypedWebGLExtensionWrapper { extension: MutNullableDom, } /// Typed WebGL Extension implementation. /// Exposes the exact MutNullableDom type defined by the extension. impl TypedWebGLExtensionWrapper { pub fn new() -> TypedWebGLExtensionWrapper { TypedWebGLExtensionWrapper { extension: MutNullableDom::new(None), } } } impl WebGLExtensionWrapper for TypedWebGLExtensionWrapper where T: WebGLExtension + JSTraceable + MallocSizeOf + 'static, { #[allow(unsafe_code)] fn instance_or_init( &self, ctx: &WebGLRenderingContext, ext: &WebGLExtensions, ) -> NonNull { let mut enabled = true; let extension = self.extension.or_init(|| { enabled = false; T::new(ctx) }); if !enabled { self.enable(ext); } unsafe { NonNull::new_unchecked(extension.reflector().get_jsobject().get()) } } fn spec(&self) -> WebGLExtensionSpec { T::spec() } fn is_supported(&self, ext: &WebGLExtensions) -> bool { self.is_enabled() || T::is_supported(ext) } fn is_enabled(&self) -> bool { self.extension.get().is_some() } fn enable(&self, ext: &WebGLExtensions) { T::enable(ext); } fn name(&self) -> &'static str { T::name() } fn as_any<'a>(&'a self) -> &'a Any { self } }