Skip to main content

script/dom/webgl/extensions/
wrapper.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::ptr::NonNull;
6
7use js::context::JSContext;
8use js::jsapi::JSObject;
9use malloc_size_of::MallocSizeOf;
10use script_bindings::reflector::DomObject;
11
12use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions};
13use crate::dom::bindings::root::MutNullableDom;
14use crate::dom::bindings::trace::JSTraceable;
15use crate::dom::webgl::webglrenderingcontext::WebGLRenderingContext;
16
17/// Trait used internally by WebGLExtensions to store and
18/// handle the different WebGL extensions in a common list.
19pub(crate) trait WebGLExtensionWrapper: JSTraceable + MallocSizeOf {
20    fn instance_or_init(
21        &self,
22        cx: &mut JSContext,
23        ctx: &WebGLRenderingContext,
24        ext: &WebGLExtensions,
25    ) -> NonNull<JSObject>;
26    fn spec(&self) -> WebGLExtensionSpec;
27    fn is_supported(&self, _: &WebGLExtensions) -> bool;
28    fn is_enabled(&self) -> bool;
29    fn enable(&self, ext: &WebGLExtensions);
30    fn name(&self) -> &'static str;
31}
32
33#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
34#[derive(JSTraceable, MallocSizeOf)]
35pub(crate) struct TypedWebGLExtensionWrapper<T: WebGLExtension> {
36    extension: MutNullableDom<T::Extension>,
37}
38
39/// Typed WebGL Extension implementation.
40/// Exposes the exact `MutNullableDom<DOMObject>` type defined by the extension.
41impl<T: WebGLExtension> TypedWebGLExtensionWrapper<T> {
42    pub(crate) fn new() -> TypedWebGLExtensionWrapper<T> {
43        TypedWebGLExtensionWrapper {
44            extension: MutNullableDom::new(None),
45        }
46    }
47}
48
49impl<T> WebGLExtensionWrapper for TypedWebGLExtensionWrapper<T>
50where
51    T: WebGLExtension + JSTraceable + MallocSizeOf + 'static,
52{
53    #[expect(unsafe_code)]
54    fn instance_or_init(
55        &self,
56        cx: &mut JSContext,
57        ctx: &WebGLRenderingContext,
58        ext: &WebGLExtensions,
59    ) -> NonNull<JSObject> {
60        let mut enabled = true;
61        let extension = self.extension.or_init(|| {
62            enabled = false;
63            T::new(cx, ctx)
64        });
65        if !enabled {
66            self.enable(ext);
67        }
68        unsafe { NonNull::new_unchecked(extension.reflector().get_jsobject().get()) }
69    }
70
71    fn spec(&self) -> WebGLExtensionSpec {
72        T::spec()
73    }
74
75    fn is_supported(&self, ext: &WebGLExtensions) -> bool {
76        self.is_enabled() || T::is_supported(ext)
77    }
78
79    fn is_enabled(&self) -> bool {
80        self.extension.get().is_some()
81    }
82
83    fn enable(&self, ext: &WebGLExtensions) {
84        T::enable(ext);
85    }
86
87    fn name(&self) -> &'static str {
88        T::name()
89    }
90}