script/dom/webgl/
webgl2renderingcontext.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::cell::Cell;
6use std::cmp;
7use std::ptr::{self, NonNull};
8#[cfg(feature = "webxr")]
9use std::rc::Rc;
10
11use bitflags::bitflags;
12use canvas_traits::webgl::WebGLError::*;
13use canvas_traits::webgl::{
14    AlphaTreatment, GLContextAttributes, InternalFormatParameter, TexDataType, TexFormat,
15    WebGLCommand, WebGLContextId, WebGLResult, WebGLVersion, YAxisTreatment, webgl_channel,
16};
17use dom_struct::dom_struct;
18use euclid::default::{Point2D, Rect, Size2D};
19use ipc_channel::ipc::{self, IpcSharedMemory};
20use js::jsapi::{JSObject, Type};
21use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
22use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue};
23use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
24use pixels::{Alpha, Snapshot};
25use script_bindings::conversions::SafeToJSValConvertible;
26use script_bindings::interfaces::WebGL2RenderingContextHelpers;
27use servo_config::pref;
28use url::Host;
29use webrender_api::ImageKey;
30
31use super::validations::types::TexImageTarget;
32use crate::canvas_context::{CanvasContext, LayoutCanvasRenderingContextHelpers};
33use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
34    WebGL2RenderingContextConstants as constants, WebGL2RenderingContextMethods,
35};
36use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{
37    TexImageSource, WebGLContextAttributes, WebGLRenderingContextMethods,
38};
39use crate::dom::bindings::codegen::UnionTypes::{
40    ArrayBufferViewOrArrayBuffer, Float32ArrayOrUnrestrictedFloatSequence,
41    HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas,
42    Int32ArrayOrLongSequence, Uint32ArrayOrUnsignedLongSequence,
43};
44use crate::dom::bindings::error::{ErrorResult, Fallible};
45use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
46use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
47use crate::dom::bindings::str::DOMString;
48use crate::dom::globalscope::GlobalScope;
49#[cfg(feature = "webxr")]
50use crate::dom::promise::Promise;
51use crate::dom::webgl::validations::WebGLValidator;
52use crate::dom::webgl::validations::tex_image_2d::{
53    TexImage2DValidator, TexImage2DValidatorResult, TexStorageValidator, TexStorageValidatorResult,
54};
55use crate::dom::webgl::validations::tex_image_3d::{
56    TexImage3DValidator, TexImage3DValidatorResult,
57};
58use crate::dom::webgl::webglactiveinfo::WebGLActiveInfo;
59use crate::dom::webgl::webglbuffer::WebGLBuffer;
60use crate::dom::webgl::webglframebuffer::{WebGLFramebuffer, WebGLFramebufferAttachmentRoot};
61use crate::dom::webgl::webglprogram::WebGLProgram;
62use crate::dom::webgl::webglquery::WebGLQuery;
63use crate::dom::webgl::webglrenderbuffer::WebGLRenderbuffer;
64use crate::dom::webgl::webglrenderingcontext::{
65    Operation, TexPixels, TexSource, VertexAttrib, WebGLRenderingContext, uniform_get,
66    uniform_typed,
67};
68use crate::dom::webgl::webglsampler::{WebGLSampler, WebGLSamplerValue};
69use crate::dom::webgl::webglshader::WebGLShader;
70use crate::dom::webgl::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
71use crate::dom::webgl::webglsync::WebGLSync;
72use crate::dom::webgl::webgltexture::WebGLTexture;
73use crate::dom::webgl::webgltransformfeedback::WebGLTransformFeedback;
74use crate::dom::webgl::webgluniformlocation::WebGLUniformLocation;
75use crate::dom::webgl::webglvertexarrayobject::WebGLVertexArrayObject;
76use crate::dom::window::Window;
77use crate::script_runtime::{CanGc, JSContext};
78
79#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
80#[derive(JSTraceable, MallocSizeOf)]
81struct IndexedBinding {
82    buffer: MutNullableDom<WebGLBuffer>,
83    start: Cell<i64>,
84    size: Cell<i64>,
85}
86
87impl IndexedBinding {
88    fn new() -> IndexedBinding {
89        IndexedBinding {
90            buffer: MutNullableDom::new(None),
91            start: Cell::new(0),
92            size: Cell::new(0),
93        }
94    }
95}
96
97#[dom_struct]
98pub(crate) struct WebGL2RenderingContext {
99    reflector_: Reflector,
100    base: Dom<WebGLRenderingContext>,
101    occlusion_query: MutNullableDom<WebGLQuery>,
102    primitives_query: MutNullableDom<WebGLQuery>,
103    samplers: Box<[MutNullableDom<WebGLSampler>]>,
104    bound_copy_read_buffer: MutNullableDom<WebGLBuffer>,
105    bound_copy_write_buffer: MutNullableDom<WebGLBuffer>,
106    bound_pixel_pack_buffer: MutNullableDom<WebGLBuffer>,
107    bound_pixel_unpack_buffer: MutNullableDom<WebGLBuffer>,
108    bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
109    bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
110    indexed_uniform_buffer_bindings: Box<[IndexedBinding]>,
111    indexed_transform_feedback_buffer_bindings: Box<[IndexedBinding]>,
112    current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
113    texture_pack_row_length: Cell<usize>,
114    texture_pack_skip_pixels: Cell<usize>,
115    texture_pack_skip_rows: Cell<usize>,
116    enable_rasterizer_discard: Cell<bool>,
117    default_fb_readbuffer: Cell<u32>,
118    default_fb_drawbuffer: Cell<u32>,
119}
120
121struct ReadPixelsAllowedFormats<'a> {
122    array_types: &'a [Type],
123    channels: usize,
124}
125
126struct ReadPixelsSizes {
127    row_stride: usize,
128    skipped_bytes: usize,
129    size: usize,
130}
131
132impl WebGL2RenderingContext {
133    fn new_inherited(
134        window: &Window,
135        canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
136        size: Size2D<u32>,
137        attrs: GLContextAttributes,
138        can_gc: CanGc,
139    ) -> Option<WebGL2RenderingContext> {
140        let base =
141            WebGLRenderingContext::new(window, canvas, WebGLVersion::WebGL2, size, attrs, can_gc)?;
142
143        let samplers = (0..base.limits().max_combined_texture_image_units)
144            .map(|_| Default::default())
145            .collect::<Vec<_>>()
146            .into();
147        let indexed_uniform_buffer_bindings = (0..base.limits().max_uniform_buffer_bindings)
148            .map(|_| IndexedBinding::new())
149            .collect::<Vec<_>>()
150            .into();
151        let indexed_transform_feedback_buffer_bindings =
152            (0..base.limits().max_transform_feedback_separate_attribs)
153                .map(|_| IndexedBinding::new())
154                .collect::<Vec<_>>()
155                .into();
156
157        Some(WebGL2RenderingContext {
158            reflector_: Reflector::new(),
159            base: Dom::from_ref(&*base),
160            occlusion_query: MutNullableDom::new(None),
161            primitives_query: MutNullableDom::new(None),
162            samplers,
163            bound_copy_read_buffer: MutNullableDom::new(None),
164            bound_copy_write_buffer: MutNullableDom::new(None),
165            bound_pixel_pack_buffer: MutNullableDom::new(None),
166            bound_pixel_unpack_buffer: MutNullableDom::new(None),
167            bound_transform_feedback_buffer: MutNullableDom::new(None),
168            bound_uniform_buffer: MutNullableDom::new(None),
169            indexed_uniform_buffer_bindings,
170            indexed_transform_feedback_buffer_bindings,
171            current_transform_feedback: MutNullableDom::new(None),
172            texture_pack_row_length: Cell::new(0),
173            texture_pack_skip_pixels: Cell::new(0),
174            texture_pack_skip_rows: Cell::new(0),
175            enable_rasterizer_discard: Cell::new(false),
176            default_fb_readbuffer: Cell::new(constants::BACK),
177            default_fb_drawbuffer: Cell::new(constants::BACK),
178        })
179    }
180
181    pub(crate) fn new(
182        window: &Window,
183        canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
184        size: Size2D<u32>,
185        attrs: GLContextAttributes,
186        can_gc: CanGc,
187    ) -> Option<DomRoot<WebGL2RenderingContext>> {
188        WebGL2RenderingContext::new_inherited(window, canvas, size, attrs, can_gc)
189            .map(|ctx| reflect_dom_object(Box::new(ctx), window, can_gc))
190    }
191
192    #[allow(unsafe_code)]
193    pub(crate) fn is_webgl2_enabled(_cx: JSContext, global: HandleObject) -> bool {
194        if pref!(dom_webgl2_enabled) {
195            return true;
196        }
197
198        let global = unsafe { GlobalScope::from_object(global.get()) };
199        let origin = global.origin();
200        let host = origin.host();
201        WEBGL2_ORIGINS
202            .iter()
203            .any(|origin| host == Host::parse(origin).ok().as_ref())
204    }
205}
206
207/// List of domains for which WebGL 2 is enabled automatically, regardless
208/// of the status of the dom.webgl2.enabled preference.
209static WEBGL2_ORIGINS: &[&str] = &["www.servoexperiments.com"];
210
211impl WebGL2RenderingContext {
212    pub(crate) fn current_vao(&self) -> DomRoot<WebGLVertexArrayObject> {
213        self.base.current_vao_webgl2()
214    }
215
216    pub(crate) fn validate_uniform_block_for_draw(&self) {
217        let program = match self.base.current_program() {
218            Some(program) => program,
219            None => return,
220        };
221        for uniform_block in program.active_uniform_blocks().iter() {
222            let data_size = uniform_block.size as usize;
223            for block in program.active_uniforms().iter() {
224                let index = match block.bind_index {
225                    Some(index) => index,
226                    None => continue,
227                };
228                let indexed = &self.indexed_uniform_buffer_bindings[index as usize];
229                let buffer = match indexed.buffer.get() {
230                    Some(buffer) => buffer,
231                    None => {
232                        self.base.webgl_error(InvalidOperation);
233                        return;
234                    },
235                };
236                if indexed.size.get() == 0 {
237                    if data_size > buffer.capacity() {
238                        self.base.webgl_error(InvalidOperation);
239                        return;
240                    }
241                } else {
242                    let start = indexed.start.get() as usize;
243                    let mut size = indexed.size.get() as usize;
244                    if start >= size {
245                        self.base.webgl_error(InvalidOperation);
246                        return;
247                    }
248                    size -= start;
249                    if data_size > size {
250                        self.base.webgl_error(InvalidOperation);
251                        return;
252                    }
253                }
254            }
255        }
256    }
257
258    fn validate_vertex_attribs_for_draw(&self) {
259        let program = match self.base.current_program() {
260            Some(program) => program,
261            None => return,
262        };
263        let groups = [
264            [
265                constants::INT,
266                constants::INT_VEC2,
267                constants::INT_VEC3,
268                constants::INT_VEC4,
269            ],
270            [
271                constants::UNSIGNED_INT,
272                constants::UNSIGNED_INT_VEC2,
273                constants::UNSIGNED_INT_VEC3,
274                constants::UNSIGNED_INT_VEC4,
275            ],
276            [
277                constants::FLOAT,
278                constants::FLOAT_VEC2,
279                constants::FLOAT_VEC3,
280                constants::FLOAT_VEC4,
281            ],
282        ];
283        let vao = self.current_vao();
284        for prog_attrib in program.active_attribs().iter() {
285            let attrib = handle_potential_webgl_error!(
286                self.base,
287                // TODO(#34300): remove unwrap
288                vao.get_vertex_attrib(prog_attrib.location.unwrap_or(u32::MAX))
289                    .ok_or(InvalidOperation),
290                return
291            );
292
293            // TODO(#34300): remove unwrap
294            let current_vertex_attrib = self.base.current_vertex_attribs()[prog_attrib
295                .location
296                .map(|l| l as usize)
297                .unwrap_or(usize::MAX)];
298            let attrib_data_base_type = if !attrib.enabled_as_array {
299                match current_vertex_attrib {
300                    VertexAttrib::Int(_, _, _, _) => constants::INT,
301                    VertexAttrib::Uint(_, _, _, _) => constants::UNSIGNED_INT,
302                    VertexAttrib::Float(_, _, _, _) => constants::FLOAT,
303                }
304            } else {
305                attrib.type_
306            };
307
308            let contains = groups
309                .iter()
310                .find(|g| g.contains(&attrib_data_base_type) && g.contains(&prog_attrib.type_));
311            if contains.is_none() {
312                self.base.webgl_error(InvalidOperation);
313                return;
314            }
315        }
316    }
317
318    pub(crate) fn base_context(&self) -> DomRoot<WebGLRenderingContext> {
319        DomRoot::from_ref(&*self.base)
320    }
321
322    fn bound_buffer(&self, target: u32) -> WebGLResult<Option<DomRoot<WebGLBuffer>>> {
323        match target {
324            constants::COPY_READ_BUFFER => Ok(self.bound_copy_read_buffer.get()),
325            constants::COPY_WRITE_BUFFER => Ok(self.bound_copy_write_buffer.get()),
326            constants::PIXEL_PACK_BUFFER => Ok(self.bound_pixel_pack_buffer.get()),
327            constants::PIXEL_UNPACK_BUFFER => Ok(self.bound_pixel_unpack_buffer.get()),
328            constants::TRANSFORM_FEEDBACK_BUFFER => Ok(self.bound_transform_feedback_buffer.get()),
329            constants::UNIFORM_BUFFER => Ok(self.bound_uniform_buffer.get()),
330            constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
331            _ => self.base.bound_buffer(target),
332        }
333    }
334
335    pub(crate) fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
336        match usage {
337            constants::STATIC_READ |
338            constants::DYNAMIC_READ |
339            constants::STREAM_READ |
340            constants::STATIC_COPY |
341            constants::DYNAMIC_COPY |
342            constants::STREAM_COPY => Ok(usage),
343            _ => self.base.buffer_usage(usage),
344        }
345    }
346
347    fn unbind_from(&self, slot: &MutNullableDom<WebGLBuffer>, buffer: &WebGLBuffer) {
348        if slot.get().is_some_and(|b| buffer == &*b) {
349            buffer.decrement_attached_counter(Operation::Infallible);
350            slot.set(None);
351        }
352    }
353
354    fn calc_read_pixel_formats(
355        &self,
356        pixel_type: u32,
357        format: u32,
358    ) -> WebGLResult<ReadPixelsAllowedFormats<'_>> {
359        let array_types = match pixel_type {
360            constants::BYTE => &[Type::Int8][..],
361            constants::SHORT => &[Type::Int16][..],
362            constants::INT => &[Type::Int32][..],
363            constants::UNSIGNED_BYTE => &[Type::Uint8, Type::Uint8Clamped][..],
364            constants::UNSIGNED_SHORT |
365            constants::UNSIGNED_SHORT_4_4_4_4 |
366            constants::UNSIGNED_SHORT_5_5_5_1 |
367            constants::UNSIGNED_SHORT_5_6_5 => &[Type::Uint16][..],
368            constants::UNSIGNED_INT |
369            constants::UNSIGNED_INT_2_10_10_10_REV |
370            constants::UNSIGNED_INT_10F_11F_11F_REV |
371            constants::UNSIGNED_INT_5_9_9_9_REV => &[Type::Uint32][..],
372            constants::FLOAT => &[Type::Float32][..],
373            constants::HALF_FLOAT => &[Type::Uint16][..],
374            _ => return Err(InvalidEnum),
375        };
376        let channels = match format {
377            constants::ALPHA | constants::RED | constants::RED_INTEGER => 1,
378            constants::RG | constants::RG_INTEGER => 2,
379            constants::RGB | constants::RGB_INTEGER => 3,
380            constants::RGBA | constants::RGBA_INTEGER => 4,
381            _ => return Err(InvalidEnum),
382        };
383        Ok(ReadPixelsAllowedFormats {
384            array_types,
385            channels,
386        })
387    }
388
389    fn calc_read_pixel_sizes(
390        &self,
391        width: i32,
392        height: i32,
393        bytes_per_pixel: usize,
394    ) -> WebGLResult<ReadPixelsSizes> {
395        if width < 0 || height < 0 {
396            return Err(InvalidValue);
397        }
398
399        // See also https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.36
400        let pixels_per_row = if self.texture_pack_row_length.get() > 0 {
401            self.texture_pack_row_length.get()
402        } else {
403            width as usize
404        };
405        if self.texture_pack_skip_pixels.get() + width as usize > pixels_per_row {
406            return Err(InvalidOperation);
407        }
408
409        let bytes_per_row = pixels_per_row
410            .checked_mul(bytes_per_pixel)
411            .ok_or(InvalidOperation)?;
412        let row_padding_bytes = {
413            let pack_alignment = self.base.get_texture_packing_alignment() as usize;
414            match bytes_per_row % pack_alignment {
415                0 => 0,
416                remainder => pack_alignment - remainder,
417            }
418        };
419        let row_stride = bytes_per_row + row_padding_bytes;
420        let size = if width == 0 || height == 0 {
421            0
422        } else {
423            let full_row_bytes = row_stride
424                .checked_mul(height as usize - 1)
425                .ok_or(InvalidOperation)?;
426            let last_row_bytes = bytes_per_pixel
427                .checked_mul(width as usize)
428                .ok_or(InvalidOperation)?;
429            full_row_bytes
430                .checked_add(last_row_bytes)
431                .ok_or(InvalidOperation)?
432        };
433        let skipped_bytes = {
434            let skipped_row_bytes = self
435                .texture_pack_skip_rows
436                .get()
437                .checked_mul(row_stride)
438                .ok_or(InvalidOperation)?;
439            let skipped_pixel_bytes = self
440                .texture_pack_skip_pixels
441                .get()
442                .checked_mul(bytes_per_pixel)
443                .ok_or(InvalidOperation)?;
444            skipped_row_bytes
445                .checked_add(skipped_pixel_bytes)
446                .ok_or(InvalidOperation)?
447        };
448        Ok(ReadPixelsSizes {
449            row_stride,
450            skipped_bytes,
451            size,
452        })
453    }
454
455    #[allow(unsafe_code, clippy::too_many_arguments)]
456    fn read_pixels_into(
457        &self,
458        x: i32,
459        y: i32,
460        width: i32,
461        height: i32,
462        format: u32,
463        pixel_type: u32,
464        dst: &mut ArrayBufferView,
465        dst_elem_offset: u32,
466    ) {
467        handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
468
469        if self.bound_pixel_pack_buffer.get().is_some() {
470            return self.base.webgl_error(InvalidOperation);
471        }
472
473        let fb_slot = self.base.get_draw_framebuffer_slot();
474        let fb_readbuffer_valid = match fb_slot.get() {
475            Some(fb) => fb.attachment(fb.read_buffer()).is_some(),
476            None => self.default_fb_readbuffer.get() != constants::NONE,
477        };
478        if !fb_readbuffer_valid {
479            return self.base.webgl_error(InvalidOperation);
480        }
481
482        let dst_byte_offset = {
483            let dst_elem_size = dst.get_array_type().byte_size().unwrap();
484            dst_elem_offset as usize * dst_elem_size
485        };
486        if dst_byte_offset > dst.len() {
487            return self.base.webgl_error(InvalidValue);
488        }
489
490        let dst_array_type = dst.get_array_type();
491        let ReadPixelsAllowedFormats {
492            array_types: allowed_array_types,
493            channels,
494        } = match self.calc_read_pixel_formats(pixel_type, format) {
495            Ok(result) => result,
496            Err(error) => return self.base.webgl_error(error),
497        };
498        if !allowed_array_types.contains(&dst_array_type) {
499            return self.base.webgl_error(InvalidOperation);
500        }
501        if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
502            return self.base.webgl_error(InvalidOperation);
503        }
504
505        let bytes_per_pixel = dst_array_type.byte_size().unwrap() * channels;
506        let ReadPixelsSizes {
507            row_stride,
508            skipped_bytes,
509            size,
510        } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
511            Ok(result) => result,
512            Err(error) => return self.base.webgl_error(error),
513        };
514        let dst_end = dst_byte_offset + skipped_bytes + size;
515        let dst_pixels = unsafe { dst.as_mut_slice() };
516        if dst_pixels.len() < dst_end {
517            return self.base.webgl_error(InvalidOperation);
518        }
519
520        let dst_byte_offset = {
521            let margin_left = cmp::max(0, -x) as usize;
522            let margin_top = cmp::max(0, -y) as usize;
523            dst_byte_offset +
524                skipped_bytes +
525                margin_left * bytes_per_pixel +
526                margin_top * row_stride
527        };
528        let src_rect = {
529            let (fb_width, fb_height) = handle_potential_webgl_error!(
530                self.base,
531                self.base
532                    .get_current_framebuffer_size()
533                    .ok_or(InvalidOperation),
534                return
535            );
536            let src_origin = Point2D::new(x, y);
537            let src_size = Size2D::new(width as u32, height as u32);
538            let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
539            match pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()) {
540                Some(rect) => rect.to_u32(),
541                None => return,
542            }
543        };
544        let src_row_bytes = handle_potential_webgl_error!(
545            self.base,
546            src_rect
547                .size
548                .width
549                .checked_mul(bytes_per_pixel as u32)
550                .ok_or(InvalidOperation),
551            return
552        );
553
554        let (sender, receiver) = ipc::channel().unwrap();
555        self.base.send_command(WebGLCommand::ReadPixels(
556            src_rect, format, pixel_type, sender,
557        ));
558        let (src, _) = receiver.recv().unwrap();
559
560        for i in 0..src_rect.size.height as usize {
561            let src_start = i * src_row_bytes as usize;
562            let dst_start = dst_byte_offset + i * row_stride;
563            dst_pixels[dst_start..dst_start + src_row_bytes as usize]
564                .copy_from_slice(&src[src_start..src_start + src_row_bytes as usize]);
565        }
566    }
567
568    fn uniform_vec_section_uint(
569        &self,
570        vec: Uint32ArrayOrUnsignedLongSequence,
571        offset: u32,
572        length: u32,
573        uniform_size: usize,
574        uniform_location: &WebGLUniformLocation,
575    ) -> WebGLResult<Vec<u32>> {
576        let vec = match vec {
577            Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
578            Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
579        };
580        self.base
581            .uniform_vec_section::<u32>(vec, offset, length, uniform_size, uniform_location)
582    }
583
584    #[allow(unsafe_code)]
585    fn get_default_fb_attachment_param(
586        &self,
587        attachment: u32,
588        pname: u32,
589        mut retval: MutableHandleValue,
590    ) -> WebGLResult<()> {
591        match attachment {
592            constants::BACK | constants::DEPTH | constants::STENCIL => {},
593            _ => return Err(InvalidEnum),
594        }
595
596        if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
597            retval.set(NullValue());
598            return Ok(());
599        }
600
601        let attrs = self
602            .GetContextAttributes()
603            .unwrap_or_else(WebGLContextAttributes::empty);
604
605        let intval = match pname {
606            constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => match attachment {
607                constants::DEPTH if !attrs.depth => constants::NONE as _,
608                constants::STENCIL if !attrs.stencil => constants::NONE as _,
609                _ => constants::FRAMEBUFFER_DEFAULT as _,
610            },
611            constants::FRAMEBUFFER_ATTACHMENT_RED_SIZE |
612            constants::FRAMEBUFFER_ATTACHMENT_GREEN_SIZE |
613            constants::FRAMEBUFFER_ATTACHMENT_BLUE_SIZE => match attachment {
614                constants::BACK => 8,
615                _ => 0,
616            },
617            constants::FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE => match attachment {
618                constants::BACK if attrs.alpha => 8,
619                constants::BACK => return Err(InvalidOperation),
620                _ => 0,
621            },
622            constants::FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE => match attachment {
623                constants::DEPTH if attrs.depth => 24,
624                constants::DEPTH => return Err(InvalidOperation),
625                _ => 0,
626            },
627            constants::FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE => match attachment {
628                constants::STENCIL if attrs.stencil => 8,
629                constants::STENCIL => return Err(InvalidOperation),
630                _ => 0,
631            },
632            constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE => match attachment {
633                constants::DEPTH if attrs.depth => constants::UNSIGNED_NORMALIZED as _,
634                constants::STENCIL if attrs.stencil => constants::UNSIGNED_INT as _,
635                constants::DEPTH => return Err(InvalidOperation),
636                constants::STENCIL => return Err(InvalidOperation),
637                _ => constants::UNSIGNED_NORMALIZED as _,
638            },
639            constants::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING => match attachment {
640                constants::DEPTH if !attrs.depth => return Err(InvalidOperation),
641                constants::STENCIL if !attrs.stencil => return Err(InvalidOperation),
642                _ => constants::LINEAR as _,
643            },
644            _ => return Err(InvalidEnum),
645        };
646        retval.set(Int32Value(intval));
647        Ok(())
648    }
649
650    fn get_specific_fb_attachment_param(
651        &self,
652        cx: JSContext,
653        fb: &WebGLFramebuffer,
654        target: u32,
655        attachment: u32,
656        pname: u32,
657        mut rval: MutableHandleValue,
658    ) -> WebGLResult<()> {
659        use crate::dom::webgl::webglframebuffer::WebGLFramebufferAttachmentRoot::{
660            Renderbuffer, Texture,
661        };
662
663        match attachment {
664            constants::DEPTH_ATTACHMENT | constants::STENCIL_ATTACHMENT => {},
665            constants::DEPTH_STENCIL_ATTACHMENT => {
666                if pname == constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE {
667                    return Err(InvalidOperation);
668                }
669
670                let a = fb.attachment(constants::DEPTH_ATTACHMENT);
671                let b = fb.attachment(constants::STENCIL_ATTACHMENT);
672                match (a, b) {
673                    (Some(Renderbuffer(ref a)), Some(Renderbuffer(ref b))) if a.id() == b.id() => {
674                    },
675                    (Some(Texture(ref a)), Some(Texture(ref b))) if a.id() == b.id() => {},
676                    _ => return Err(InvalidOperation),
677                }
678            },
679            constants::COLOR_ATTACHMENT0..=constants::COLOR_ATTACHMENT15 => {
680                let last_slot =
681                    constants::COLOR_ATTACHMENT0 + self.base.limits().max_color_attachments - 1;
682                if last_slot < attachment {
683                    return Err(InvalidEnum);
684                }
685            },
686            _ => return Err(InvalidEnum),
687        }
688
689        let attachment = match attachment {
690            constants::DEPTH_STENCIL_ATTACHMENT => constants::DEPTH_ATTACHMENT,
691            _ => attachment,
692        };
693
694        if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
695            match fb.attachment(attachment) {
696                Some(Renderbuffer(rb)) => {
697                    rb.safe_to_jsval(cx, rval, CanGc::note());
698                },
699                Some(Texture(texture)) => {
700                    texture.safe_to_jsval(cx, rval, CanGc::note());
701                },
702                _ => rval.set(NullValue()),
703            }
704            return Ok(());
705        }
706
707        match pname {
708            constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE => {},
709            _ => match fb.attachment(attachment) {
710                Some(webgl_attachment) => match pname {
711                    constants::FRAMEBUFFER_ATTACHMENT_RED_SIZE |
712                    constants::FRAMEBUFFER_ATTACHMENT_GREEN_SIZE |
713                    constants::FRAMEBUFFER_ATTACHMENT_BLUE_SIZE |
714                    constants::FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE |
715                    constants::FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE |
716                    constants::FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE |
717                    constants::FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE |
718                    constants::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING => {},
719                    _ => match webgl_attachment {
720                        WebGLFramebufferAttachmentRoot::Renderbuffer(_) => return Err(InvalidEnum),
721                        WebGLFramebufferAttachmentRoot::Texture(_) => match pname {
722                            constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL |
723                            constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE |
724                            constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER => {},
725                            _ => return Err(InvalidEnum),
726                        },
727                    },
728                },
729                None => return Err(InvalidOperation),
730            },
731        }
732
733        let (sender, receiver) = webgl_channel().unwrap();
734        self.base
735            .send_command(WebGLCommand::GetFramebufferAttachmentParameter(
736                target, attachment, pname, sender,
737            ));
738
739        let retval = receiver.recv().unwrap();
740        rval.set(Int32Value(retval));
741        Ok(())
742    }
743
744    fn clearbuffer_array_size(&self, buffer: u32, draw_buffer: i32) -> WebGLResult<usize> {
745        match buffer {
746            constants::COLOR => {
747                if draw_buffer < 0 || draw_buffer as u32 >= self.base.limits().max_draw_buffers {
748                    return Err(InvalidValue);
749                }
750                Ok(4)
751            },
752            constants::DEPTH | constants::STENCIL | constants::DEPTH_STENCIL => {
753                if draw_buffer != 0 {
754                    return Err(InvalidValue);
755                }
756                Ok(1)
757            },
758            _ => unreachable!(),
759        }
760    }
761
762    fn clear_buffer<T: Clone>(
763        &self,
764        buffer: u32,
765        draw_buffer: i32,
766        valid_buffers: &[u32],
767        src_offset: u32,
768        array: Vec<T>,
769        msg: fn(u32, i32, Vec<T>) -> WebGLCommand,
770    ) {
771        if !valid_buffers.contains(&buffer) {
772            return self.base.webgl_error(InvalidEnum);
773        }
774
775        let array_size = handle_potential_webgl_error!(
776            self.base,
777            self.clearbuffer_array_size(buffer, draw_buffer),
778            return
779        );
780        let src_offset = src_offset as usize;
781
782        if array.len() < src_offset + array_size {
783            return self.base.webgl_error(InvalidValue);
784        }
785        let array = array[src_offset..src_offset + array_size].to_vec();
786
787        self.base.send_command(msg(buffer, draw_buffer, array));
788    }
789
790    fn valid_fb_attachment_values(&self, target: u32, attachments: &[u32]) -> bool {
791        let fb_slot = match target {
792            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
793                self.base.get_draw_framebuffer_slot()
794            },
795            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
796            _ => {
797                self.base.webgl_error(InvalidEnum);
798                return false;
799            },
800        };
801
802        if let Some(fb) = fb_slot.get() {
803            if fb.check_status() != constants::FRAMEBUFFER_COMPLETE {
804                return false;
805            }
806
807            for &attachment in attachments {
808                match attachment {
809                    constants::DEPTH_ATTACHMENT |
810                    constants::STENCIL_ATTACHMENT |
811                    constants::DEPTH_STENCIL_ATTACHMENT => {},
812                    constants::COLOR_ATTACHMENT0..=constants::COLOR_ATTACHMENT15 => {
813                        let last_slot = constants::COLOR_ATTACHMENT0 +
814                            self.base.limits().max_color_attachments -
815                            1;
816                        if last_slot < attachment {
817                            return false;
818                        }
819                    },
820                    _ => return false,
821                }
822            }
823        } else {
824            for &attachment in attachments {
825                match attachment {
826                    constants::COLOR | constants::DEPTH | constants::STENCIL => {},
827                    _ => return false,
828                }
829            }
830        }
831
832        true
833    }
834
835    fn vertex_attrib_i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
836        if index >= self.base.limits().max_vertex_attribs {
837            return self.base.webgl_error(InvalidValue);
838        }
839        self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Int(x, y, z, w);
840        self.current_vao()
841            .set_vertex_attrib_type(index, constants::INT);
842        self.base
843            .send_command(WebGLCommand::VertexAttribI(index, x, y, z, w));
844    }
845
846    fn vertex_attrib_u(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
847        if index >= self.base.limits().max_vertex_attribs {
848            return self.base.webgl_error(InvalidValue);
849        }
850        self.base.current_vertex_attribs()[index as usize] = VertexAttrib::Uint(x, y, z, w);
851        self.current_vao()
852            .set_vertex_attrib_type(index, constants::UNSIGNED_INT);
853        self.base
854            .send_command(WebGLCommand::VertexAttribU(index, x, y, z, w));
855    }
856
857    #[allow(clippy::too_many_arguments)]
858    fn tex_storage(
859        &self,
860        dimensions: u8,
861        target: u32,
862        levels: i32,
863        internal_format: u32,
864        width: i32,
865        height: i32,
866        depth: i32,
867    ) {
868        let expected_dimensions = match target {
869            constants::TEXTURE_2D | constants::TEXTURE_CUBE_MAP => 2,
870            constants::TEXTURE_3D | constants::TEXTURE_2D_ARRAY => 3,
871            _ => return self.base.webgl_error(InvalidEnum),
872        };
873        if dimensions != expected_dimensions {
874            return self.base.webgl_error(InvalidEnum);
875        }
876
877        let validator = TexStorageValidator::new(
878            &self.base,
879            dimensions,
880            target,
881            levels,
882            internal_format,
883            width,
884            height,
885            depth,
886        );
887        let TexStorageValidatorResult {
888            texture,
889            target,
890            levels,
891            internal_format,
892            width,
893            height,
894            depth,
895        } = match validator.validate() {
896            Ok(result) => result,
897            Err(_) => return, // NB: The validator sets the correct error for us.
898        };
899
900        handle_potential_webgl_error!(
901            self.base,
902            texture.storage(target, levels, internal_format, width, height, depth)
903        );
904    }
905
906    #[allow(clippy::too_many_arguments)]
907    fn tex_image_3d(
908        &self,
909        texture: &WebGLTexture,
910        target: TexImageTarget,
911        data_type: TexDataType,
912        internal_format: TexFormat,
913        format: TexFormat,
914        level: u32,
915        width: u32,
916        height: u32,
917        depth: u32,
918        _border: u32,
919        unpacking_alignment: u32,
920        data: TexPixels,
921    ) {
922        handle_potential_webgl_error!(
923            self.base,
924            texture.initialize(
925                target,
926                width,
927                height,
928                depth,
929                internal_format,
930                level,
931                Some(data_type)
932            )
933        );
934
935        let internal_format = self
936            .base
937            .extension_manager()
938            .get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
939        let effective_data_type = self
940            .base
941            .extension_manager()
942            .effective_type(data_type.as_gl_constant());
943
944        self.base.send_command(WebGLCommand::TexImage3D {
945            target: target.as_gl_constant(),
946            level,
947            internal_format,
948            size: data.size(),
949            depth,
950            format,
951            data_type,
952            effective_data_type,
953            unpacking_alignment,
954            alpha_treatment: data.alpha_treatment(),
955            y_axis_treatment: data.y_axis_treatment(),
956            pixel_format: data.pixel_format(),
957            data: data.into_shared_memory().into(),
958        });
959        // TODO: Hint/tex_parameter
960
961        if let Some(fb) = self.base.bound_draw_framebuffer() {
962            fb.invalidate_texture(texture);
963        }
964    }
965}
966
967impl CanvasContext for WebGL2RenderingContext {
968    type ID = WebGLContextId;
969
970    fn context_id(&self) -> Self::ID {
971        self.base.context_id()
972    }
973
974    fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
975        self.base.canvas()
976    }
977
978    fn resize(&self) {
979        self.base.resize();
980    }
981
982    fn reset_bitmap(&self) {
983        self.base.reset_bitmap();
984    }
985
986    fn get_image_data(&self) -> Option<Snapshot> {
987        self.base.get_image_data()
988    }
989
990    fn mark_as_dirty(&self) {
991        self.base.mark_as_dirty()
992    }
993
994    fn image_key(&self) -> Option<ImageKey> {
995        self.base.image_key()
996    }
997}
998
999impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingContext {
1000    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1>
1001    fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
1002        self.base.Canvas()
1003    }
1004
1005    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1006    fn Flush(&self) {
1007        self.base.Flush()
1008    }
1009
1010    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1011    fn Finish(&self) {
1012        self.base.Finish()
1013    }
1014
1015    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1>
1016    fn DrawingBufferWidth(&self) -> i32 {
1017        self.base.DrawingBufferWidth()
1018    }
1019
1020    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1>
1021    fn DrawingBufferHeight(&self) -> i32 {
1022        self.base.DrawingBufferHeight()
1023    }
1024
1025    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1026    fn GetBufferParameter(
1027        &self,
1028        _cx: JSContext,
1029        target: u32,
1030        parameter: u32,
1031        mut retval: MutableHandleValue,
1032    ) {
1033        let buffer = handle_potential_webgl_error!(
1034            self.base,
1035            self.bound_buffer(target),
1036            return retval.set(NullValue())
1037        );
1038        self.base.get_buffer_param(buffer, parameter, retval)
1039    }
1040
1041    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1042    fn GetParameter(&self, cx: JSContext, parameter: u32, mut rval: MutableHandleValue) {
1043        match parameter {
1044            constants::VERSION => {
1045                "WebGL 2.0".safe_to_jsval(cx, rval, CanGc::note());
1046                return;
1047            },
1048            constants::SHADING_LANGUAGE_VERSION => {
1049                "WebGL GLSL ES 3.00".safe_to_jsval(cx, rval, CanGc::note());
1050                return;
1051            },
1052            constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => {
1053                rval.set(DoubleValue(
1054                    self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64,
1055                ));
1056                return;
1057            },
1058            constants::MAX_SERVER_WAIT_TIMEOUT => {
1059                rval.set(DoubleValue(
1060                    self.base.limits().max_server_wait_timeout.as_nanos() as f64,
1061                ));
1062                return;
1063            },
1064            constants::SAMPLER_BINDING => {
1065                let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize;
1066                assert!(idx < self.samplers.len());
1067                let sampler = self.samplers[idx].get();
1068                sampler.safe_to_jsval(cx, rval, CanGc::note());
1069                return;
1070            },
1071            constants::COPY_READ_BUFFER_BINDING => {
1072                self.bound_copy_read_buffer
1073                    .get()
1074                    .safe_to_jsval(cx, rval, CanGc::note());
1075                return;
1076            },
1077            constants::COPY_WRITE_BUFFER_BINDING => {
1078                self.bound_copy_write_buffer
1079                    .get()
1080                    .safe_to_jsval(cx, rval, CanGc::note());
1081                return;
1082            },
1083            constants::PIXEL_PACK_BUFFER_BINDING => {
1084                self.bound_pixel_pack_buffer
1085                    .get()
1086                    .safe_to_jsval(cx, rval, CanGc::note());
1087                return;
1088            },
1089            constants::PIXEL_UNPACK_BUFFER_BINDING => {
1090                self.bound_pixel_unpack_buffer
1091                    .get()
1092                    .safe_to_jsval(cx, rval, CanGc::note());
1093                return;
1094            },
1095            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => {
1096                self.bound_transform_feedback_buffer
1097                    .get()
1098                    .safe_to_jsval(cx, rval, CanGc::note());
1099                return;
1100            },
1101            constants::UNIFORM_BUFFER_BINDING => {
1102                self.bound_uniform_buffer
1103                    .get()
1104                    .safe_to_jsval(cx, rval, CanGc::note());
1105                return;
1106            },
1107            constants::TRANSFORM_FEEDBACK_BINDING => {
1108                self.current_transform_feedback
1109                    .get()
1110                    .safe_to_jsval(cx, rval, CanGc::note());
1111                return;
1112            },
1113            constants::ELEMENT_ARRAY_BUFFER_BINDING => {
1114                let buffer = self.current_vao().element_array_buffer().get();
1115                buffer.safe_to_jsval(cx, rval, CanGc::note());
1116                return;
1117            },
1118            constants::VERTEX_ARRAY_BINDING => {
1119                let vao = self.current_vao();
1120                let vao = vao.id().map(|_| &*vao);
1121                vao.safe_to_jsval(cx, rval, CanGc::note());
1122                return;
1123            },
1124            // NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side
1125            constants::READ_FRAMEBUFFER_BINDING => {
1126                self.base
1127                    .get_read_framebuffer_slot()
1128                    .get()
1129                    .safe_to_jsval(cx, rval, CanGc::note());
1130                return;
1131            },
1132            constants::READ_BUFFER => {
1133                let buffer = match self.base.get_read_framebuffer_slot().get() {
1134                    Some(fb) => fb.read_buffer(),
1135                    None => self.default_fb_readbuffer.get(),
1136                };
1137                rval.set(UInt32Value(buffer));
1138                return;
1139            },
1140            constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
1141                let buffer = match self.base.get_read_framebuffer_slot().get() {
1142                    Some(fb) => {
1143                        let idx = parameter - constants::DRAW_BUFFER0;
1144                        fb.draw_buffer_i(idx as usize)
1145                    },
1146                    None if parameter == constants::DRAW_BUFFER0 => {
1147                        self.default_fb_readbuffer.get()
1148                    },
1149                    None => constants::NONE,
1150                };
1151                rval.set(UInt32Value(buffer));
1152                return;
1153            },
1154            constants::MAX_TEXTURE_LOD_BIAS => {
1155                rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64));
1156                return;
1157            },
1158            constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
1159                rval.set(DoubleValue(
1160                    self.base.limits().max_combined_fragment_uniform_components as f64,
1161                ));
1162                return;
1163            },
1164            constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
1165                rval.set(DoubleValue(
1166                    self.base.limits().max_combined_vertex_uniform_components as f64,
1167                ));
1168                return;
1169            },
1170            constants::MAX_ELEMENT_INDEX => {
1171                rval.set(DoubleValue(self.base.limits().max_element_index as f64));
1172                return;
1173            },
1174            constants::MAX_UNIFORM_BLOCK_SIZE => {
1175                rval.set(DoubleValue(
1176                    self.base.limits().max_uniform_block_size as f64,
1177                ));
1178                return;
1179            },
1180            constants::MIN_PROGRAM_TEXEL_OFFSET => {
1181                rval.set(Int32Value(self.base.limits().min_program_texel_offset));
1182                return;
1183            },
1184            _ => {},
1185        }
1186
1187        let limit = match parameter {
1188            constants::MAX_3D_TEXTURE_SIZE => Some(self.base.limits().max_3d_texture_size),
1189            constants::MAX_ARRAY_TEXTURE_LAYERS => {
1190                Some(self.base.limits().max_array_texture_layers)
1191            },
1192            constants::MAX_COLOR_ATTACHMENTS => Some(self.base.limits().max_color_attachments),
1193            constants::MAX_COMBINED_UNIFORM_BLOCKS => {
1194                Some(self.base.limits().max_combined_uniform_blocks)
1195            },
1196            constants::MAX_DRAW_BUFFERS => Some(self.base.limits().max_draw_buffers),
1197            constants::MAX_ELEMENTS_INDICES => Some(self.base.limits().max_elements_indices),
1198            constants::MAX_ELEMENTS_VERTICES => Some(self.base.limits().max_elements_vertices),
1199            constants::MAX_FRAGMENT_INPUT_COMPONENTS => {
1200                Some(self.base.limits().max_fragment_input_components)
1201            },
1202            constants::MAX_FRAGMENT_UNIFORM_BLOCKS => {
1203                Some(self.base.limits().max_fragment_uniform_blocks)
1204            },
1205            constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => {
1206                Some(self.base.limits().max_fragment_uniform_components)
1207            },
1208            constants::MAX_PROGRAM_TEXEL_OFFSET => {
1209                Some(self.base.limits().max_program_texel_offset)
1210            },
1211            constants::MAX_SAMPLES => Some(self.base.limits().max_samples),
1212            constants::MAX_UNIFORM_BUFFER_BINDINGS => {
1213                Some(self.base.limits().max_uniform_buffer_bindings)
1214            },
1215            constants::MAX_VARYING_COMPONENTS => Some(self.base.limits().max_varying_components),
1216            constants::MAX_VERTEX_OUTPUT_COMPONENTS => {
1217                Some(self.base.limits().max_vertex_output_components)
1218            },
1219            constants::MAX_VERTEX_UNIFORM_BLOCKS => {
1220                Some(self.base.limits().max_vertex_uniform_blocks)
1221            },
1222            constants::MAX_VERTEX_UNIFORM_COMPONENTS => {
1223                Some(self.base.limits().max_vertex_uniform_components)
1224            },
1225            constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => {
1226                Some(self.base.limits().uniform_buffer_offset_alignment)
1227            },
1228            _ => None,
1229        };
1230        if let Some(limit) = limit {
1231            rval.set(UInt32Value(limit));
1232            return;
1233        }
1234
1235        self.base.GetParameter(cx, parameter, rval)
1236    }
1237
1238    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1239    fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) {
1240        self.base.GetTexParameter(cx, target, pname, retval)
1241    }
1242
1243    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1244    fn GetError(&self) -> u32 {
1245        self.base.GetError()
1246    }
1247
1248    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.2>
1249    fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
1250        self.base.GetContextAttributes()
1251    }
1252
1253    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.13>
1254    fn IsContextLost(&self) -> bool {
1255        self.base.IsContextLost()
1256    }
1257
1258    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14>
1259    fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
1260        self.base.GetSupportedExtensions()
1261    }
1262
1263    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14>
1264    fn GetExtension(&self, cx: JSContext, name: DOMString) -> Option<NonNull<JSObject>> {
1265        self.base.GetExtension(cx, name)
1266    }
1267
1268    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
1269    fn GetFramebufferAttachmentParameter(
1270        &self,
1271        cx: JSContext,
1272        target: u32,
1273        attachment: u32,
1274        pname: u32,
1275        mut rval: MutableHandleValue,
1276    ) {
1277        let fb_slot = match target {
1278            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
1279                self.base.get_draw_framebuffer_slot()
1280            },
1281            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
1282            _ => {
1283                self.base.webgl_error(InvalidEnum);
1284                rval.set(NullValue());
1285                return;
1286            },
1287        };
1288
1289        if let Some(fb) = fb_slot.get() {
1290            // A selected framebuffer is bound to the target
1291            handle_potential_webgl_error!(
1292                self.base,
1293                fb.validate_transparent(),
1294                return rval.set(NullValue())
1295            );
1296            handle_potential_webgl_error!(
1297                self.base,
1298                self.get_specific_fb_attachment_param(
1299                    cx,
1300                    &fb,
1301                    target,
1302                    attachment,
1303                    pname,
1304                    rval.reborrow()
1305                ),
1306                rval.set(NullValue())
1307            )
1308        } else {
1309            // The default framebuffer is bound to the target
1310            handle_potential_webgl_error!(
1311                self.base,
1312                self.get_default_fb_attachment_param(attachment, pname, rval.reborrow()),
1313                rval.set(NullValue())
1314            )
1315        }
1316    }
1317
1318    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1319    fn GetRenderbufferParameter(
1320        &self,
1321        cx: JSContext,
1322        target: u32,
1323        pname: u32,
1324        retval: MutableHandleValue,
1325    ) {
1326        self.base
1327            .GetRenderbufferParameter(cx, target, pname, retval)
1328    }
1329
1330    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1331    fn ActiveTexture(&self, texture: u32) {
1332        self.base.ActiveTexture(texture)
1333    }
1334
1335    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1336    fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
1337        self.base.BlendColor(r, g, b, a)
1338    }
1339
1340    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1341    fn BlendEquation(&self, mode: u32) {
1342        self.base.BlendEquation(mode)
1343    }
1344
1345    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1346    fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
1347        self.base.BlendEquationSeparate(mode_rgb, mode_alpha)
1348    }
1349
1350    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1351    fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
1352        self.base.BlendFunc(src_factor, dest_factor)
1353    }
1354
1355    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1356    fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
1357        self.base
1358            .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1359    }
1360
1361    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1362    fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1363        self.base.AttachShader(program, shader)
1364    }
1365
1366    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1367    fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1368        self.base.DetachShader(program, shader)
1369    }
1370
1371    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1372    fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
1373        self.base.BindAttribLocation(program, index, name)
1374    }
1375
1376    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
1377    fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
1378        let current_vao;
1379        let slot = match target {
1380            constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
1381            constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
1382            constants::PIXEL_PACK_BUFFER => &self.bound_pixel_pack_buffer,
1383            constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
1384            constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
1385            constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
1386            constants::ELEMENT_ARRAY_BUFFER => {
1387                current_vao = self.current_vao();
1388                current_vao.element_array_buffer()
1389            },
1390            _ => return self.base.BindBuffer(target, buffer),
1391        };
1392        self.base.bind_buffer_maybe(slot, target, buffer);
1393    }
1394
1395    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1396    fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
1397        handle_potential_webgl_error!(
1398            self.base,
1399            self.base.validate_new_framebuffer_binding(framebuffer),
1400            return
1401        );
1402
1403        let (bind_read, bind_draw) = match target {
1404            constants::FRAMEBUFFER => (true, true),
1405            constants::READ_FRAMEBUFFER => (true, false),
1406            constants::DRAW_FRAMEBUFFER => (false, true),
1407            _ => return self.base.webgl_error(InvalidEnum),
1408        };
1409        if bind_read {
1410            self.base.bind_framebuffer_to(
1411                target,
1412                framebuffer,
1413                self.base.get_read_framebuffer_slot(),
1414            );
1415        }
1416        if bind_draw {
1417            self.base.bind_framebuffer_to(
1418                target,
1419                framebuffer,
1420                self.base.get_draw_framebuffer_slot(),
1421            );
1422        }
1423    }
1424
1425    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1426    fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
1427        self.base.BindRenderbuffer(target, renderbuffer)
1428    }
1429
1430    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1431    fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
1432        self.base.BindTexture(target, texture)
1433    }
1434
1435    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1436    fn GenerateMipmap(&self, target: u32) {
1437        self.base.GenerateMipmap(target)
1438    }
1439
1440    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1441    fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
1442        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1443        let bound_buffer =
1444            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1445        self.base.buffer_data(target, data, usage, bound_buffer)
1446    }
1447
1448    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1449    fn BufferData(&self, target: u32, size: i64, usage: u32) {
1450        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1451        let bound_buffer =
1452            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1453        self.base.buffer_data_(target, size, usage, bound_buffer)
1454    }
1455
1456    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1457    #[allow(unsafe_code)]
1458    fn BufferData__(
1459        &self,
1460        target: u32,
1461        data: CustomAutoRooterGuard<ArrayBufferView>,
1462        usage: u32,
1463        elem_offset: u32,
1464        length: u32,
1465    ) {
1466        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1467        let bound_buffer =
1468            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1469        let bound_buffer =
1470            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1471
1472        let elem_size = data.get_array_type().byte_size().unwrap();
1473        let elem_count = data.len() / elem_size;
1474        let elem_offset = elem_offset as usize;
1475        let byte_offset = elem_offset * elem_size;
1476
1477        if byte_offset > data.len() {
1478            return self.base.webgl_error(InvalidValue);
1479        }
1480
1481        let copy_count = if length == 0 {
1482            elem_count - elem_offset
1483        } else {
1484            length as usize
1485        };
1486        if copy_count == 0 {
1487            return;
1488        }
1489        let copy_bytes = copy_count * elem_size;
1490
1491        if byte_offset + copy_bytes > data.len() {
1492            return self.base.webgl_error(InvalidValue);
1493        }
1494
1495        let data_end = byte_offset + copy_bytes;
1496        let data: &[u8] = unsafe { &data.as_slice()[byte_offset..data_end] };
1497        handle_potential_webgl_error!(self.base, bound_buffer.buffer_data(target, data, usage));
1498    }
1499
1500    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1501    fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
1502        let bound_buffer =
1503            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1504        self.base
1505            .buffer_sub_data(target, offset, data, bound_buffer)
1506    }
1507
1508    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1509    #[allow(unsafe_code)]
1510    fn BufferSubData_(
1511        &self,
1512        target: u32,
1513        dst_byte_offset: i64,
1514        src_data: CustomAutoRooterGuard<ArrayBufferView>,
1515        src_elem_offset: u32,
1516        length: u32,
1517    ) {
1518        let bound_buffer =
1519            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1520        let bound_buffer =
1521            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1522
1523        let src_elem_size = src_data.get_array_type().byte_size().unwrap();
1524        let src_elem_count = src_data.len() / src_elem_size;
1525        let src_elem_offset = src_elem_offset as usize;
1526        let src_byte_offset = src_elem_offset * src_elem_size;
1527
1528        if dst_byte_offset < 0 || src_byte_offset > src_data.len() {
1529            return self.base.webgl_error(InvalidValue);
1530        }
1531
1532        let copy_count = if length == 0 {
1533            src_elem_count - src_elem_offset
1534        } else {
1535            length as usize
1536        };
1537        if copy_count == 0 {
1538            return;
1539        }
1540        let copy_bytes = copy_count * src_elem_size;
1541
1542        let dst_byte_offset = dst_byte_offset as usize;
1543        if dst_byte_offset + copy_bytes > bound_buffer.capacity() ||
1544            src_byte_offset + copy_bytes > src_data.len()
1545        {
1546            return self.base.webgl_error(InvalidValue);
1547        }
1548
1549        let (sender, receiver) = ipc::bytes_channel().unwrap();
1550        self.base.send_command(WebGLCommand::BufferSubData(
1551            target,
1552            dst_byte_offset as isize,
1553            receiver,
1554        ));
1555        let src_end = src_byte_offset + copy_bytes;
1556        let data: &[u8] = unsafe { &src_data.as_slice()[src_byte_offset..src_end] };
1557        sender.send(data).unwrap();
1558    }
1559
1560    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1561    fn CopyBufferSubData(
1562        &self,
1563        read_target: u32,
1564        write_target: u32,
1565        read_offset: i64,
1566        write_offset: i64,
1567        size: i64,
1568    ) {
1569        if read_offset < 0 || write_offset < 0 || size < 0 {
1570            return self.base.webgl_error(InvalidValue);
1571        }
1572
1573        let read_buffer =
1574            handle_potential_webgl_error!(self.base, self.bound_buffer(read_target), return);
1575        let read_buffer =
1576            handle_potential_webgl_error!(self.base, read_buffer.ok_or(InvalidOperation), return);
1577
1578        let write_buffer =
1579            handle_potential_webgl_error!(self.base, self.bound_buffer(write_target), return);
1580        let write_buffer =
1581            handle_potential_webgl_error!(self.base, write_buffer.ok_or(InvalidOperation), return);
1582
1583        let read_until = read_offset + size;
1584        let write_until = write_offset + size;
1585        if read_until as usize > read_buffer.capacity() ||
1586            write_until as usize > write_buffer.capacity()
1587        {
1588            return self.base.webgl_error(InvalidValue);
1589        }
1590
1591        if read_target == write_target {
1592            let is_separate = read_until <= write_offset || write_until <= read_offset;
1593            if !is_separate {
1594                return self.base.webgl_error(InvalidValue);
1595            }
1596        }
1597        let src_is_elemarray = read_buffer
1598            .target()
1599            .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1600        let dst_is_elemarray = write_buffer
1601            .target()
1602            .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1603        if src_is_elemarray != dst_is_elemarray {
1604            return self.base.webgl_error(InvalidOperation);
1605        }
1606
1607        self.base.send_command(WebGLCommand::CopyBufferSubData(
1608            read_target,
1609            write_target,
1610            read_offset,
1611            write_offset,
1612            size,
1613        ));
1614    }
1615
1616    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1617    #[allow(unsafe_code)]
1618    fn GetBufferSubData(
1619        &self,
1620        target: u32,
1621        src_byte_offset: i64,
1622        mut dst_buffer: CustomAutoRooterGuard<ArrayBufferView>,
1623        dst_elem_offset: u32,
1624        length: u32,
1625    ) {
1626        let bound_buffer =
1627            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1628        let bound_buffer =
1629            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1630
1631        let dst_elem_size = dst_buffer.get_array_type().byte_size().unwrap();
1632        let dst_elem_count = dst_buffer.len() / dst_elem_size;
1633        let dst_elem_offset = dst_elem_offset as usize;
1634        let dst_byte_offset = dst_elem_offset * dst_elem_size;
1635
1636        if src_byte_offset < 0 || dst_byte_offset > dst_buffer.len() {
1637            return self.base.webgl_error(InvalidValue);
1638        }
1639
1640        let copy_count = if length == 0 {
1641            dst_elem_count - dst_elem_offset
1642        } else {
1643            length as usize
1644        };
1645        if copy_count == 0 {
1646            return;
1647        }
1648        let copy_bytes = copy_count * dst_elem_size;
1649
1650        // TODO(mmatyas): Transform Feedback
1651
1652        let src_byte_offset = src_byte_offset as usize;
1653        if src_byte_offset + copy_bytes > bound_buffer.capacity() ||
1654            dst_byte_offset + copy_bytes > dst_buffer.len()
1655        {
1656            return self.base.webgl_error(InvalidValue);
1657        }
1658
1659        let (sender, receiver) = ipc::bytes_channel().unwrap();
1660        self.base.send_command(WebGLCommand::GetBufferSubData(
1661            target,
1662            src_byte_offset,
1663            copy_bytes,
1664            sender,
1665        ));
1666        let data = receiver.recv().unwrap();
1667        let dst_end = dst_byte_offset + copy_bytes;
1668        unsafe {
1669            dst_buffer.as_mut_slice()[dst_byte_offset..dst_end].copy_from_slice(&data);
1670        }
1671    }
1672
1673    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
1674    #[allow(unsafe_code)]
1675    fn CompressedTexImage2D(
1676        &self,
1677        target: u32,
1678        level: i32,
1679        internal_format: u32,
1680        width: i32,
1681        height: i32,
1682        border: i32,
1683        pixels: CustomAutoRooterGuard<ArrayBufferView>,
1684        src_offset: u32,
1685        src_length_override: u32,
1686    ) {
1687        let mut data = unsafe { pixels.as_slice() };
1688        let start = src_offset as usize;
1689        let end = (src_offset + src_length_override) as usize;
1690        if start > data.len() || end > data.len() {
1691            self.base.webgl_error(InvalidValue);
1692            return;
1693        }
1694        if src_length_override != 0 {
1695            data = &data[start..end];
1696        }
1697        self.base.compressed_tex_image_2d(
1698            target,
1699            level,
1700            internal_format,
1701            width,
1702            height,
1703            border,
1704            data,
1705        )
1706    }
1707
1708    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1709    #[allow(unsafe_code)]
1710    fn CompressedTexSubImage2D(
1711        &self,
1712        target: u32,
1713        level: i32,
1714        xoffset: i32,
1715        yoffset: i32,
1716        width: i32,
1717        height: i32,
1718        format: u32,
1719        pixels: CustomAutoRooterGuard<ArrayBufferView>,
1720        src_offset: u32,
1721        src_length_override: u32,
1722    ) {
1723        let mut data = unsafe { pixels.as_slice() };
1724        let start = src_offset as usize;
1725        let end = (src_offset + src_length_override) as usize;
1726        if start > data.len() || end > data.len() {
1727            self.base.webgl_error(InvalidValue);
1728            return;
1729        }
1730        if src_length_override != 0 {
1731            data = &data[start..end];
1732        }
1733        self.base.compressed_tex_sub_image_2d(
1734            target, level, xoffset, yoffset, width, height, format, data,
1735        )
1736    }
1737
1738    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1739    fn CopyTexImage2D(
1740        &self,
1741        target: u32,
1742        level: i32,
1743        internal_format: u32,
1744        x: i32,
1745        y: i32,
1746        width: i32,
1747        height: i32,
1748        border: i32,
1749    ) {
1750        self.base
1751            .CopyTexImage2D(target, level, internal_format, x, y, width, height, border)
1752    }
1753
1754    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1755    fn CopyTexSubImage2D(
1756        &self,
1757        target: u32,
1758        level: i32,
1759        xoffset: i32,
1760        yoffset: i32,
1761        x: i32,
1762        y: i32,
1763        width: i32,
1764        height: i32,
1765    ) {
1766        self.base
1767            .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height)
1768    }
1769
1770    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1771    fn Clear(&self, mask: u32) {
1772        self.base.Clear(mask)
1773    }
1774
1775    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1776    fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
1777        self.base.ClearColor(red, green, blue, alpha)
1778    }
1779
1780    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1781    fn ClearDepth(&self, depth: f32) {
1782        self.base.ClearDepth(depth)
1783    }
1784
1785    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1786    fn ClearStencil(&self, stencil: i32) {
1787        self.base.ClearStencil(stencil)
1788    }
1789
1790    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1791    fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
1792        self.base.ColorMask(r, g, b, a)
1793    }
1794
1795    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1796    fn CullFace(&self, mode: u32) {
1797        self.base.CullFace(mode)
1798    }
1799
1800    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1801    fn FrontFace(&self, mode: u32) {
1802        self.base.FrontFace(mode)
1803    }
1804    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1805    fn DepthFunc(&self, func: u32) {
1806        self.base.DepthFunc(func)
1807    }
1808
1809    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1810    fn DepthMask(&self, flag: bool) {
1811        self.base.DepthMask(flag)
1812    }
1813
1814    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1815    fn DepthRange(&self, near: f32, far: f32) {
1816        self.base.DepthRange(near, far)
1817    }
1818
1819    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1820    fn Enable(&self, cap: u32) {
1821        match cap {
1822            constants::RASTERIZER_DISCARD => {
1823                self.enable_rasterizer_discard.set(true);
1824                self.base.send_command(WebGLCommand::Enable(cap));
1825            },
1826            _ => self.base.Enable(cap),
1827        }
1828    }
1829
1830    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1831    fn Disable(&self, cap: u32) {
1832        match cap {
1833            constants::RASTERIZER_DISCARD => {
1834                self.enable_rasterizer_discard.set(false);
1835                self.base.send_command(WebGLCommand::Disable(cap));
1836            },
1837            _ => self.base.Disable(cap),
1838        }
1839    }
1840
1841    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1842    fn CompileShader(&self, shader: &WebGLShader) {
1843        self.base.CompileShader(shader)
1844    }
1845
1846    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1847    fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1848        self.base.CreateBuffer()
1849    }
1850
1851    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1852    fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
1853        self.base.CreateFramebuffer()
1854    }
1855
1856    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1857    fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
1858        self.base.CreateRenderbuffer()
1859    }
1860
1861    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1862    fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
1863        self.base.CreateTexture()
1864    }
1865
1866    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1867    fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
1868        self.base.CreateProgram()
1869    }
1870
1871    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1872    fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
1873        self.base.CreateShader(shader_type)
1874    }
1875
1876    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
1877    fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1878        self.base.create_vertex_array_webgl2()
1879    }
1880
1881    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1882    fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
1883        let buffer = match buffer {
1884            Some(buffer) => buffer,
1885            None => return,
1886        };
1887        handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
1888        if buffer.is_marked_for_deletion() {
1889            return;
1890        }
1891        self.current_vao().unbind_buffer(buffer);
1892        self.unbind_from(self.base.array_buffer_slot(), buffer);
1893        self.unbind_from(&self.bound_copy_read_buffer, buffer);
1894        self.unbind_from(&self.bound_copy_write_buffer, buffer);
1895        self.unbind_from(&self.bound_pixel_pack_buffer, buffer);
1896        self.unbind_from(&self.bound_pixel_unpack_buffer, buffer);
1897        self.unbind_from(&self.bound_transform_feedback_buffer, buffer);
1898        self.unbind_from(&self.bound_uniform_buffer, buffer);
1899
1900        for binding in self.indexed_uniform_buffer_bindings.iter() {
1901            self.unbind_from(&binding.buffer, buffer);
1902        }
1903        for binding in self.indexed_transform_feedback_buffer_bindings.iter() {
1904            self.unbind_from(&binding.buffer, buffer);
1905        }
1906
1907        buffer.mark_for_deletion(Operation::Infallible);
1908    }
1909
1910    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1911    fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
1912        self.base.DeleteFramebuffer(framebuffer)
1913    }
1914
1915    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1916    fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
1917        self.base.DeleteRenderbuffer(renderbuffer)
1918    }
1919
1920    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1921    fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
1922        self.base.DeleteTexture(texture)
1923    }
1924
1925    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1926    fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
1927        self.base.DeleteProgram(program)
1928    }
1929
1930    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1931    fn DeleteShader(&self, shader: Option<&WebGLShader>) {
1932        self.base.DeleteShader(shader)
1933    }
1934
1935    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
1936    fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
1937        self.base.delete_vertex_array_webgl2(vertex_array);
1938    }
1939
1940    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1941    fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
1942        self.validate_uniform_block_for_draw();
1943        self.validate_vertex_attribs_for_draw();
1944        self.base.DrawArrays(mode, first, count)
1945    }
1946
1947    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1948    fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
1949        self.validate_uniform_block_for_draw();
1950        self.validate_vertex_attribs_for_draw();
1951        self.base.DrawElements(mode, count, type_, offset)
1952    }
1953
1954    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1955    fn EnableVertexAttribArray(&self, attrib_id: u32) {
1956        self.base.EnableVertexAttribArray(attrib_id)
1957    }
1958
1959    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1960    fn DisableVertexAttribArray(&self, attrib_id: u32) {
1961        self.base.DisableVertexAttribArray(attrib_id)
1962    }
1963
1964    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1965    fn GetActiveUniform(
1966        &self,
1967        program: &WebGLProgram,
1968        index: u32,
1969    ) -> Option<DomRoot<WebGLActiveInfo>> {
1970        self.base.GetActiveUniform(program, index)
1971    }
1972
1973    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1974    fn GetActiveAttrib(
1975        &self,
1976        program: &WebGLProgram,
1977        index: u32,
1978    ) -> Option<DomRoot<WebGLActiveInfo>> {
1979        self.base.GetActiveAttrib(program, index)
1980    }
1981
1982    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1983    fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1984        self.base.GetAttribLocation(program, name)
1985    }
1986
1987    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.7>
1988    fn GetFragDataLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1989        handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return -1);
1990        handle_potential_webgl_error!(self.base, program.get_frag_data_location(name), -1)
1991    }
1992
1993    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1994    fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
1995        self.base.GetProgramInfoLog(program)
1996    }
1997
1998    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1999    fn GetProgramParameter(
2000        &self,
2001        cx: JSContext,
2002        program: &WebGLProgram,
2003        param_id: u32,
2004        mut retval: MutableHandleValue,
2005    ) {
2006        handle_potential_webgl_error!(
2007            self.base,
2008            self.base.validate_ownership(program),
2009            return retval.set(NullValue())
2010        );
2011        if program.is_deleted() {
2012            self.base.webgl_error(InvalidOperation);
2013            return retval.set(NullValue());
2014        }
2015        match param_id {
2016            constants::TRANSFORM_FEEDBACK_VARYINGS => {
2017                retval.set(Int32Value(program.transform_feedback_varyings_length()))
2018            },
2019            constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
2020                retval.set(Int32Value(program.transform_feedback_buffer_mode()))
2021            },
2022            _ => self.base.GetProgramParameter(cx, program, param_id, retval),
2023        }
2024    }
2025
2026    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2027    fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
2028        self.base.GetShaderInfoLog(shader)
2029    }
2030
2031    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2032    fn GetShaderParameter(
2033        &self,
2034        cx: JSContext,
2035        shader: &WebGLShader,
2036        param_id: u32,
2037        retval: MutableHandleValue,
2038    ) {
2039        self.base.GetShaderParameter(cx, shader, param_id, retval)
2040    }
2041
2042    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2043    fn GetShaderPrecisionFormat(
2044        &self,
2045        shader_type: u32,
2046        precision_type: u32,
2047    ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
2048        self.base
2049            .GetShaderPrecisionFormat(shader_type, precision_type)
2050    }
2051
2052    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2053    fn GetIndexedParameter(
2054        &self,
2055        cx: JSContext,
2056        target: u32,
2057        index: u32,
2058        mut retval: MutableHandleValue,
2059    ) {
2060        let bindings = match target {
2061            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
2062            constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
2063            constants::TRANSFORM_FEEDBACK_BUFFER_START => {
2064                &self.indexed_transform_feedback_buffer_bindings
2065            },
2066            constants::UNIFORM_BUFFER_BINDING |
2067            constants::UNIFORM_BUFFER_SIZE |
2068            constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
2069            _ => {
2070                self.base.webgl_error(InvalidEnum);
2071                return retval.set(NullValue());
2072            },
2073        };
2074
2075        let binding = match bindings.get(index as usize) {
2076            Some(binding) => binding,
2077            None => {
2078                self.base.webgl_error(InvalidValue);
2079                return retval.set(NullValue());
2080            },
2081        };
2082
2083        match target {
2084            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => {
2085                binding
2086                    .buffer
2087                    .get()
2088                    .safe_to_jsval(cx, retval, CanGc::note())
2089            },
2090            constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
2091                retval.set(Int32Value(binding.start.get() as _))
2092            },
2093            constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
2094                retval.set(Int32Value(binding.size.get() as _))
2095            },
2096            _ => unreachable!(),
2097        }
2098    }
2099
2100    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2101    fn GetUniformLocation(
2102        &self,
2103        program: &WebGLProgram,
2104        name: DOMString,
2105    ) -> Option<DomRoot<WebGLUniformLocation>> {
2106        self.base.GetUniformLocation(program, name)
2107    }
2108
2109    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2110    fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) {
2111        self.base.GetVertexAttrib(cx, index, pname, retval)
2112    }
2113
2114    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2115    fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
2116        self.base.GetVertexAttribOffset(index, pname)
2117    }
2118
2119    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2120    fn Hint(&self, target: u32, mode: u32) {
2121        self.base.Hint(target, mode)
2122    }
2123
2124    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
2125    fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
2126        self.base.IsBuffer(buffer)
2127    }
2128
2129    // TODO: We could write this without IPC, recording the calls to `enable` and `disable`.
2130    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2131    fn IsEnabled(&self, cap: u32) -> bool {
2132        match cap {
2133            constants::RASTERIZER_DISCARD => self.enable_rasterizer_discard.get(),
2134            _ => self.base.IsEnabled(cap),
2135        }
2136    }
2137
2138    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
2139    fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
2140        self.base.IsFramebuffer(frame_buffer)
2141    }
2142
2143    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2144    fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
2145        self.base.IsProgram(program)
2146    }
2147
2148    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
2149    fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
2150        self.base.IsRenderbuffer(render_buffer)
2151    }
2152
2153    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2154    fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
2155        self.base.IsShader(shader)
2156    }
2157
2158    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
2159    fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
2160        self.base.IsTexture(texture)
2161    }
2162
2163    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
2164    fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
2165        self.base.is_vertex_array_webgl2(vertex_array)
2166    }
2167
2168    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2169    fn LineWidth(&self, width: f32) {
2170        self.base.LineWidth(width)
2171    }
2172
2173    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2174    fn PixelStorei(&self, param_name: u32, param_value: i32) {
2175        if param_value < 0 {
2176            return self.base.webgl_error(InvalidValue);
2177        }
2178
2179        match param_name {
2180            constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
2181            constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
2182            constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
2183            _ => self.base.PixelStorei(param_name, param_value),
2184        }
2185    }
2186
2187    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2188    fn PolygonOffset(&self, factor: f32, units: f32) {
2189        self.base.PolygonOffset(factor, units)
2190    }
2191
2192    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.12>
2193    fn ReadPixels(
2194        &self,
2195        x: i32,
2196        y: i32,
2197        width: i32,
2198        height: i32,
2199        format: u32,
2200        pixel_type: u32,
2201        mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
2202    ) {
2203        let pixels =
2204            handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
2205
2206        self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
2207    }
2208
2209    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10>
2210    fn ReadPixels_(
2211        &self,
2212        x: i32,
2213        y: i32,
2214        width: i32,
2215        height: i32,
2216        format: u32,
2217        pixel_type: u32,
2218        dst_byte_offset: i64,
2219    ) {
2220        handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
2221
2222        let dst = match self.bound_pixel_pack_buffer.get() {
2223            Some(buffer) => buffer,
2224            None => return self.base.webgl_error(InvalidOperation),
2225        };
2226
2227        if dst_byte_offset < 0 {
2228            return self.base.webgl_error(InvalidValue);
2229        }
2230        let dst_byte_offset = dst_byte_offset as usize;
2231        if dst_byte_offset > dst.capacity() {
2232            return self.base.webgl_error(InvalidOperation);
2233        }
2234
2235        let ReadPixelsAllowedFormats {
2236            array_types: _,
2237            channels: bytes_per_pixel,
2238        } = match self.calc_read_pixel_formats(pixel_type, format) {
2239            Ok(result) => result,
2240            Err(error) => return self.base.webgl_error(error),
2241        };
2242        if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
2243            return self.base.webgl_error(InvalidOperation);
2244        }
2245
2246        let ReadPixelsSizes {
2247            row_stride: _,
2248            skipped_bytes,
2249            size,
2250        } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
2251            Ok(result) => result,
2252            Err(error) => return self.base.webgl_error(error),
2253        };
2254        let dst_end = dst_byte_offset + skipped_bytes + size;
2255        if dst.capacity() < dst_end {
2256            return self.base.webgl_error(InvalidOperation);
2257        }
2258
2259        {
2260            let (fb_width, fb_height) = handle_potential_webgl_error!(
2261                self.base,
2262                self.base
2263                    .get_current_framebuffer_size()
2264                    .ok_or(InvalidOperation),
2265                return
2266            );
2267            let src_origin = Point2D::new(x, y);
2268            let src_size = Size2D::new(width as u32, height as u32);
2269            let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
2270            if pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()).is_none() {
2271                return;
2272            }
2273        }
2274        let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
2275
2276        self.base.send_command(WebGLCommand::PixelStorei(
2277            constants::PACK_ALIGNMENT,
2278            self.base.get_texture_packing_alignment() as _,
2279        ));
2280        self.base.send_command(WebGLCommand::PixelStorei(
2281            constants::PACK_ROW_LENGTH,
2282            self.texture_pack_row_length.get() as _,
2283        ));
2284        self.base.send_command(WebGLCommand::PixelStorei(
2285            constants::PACK_SKIP_ROWS,
2286            self.texture_pack_skip_rows.get() as _,
2287        ));
2288        self.base.send_command(WebGLCommand::PixelStorei(
2289            constants::PACK_SKIP_PIXELS,
2290            self.texture_pack_skip_pixels.get() as _,
2291        ));
2292        self.base.send_command(WebGLCommand::ReadPixelsPP(
2293            src_rect,
2294            format,
2295            pixel_type,
2296            dst_byte_offset,
2297        ));
2298    }
2299
2300    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10>
2301    #[allow(unsafe_code)]
2302    fn ReadPixels__(
2303        &self,
2304        x: i32,
2305        y: i32,
2306        width: i32,
2307        height: i32,
2308        format: u32,
2309        pixel_type: u32,
2310        mut dst: CustomAutoRooterGuard<ArrayBufferView>,
2311        dst_elem_offset: u32,
2312    ) {
2313        self.read_pixels_into(
2314            x,
2315            y,
2316            width,
2317            height,
2318            format,
2319            pixel_type,
2320            &mut dst,
2321            dst_elem_offset,
2322        )
2323    }
2324
2325    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2326    fn SampleCoverage(&self, value: f32, invert: bool) {
2327        self.base.SampleCoverage(value, invert)
2328    }
2329
2330    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4>
2331    fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
2332        self.base.Scissor(x, y, width, height)
2333    }
2334
2335    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2336    fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
2337        self.base.StencilFunc(func, ref_, mask)
2338    }
2339
2340    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2341    fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
2342        self.base.StencilFuncSeparate(face, func, ref_, mask)
2343    }
2344
2345    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2346    fn StencilMask(&self, mask: u32) {
2347        self.base.StencilMask(mask)
2348    }
2349
2350    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2351    fn StencilMaskSeparate(&self, face: u32, mask: u32) {
2352        self.base.StencilMaskSeparate(face, mask)
2353    }
2354
2355    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2356    fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
2357        self.base.StencilOp(fail, zfail, zpass)
2358    }
2359
2360    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2361    fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
2362        self.base.StencilOpSeparate(face, fail, zfail, zpass)
2363    }
2364
2365    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2366    fn LinkProgram(&self, program: &WebGLProgram) {
2367        self.base.LinkProgram(program)
2368    }
2369
2370    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2371    fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
2372        self.base.ShaderSource(shader, source)
2373    }
2374
2375    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2376    fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
2377        self.base.GetShaderSource(shader)
2378    }
2379
2380    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2381    fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
2382        self.base.Uniform1f(location, val)
2383    }
2384
2385    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2386    fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
2387        self.base.Uniform1i(location, val)
2388    }
2389
2390    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2391    fn Uniform1iv(
2392        &self,
2393        location: Option<&WebGLUniformLocation>,
2394        v: Int32ArrayOrLongSequence,
2395        src_offset: u32,
2396        src_length: u32,
2397    ) {
2398        self.base.uniform1iv(location, v, src_offset, src_length)
2399    }
2400
2401    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2402    fn Uniform1ui(&self, location: Option<&WebGLUniformLocation>, val: u32) {
2403        self.base.with_location(location, |location| {
2404            match location.type_() {
2405                constants::BOOL | constants::UNSIGNED_INT => (),
2406                _ => return Err(InvalidOperation),
2407            }
2408            self.base
2409                .send_command(WebGLCommand::Uniform1ui(location.id(), val));
2410            Ok(())
2411        });
2412    }
2413
2414    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2415    fn Uniform1uiv(
2416        &self,
2417        location: Option<&WebGLUniformLocation>,
2418        val: Uint32ArrayOrUnsignedLongSequence,
2419        src_offset: u32,
2420        src_length: u32,
2421    ) {
2422        self.base.with_location(location, |location| {
2423            match location.type_() {
2424                constants::BOOL |
2425                constants::UNSIGNED_INT |
2426                constants::SAMPLER_2D |
2427                constants::SAMPLER_2D_ARRAY |
2428                constants::SAMPLER_3D |
2429                constants::SAMPLER_CUBE => {},
2430                _ => return Err(InvalidOperation),
2431            }
2432
2433            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 1, location)?;
2434
2435            match location.type_() {
2436                constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
2437                    for &v in val
2438                        .iter()
2439                        .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
2440                    {
2441                        if v >= self.base.limits().max_combined_texture_image_units {
2442                            return Err(InvalidValue);
2443                        }
2444                    }
2445                },
2446                _ => {},
2447            }
2448            self.base
2449                .send_command(WebGLCommand::Uniform1uiv(location.id(), val));
2450            Ok(())
2451        });
2452    }
2453
2454    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2455    fn Uniform1fv(
2456        &self,
2457        location: Option<&WebGLUniformLocation>,
2458        v: Float32ArrayOrUnrestrictedFloatSequence,
2459        src_offset: u32,
2460        src_length: u32,
2461    ) {
2462        self.base.uniform1fv(location, v, src_offset, src_length);
2463    }
2464
2465    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2466    fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
2467        self.base.Uniform2f(location, x, y)
2468    }
2469
2470    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2471    fn Uniform2fv(
2472        &self,
2473        location: Option<&WebGLUniformLocation>,
2474        v: Float32ArrayOrUnrestrictedFloatSequence,
2475        src_offset: u32,
2476        src_length: u32,
2477    ) {
2478        self.base.uniform2fv(location, v, src_offset, src_length);
2479    }
2480
2481    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2482    fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
2483        self.base.Uniform2i(location, x, y)
2484    }
2485
2486    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2487    fn Uniform2iv(
2488        &self,
2489        location: Option<&WebGLUniformLocation>,
2490        v: Int32ArrayOrLongSequence,
2491        src_offset: u32,
2492        src_length: u32,
2493    ) {
2494        self.base.uniform2iv(location, v, src_offset, src_length)
2495    }
2496
2497    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2498    fn Uniform2ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32) {
2499        self.base.with_location(location, |location| {
2500            match location.type_() {
2501                constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2502                _ => return Err(InvalidOperation),
2503            }
2504            self.base
2505                .send_command(WebGLCommand::Uniform2ui(location.id(), x, y));
2506            Ok(())
2507        });
2508    }
2509
2510    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2511    fn Uniform2uiv(
2512        &self,
2513        location: Option<&WebGLUniformLocation>,
2514        val: Uint32ArrayOrUnsignedLongSequence,
2515        src_offset: u32,
2516        src_length: u32,
2517    ) {
2518        self.base.with_location(location, |location| {
2519            match location.type_() {
2520                constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2521                _ => return Err(InvalidOperation),
2522            }
2523            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 2, location)?;
2524            self.base
2525                .send_command(WebGLCommand::Uniform2uiv(location.id(), val));
2526            Ok(())
2527        });
2528    }
2529
2530    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2531    fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
2532        self.base.Uniform3f(location, x, y, z)
2533    }
2534
2535    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2536    fn Uniform3fv(
2537        &self,
2538        location: Option<&WebGLUniformLocation>,
2539        v: Float32ArrayOrUnrestrictedFloatSequence,
2540        src_offset: u32,
2541        src_length: u32,
2542    ) {
2543        self.base.uniform3fv(location, v, src_offset, src_length);
2544    }
2545
2546    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2547    fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
2548        self.base.Uniform3i(location, x, y, z)
2549    }
2550
2551    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2552    fn Uniform3iv(
2553        &self,
2554        location: Option<&WebGLUniformLocation>,
2555        v: Int32ArrayOrLongSequence,
2556        src_offset: u32,
2557        src_length: u32,
2558    ) {
2559        self.base.uniform3iv(location, v, src_offset, src_length)
2560    }
2561
2562    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2563    fn Uniform3ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32) {
2564        self.base.with_location(location, |location| {
2565            match location.type_() {
2566                constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2567                _ => return Err(InvalidOperation),
2568            }
2569            self.base
2570                .send_command(WebGLCommand::Uniform3ui(location.id(), x, y, z));
2571            Ok(())
2572        });
2573    }
2574
2575    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2576    fn Uniform3uiv(
2577        &self,
2578        location: Option<&WebGLUniformLocation>,
2579        val: Uint32ArrayOrUnsignedLongSequence,
2580        src_offset: u32,
2581        src_length: u32,
2582    ) {
2583        self.base.with_location(location, |location| {
2584            match location.type_() {
2585                constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2586                _ => return Err(InvalidOperation),
2587            }
2588            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 3, location)?;
2589            self.base
2590                .send_command(WebGLCommand::Uniform3uiv(location.id(), val));
2591            Ok(())
2592        });
2593    }
2594
2595    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2596    fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
2597        self.base.Uniform4i(location, x, y, z, w)
2598    }
2599
2600    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2601    fn Uniform4iv(
2602        &self,
2603        location: Option<&WebGLUniformLocation>,
2604        v: Int32ArrayOrLongSequence,
2605        src_offset: u32,
2606        src_length: u32,
2607    ) {
2608        self.base.uniform4iv(location, v, src_offset, src_length)
2609    }
2610
2611    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2612    fn Uniform4ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32, w: u32) {
2613        self.base.with_location(location, |location| {
2614            match location.type_() {
2615                constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2616                _ => return Err(InvalidOperation),
2617            }
2618            self.base
2619                .send_command(WebGLCommand::Uniform4ui(location.id(), x, y, z, w));
2620            Ok(())
2621        });
2622    }
2623
2624    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2625    fn Uniform4uiv(
2626        &self,
2627        location: Option<&WebGLUniformLocation>,
2628        val: Uint32ArrayOrUnsignedLongSequence,
2629        src_offset: u32,
2630        src_length: u32,
2631    ) {
2632        self.base.with_location(location, |location| {
2633            match location.type_() {
2634                constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2635                _ => return Err(InvalidOperation),
2636            }
2637            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 4, location)?;
2638            self.base
2639                .send_command(WebGLCommand::Uniform4uiv(location.id(), val));
2640            Ok(())
2641        });
2642    }
2643
2644    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2645    fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
2646        self.base.Uniform4f(location, x, y, z, w)
2647    }
2648
2649    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2650    fn Uniform4fv(
2651        &self,
2652        location: Option<&WebGLUniformLocation>,
2653        v: Float32ArrayOrUnrestrictedFloatSequence,
2654        src_offset: u32,
2655        src_length: u32,
2656    ) {
2657        self.base.uniform4fv(location, v, src_offset, src_length);
2658    }
2659
2660    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2661    fn UniformMatrix2fv(
2662        &self,
2663        location: Option<&WebGLUniformLocation>,
2664        transpose: bool,
2665        v: Float32ArrayOrUnrestrictedFloatSequence,
2666        src_offset: u32,
2667        src_length: u32,
2668    ) {
2669        self.base
2670            .uniform_matrix_2fv(location, transpose, v, src_offset, src_length)
2671    }
2672
2673    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2674    fn UniformMatrix3fv(
2675        &self,
2676        location: Option<&WebGLUniformLocation>,
2677        transpose: bool,
2678        v: Float32ArrayOrUnrestrictedFloatSequence,
2679        src_offset: u32,
2680        src_length: u32,
2681    ) {
2682        self.base
2683            .uniform_matrix_3fv(location, transpose, v, src_offset, src_length)
2684    }
2685
2686    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2687    fn UniformMatrix4fv(
2688        &self,
2689        location: Option<&WebGLUniformLocation>,
2690        transpose: bool,
2691        v: Float32ArrayOrUnrestrictedFloatSequence,
2692        src_offset: u32,
2693        src_length: u32,
2694    ) {
2695        self.base
2696            .uniform_matrix_4fv(location, transpose, v, src_offset, src_length)
2697    }
2698
2699    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2700    fn UniformMatrix3x2fv(
2701        &self,
2702        location: Option<&WebGLUniformLocation>,
2703        transpose: bool,
2704        val: Float32ArrayOrUnrestrictedFloatSequence,
2705        src_offset: u32,
2706        src_length: u32,
2707    ) {
2708        self.base.with_location(location, |location| {
2709            match location.type_() {
2710                constants::FLOAT_MAT3x2 => {},
2711                _ => return Err(InvalidOperation),
2712            }
2713            let val = self.base.uniform_matrix_section(
2714                val,
2715                src_offset,
2716                src_length,
2717                transpose,
2718                3 * 2,
2719                location,
2720            )?;
2721            self.base
2722                .send_command(WebGLCommand::UniformMatrix3x2fv(location.id(), val));
2723            Ok(())
2724        });
2725    }
2726
2727    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2728    fn UniformMatrix4x2fv(
2729        &self,
2730        location: Option<&WebGLUniformLocation>,
2731        transpose: bool,
2732        val: Float32ArrayOrUnrestrictedFloatSequence,
2733        src_offset: u32,
2734        src_length: u32,
2735    ) {
2736        self.base.with_location(location, |location| {
2737            match location.type_() {
2738                constants::FLOAT_MAT4x2 => {},
2739                _ => return Err(InvalidOperation),
2740            }
2741            let val = self.base.uniform_matrix_section(
2742                val,
2743                src_offset,
2744                src_length,
2745                transpose,
2746                4 * 2,
2747                location,
2748            )?;
2749            self.base
2750                .send_command(WebGLCommand::UniformMatrix4x2fv(location.id(), val));
2751            Ok(())
2752        });
2753    }
2754
2755    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2756    fn UniformMatrix2x3fv(
2757        &self,
2758        location: Option<&WebGLUniformLocation>,
2759        transpose: bool,
2760        val: Float32ArrayOrUnrestrictedFloatSequence,
2761        src_offset: u32,
2762        src_length: u32,
2763    ) {
2764        self.base.with_location(location, |location| {
2765            match location.type_() {
2766                constants::FLOAT_MAT2x3 => {},
2767                _ => return Err(InvalidOperation),
2768            }
2769            let val = self.base.uniform_matrix_section(
2770                val,
2771                src_offset,
2772                src_length,
2773                transpose,
2774                2 * 3,
2775                location,
2776            )?;
2777            self.base
2778                .send_command(WebGLCommand::UniformMatrix2x3fv(location.id(), val));
2779            Ok(())
2780        });
2781    }
2782
2783    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2784    fn UniformMatrix4x3fv(
2785        &self,
2786        location: Option<&WebGLUniformLocation>,
2787        transpose: bool,
2788        val: Float32ArrayOrUnrestrictedFloatSequence,
2789        src_offset: u32,
2790        src_length: u32,
2791    ) {
2792        self.base.with_location(location, |location| {
2793            match location.type_() {
2794                constants::FLOAT_MAT4x3 => {},
2795                _ => return Err(InvalidOperation),
2796            }
2797            let val = self.base.uniform_matrix_section(
2798                val,
2799                src_offset,
2800                src_length,
2801                transpose,
2802                4 * 3,
2803                location,
2804            )?;
2805            self.base
2806                .send_command(WebGLCommand::UniformMatrix4x3fv(location.id(), val));
2807            Ok(())
2808        });
2809    }
2810
2811    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2812    fn UniformMatrix2x4fv(
2813        &self,
2814        location: Option<&WebGLUniformLocation>,
2815        transpose: bool,
2816        val: Float32ArrayOrUnrestrictedFloatSequence,
2817        src_offset: u32,
2818        src_length: u32,
2819    ) {
2820        self.base.with_location(location, |location| {
2821            match location.type_() {
2822                constants::FLOAT_MAT2x4 => {},
2823                _ => return Err(InvalidOperation),
2824            }
2825            let val = self.base.uniform_matrix_section(
2826                val,
2827                src_offset,
2828                src_length,
2829                transpose,
2830                2 * 4,
2831                location,
2832            )?;
2833            self.base
2834                .send_command(WebGLCommand::UniformMatrix2x4fv(location.id(), val));
2835            Ok(())
2836        });
2837    }
2838
2839    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2840    fn UniformMatrix3x4fv(
2841        &self,
2842        location: Option<&WebGLUniformLocation>,
2843        transpose: bool,
2844        val: Float32ArrayOrUnrestrictedFloatSequence,
2845        src_offset: u32,
2846        src_length: u32,
2847    ) {
2848        self.base.with_location(location, |location| {
2849            match location.type_() {
2850                constants::FLOAT_MAT3x4 => {},
2851                _ => return Err(InvalidOperation),
2852            }
2853            let val = self.base.uniform_matrix_section(
2854                val,
2855                src_offset,
2856                src_length,
2857                transpose,
2858                3 * 4,
2859                location,
2860            )?;
2861            self.base
2862                .send_command(WebGLCommand::UniformMatrix3x4fv(location.id(), val));
2863            Ok(())
2864        });
2865    }
2866
2867    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2868    #[allow(unsafe_code)]
2869    fn GetUniform(
2870        &self,
2871        cx: JSContext,
2872        program: &WebGLProgram,
2873        location: &WebGLUniformLocation,
2874        mut retval: MutableHandleValue,
2875    ) {
2876        handle_potential_webgl_error!(
2877            self.base,
2878            self.base.uniform_check_program(program, location),
2879            return retval.set(NullValue())
2880        );
2881
2882        let triple = (&*self.base, program.id(), location.id());
2883
2884        match location.type_() {
2885            constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get(
2886                triple,
2887                WebGLCommand::GetUniformUint,
2888            ))),
2889            constants::UNSIGNED_INT_VEC2 => unsafe {
2890                uniform_typed::<Uint32>(
2891                    *cx,
2892                    &uniform_get(triple, WebGLCommand::GetUniformUint2),
2893                    retval,
2894                )
2895            },
2896            constants::UNSIGNED_INT_VEC3 => unsafe {
2897                uniform_typed::<Uint32>(
2898                    *cx,
2899                    &uniform_get(triple, WebGLCommand::GetUniformUint3),
2900                    retval,
2901                )
2902            },
2903            constants::UNSIGNED_INT_VEC4 => unsafe {
2904                uniform_typed::<Uint32>(
2905                    *cx,
2906                    &uniform_get(triple, WebGLCommand::GetUniformUint4),
2907                    retval,
2908                )
2909            },
2910            constants::FLOAT_MAT2x3 => unsafe {
2911                uniform_typed::<Float32>(
2912                    *cx,
2913                    &uniform_get(triple, WebGLCommand::GetUniformFloat2x3),
2914                    retval,
2915                )
2916            },
2917            constants::FLOAT_MAT2x4 => unsafe {
2918                uniform_typed::<Float32>(
2919                    *cx,
2920                    &uniform_get(triple, WebGLCommand::GetUniformFloat2x4),
2921                    retval,
2922                )
2923            },
2924            constants::FLOAT_MAT3x2 => unsafe {
2925                uniform_typed::<Float32>(
2926                    *cx,
2927                    &uniform_get(triple, WebGLCommand::GetUniformFloat3x2),
2928                    retval,
2929                )
2930            },
2931            constants::FLOAT_MAT3x4 => unsafe {
2932                uniform_typed::<Float32>(
2933                    *cx,
2934                    &uniform_get(triple, WebGLCommand::GetUniformFloat3x4),
2935                    retval,
2936                )
2937            },
2938            constants::FLOAT_MAT4x2 => unsafe {
2939                uniform_typed::<Float32>(
2940                    *cx,
2941                    &uniform_get(triple, WebGLCommand::GetUniformFloat4x2),
2942                    retval,
2943                )
2944            },
2945            constants::FLOAT_MAT4x3 => unsafe {
2946                uniform_typed::<Float32>(
2947                    *cx,
2948                    &uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
2949                    retval,
2950                )
2951            },
2952            constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
2953                retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
2954            },
2955            _ => self.base.GetUniform(cx, program, location, retval),
2956        }
2957    }
2958
2959    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2960    fn UseProgram(&self, program: Option<&WebGLProgram>) {
2961        self.base.UseProgram(program)
2962    }
2963
2964    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2965    fn ValidateProgram(&self, program: &WebGLProgram) {
2966        self.base.ValidateProgram(program)
2967    }
2968
2969    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2970    fn VertexAttrib1f(&self, indx: u32, x: f32) {
2971        self.base.VertexAttrib1f(indx, x)
2972    }
2973
2974    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2975    fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2976        self.base.VertexAttrib1fv(indx, v)
2977    }
2978
2979    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2980    fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
2981        self.base.VertexAttrib2f(indx, x, y)
2982    }
2983
2984    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2985    fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2986        self.base.VertexAttrib2fv(indx, v)
2987    }
2988
2989    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2990    fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
2991        self.base.VertexAttrib3f(indx, x, y, z)
2992    }
2993
2994    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2995    fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2996        self.base.VertexAttrib3fv(indx, v)
2997    }
2998
2999    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
3000    fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
3001        self.base.VertexAttrib4f(indx, x, y, z, w)
3002    }
3003
3004    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
3005    fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
3006        self.base.VertexAttrib4fv(indx, v)
3007    }
3008
3009    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3010    fn VertexAttribI4i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
3011        self.vertex_attrib_i(index, x, y, z, w)
3012    }
3013
3014    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3015    fn VertexAttribI4iv(&self, index: u32, v: Int32ArrayOrLongSequence) {
3016        let values = match v {
3017            Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
3018            Int32ArrayOrLongSequence::LongSequence(v) => v,
3019        };
3020        if values.len() < 4 {
3021            return self.base.webgl_error(InvalidValue);
3022        }
3023        self.vertex_attrib_i(index, values[0], values[1], values[2], values[3]);
3024    }
3025
3026    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3027    fn VertexAttribI4ui(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
3028        self.vertex_attrib_u(index, x, y, z, w)
3029    }
3030
3031    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3032    fn VertexAttribI4uiv(&self, index: u32, v: Uint32ArrayOrUnsignedLongSequence) {
3033        let values = match v {
3034            Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
3035            Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
3036        };
3037        if values.len() < 4 {
3038            return self.base.webgl_error(InvalidValue);
3039        }
3040        self.vertex_attrib_u(index, values[0], values[1], values[2], values[3]);
3041    }
3042
3043    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
3044    fn VertexAttribPointer(
3045        &self,
3046        attrib_id: u32,
3047        size: i32,
3048        data_type: u32,
3049        normalized: bool,
3050        stride: i32,
3051        offset: i64,
3052    ) {
3053        self.base
3054            .VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset)
3055    }
3056
3057    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3058    fn VertexAttribIPointer(&self, index: u32, size: i32, type_: u32, stride: i32, offset: i64) {
3059        match type_ {
3060            constants::BYTE |
3061            constants::UNSIGNED_BYTE |
3062            constants::SHORT |
3063            constants::UNSIGNED_SHORT |
3064            constants::INT |
3065            constants::UNSIGNED_INT => {},
3066            _ => return self.base.webgl_error(InvalidEnum),
3067        };
3068        self.base
3069            .VertexAttribPointer(index, size, type_, false, stride, offset)
3070    }
3071
3072    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4>
3073    fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
3074        self.base.Viewport(x, y, width, height)
3075    }
3076
3077    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3078    ///
3079    /// Allocates and initializes the specified mipmap level of a three-dimensional or
3080    /// two-dimensional array texture.
3081    #[allow(unsafe_code)]
3082    fn TexImage3D(
3083        &self,
3084        target: u32,
3085        level: i32,
3086        internal_format: i32,
3087        width: i32,
3088        height: i32,
3089        depth: i32,
3090        border: i32,
3091        format: u32,
3092        type_: u32,
3093        src_data: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3094    ) -> Fallible<()> {
3095        // If a WebGLBuffer is bound to the PIXEL_UNPACK_BUFFER target,
3096        // generates an INVALID_OPERATION error.
3097        if self.bound_pixel_unpack_buffer.get().is_some() {
3098            self.base.webgl_error(InvalidOperation);
3099            return Ok(());
3100        }
3101
3102        // If type is specified as FLOAT_32_UNSIGNED_INT_24_8_REV, srcData must be null;
3103        // otherwise, generates an INVALID_OPERATION error.
3104        if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV && src_data.is_some() {
3105            self.base.webgl_error(InvalidOperation);
3106            return Ok(());
3107        }
3108
3109        if border != 0 {
3110            self.base.webgl_error(InvalidValue);
3111            return Ok(());
3112        }
3113
3114        let Ok(TexImage3DValidatorResult {
3115            width,
3116            height,
3117            depth,
3118            level,
3119            border,
3120            texture,
3121            target,
3122            internal_format,
3123            format,
3124            data_type,
3125        }) = TexImage3DValidator::new(
3126            &self.base,
3127            target,
3128            level,
3129            internal_format as u32,
3130            width,
3131            height,
3132            depth,
3133            border,
3134            format,
3135            type_,
3136            &src_data,
3137        )
3138        .validate()
3139        else {
3140            return Ok(());
3141        };
3142
3143        // TODO: If pixel store parameter constraints are not met, generates an INVALID_OPERATION error.
3144
3145        // If srcData is null, a buffer of sufficient size initialized to 0 is passed.
3146        let unpacking_alignment = self.base.texture_unpacking_alignment();
3147        let buff = match *src_data {
3148            Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
3149            None => {
3150                let element_size = data_type.element_size();
3151                let components = format.components();
3152                let components_per_element = format.components();
3153                // FIXME: This is copied from tex_image_2d which is apparently incorrect
3154                // NOTE: width and height are positive or zero due to validate()
3155                let expected_byte_len = if height == 0 {
3156                    0
3157                } else {
3158                    // We need to be careful here to not count unpack
3159                    // alignment at the end of the image, otherwise (for
3160                    // example) passing a single byte for uploading a 1x1
3161                    // GL_ALPHA/GL_UNSIGNED_BYTE texture would throw an error.
3162                    let cpp = element_size * components / components_per_element;
3163                    let stride =
3164                        (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
3165                    stride * (height - 1) + width * cpp
3166                };
3167                IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_len as usize])
3168            },
3169        };
3170        let (alpha_treatment, y_axis_treatment) =
3171            self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3172        // If UNPACK_FLIP_Y_WEBGL or UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to true, texImage3D and texSubImage3D
3173        // generate an INVALID_OPERATION error if they upload data from a PIXEL_UNPACK_BUFFER or a non-null client
3174        // side ArrayBufferView.
3175        if let (Some(AlphaTreatment::Premultiply), YAxisTreatment::Flipped) =
3176            (alpha_treatment, y_axis_treatment)
3177        {
3178            if src_data.is_some() {
3179                self.base.webgl_error(InvalidOperation);
3180                return Ok(());
3181            }
3182        }
3183        let tex_source = TexPixels::from_array(
3184            buff,
3185            Size2D::new(width, height),
3186            alpha_treatment,
3187            y_axis_treatment,
3188        );
3189
3190        self.tex_image_3d(
3191            &texture,
3192            target,
3193            data_type,
3194            internal_format,
3195            format,
3196            level,
3197            width,
3198            height,
3199            depth,
3200            border,
3201            unpacking_alignment,
3202            tex_source,
3203        );
3204        Ok(())
3205    }
3206
3207    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3208    fn TexImage2D(
3209        &self,
3210        target: u32,
3211        level: i32,
3212        internal_format: i32,
3213        width: i32,
3214        height: i32,
3215        border: i32,
3216        format: u32,
3217        data_type: u32,
3218        pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3219    ) -> Fallible<()> {
3220        self.base.TexImage2D(
3221            target,
3222            level,
3223            internal_format,
3224            width,
3225            height,
3226            border,
3227            format,
3228            data_type,
3229            pixels,
3230        )
3231    }
3232
3233    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3234    fn TexImage2D_(
3235        &self,
3236        target: u32,
3237        level: i32,
3238        internal_format: i32,
3239        format: u32,
3240        data_type: u32,
3241        source: TexImageSource,
3242    ) -> ErrorResult {
3243        self.base
3244            .TexImage2D_(target, level, internal_format, format, data_type, source)
3245    }
3246
3247    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3248    fn TexImage2D__(
3249        &self,
3250        target: u32,
3251        level: i32,
3252        internalformat: i32,
3253        width: i32,
3254        height: i32,
3255        border: i32,
3256        format: u32,
3257        type_: u32,
3258        pbo_offset: i64,
3259    ) -> Fallible<()> {
3260        let pixel_unpack_buffer = match self.bound_pixel_unpack_buffer.get() {
3261            Some(pixel_unpack_buffer) => pixel_unpack_buffer,
3262            None => {
3263                self.base.webgl_error(InvalidOperation);
3264                return Ok(());
3265            },
3266        };
3267
3268        if let Some(tf_buffer) = self.bound_transform_feedback_buffer.get() {
3269            if pixel_unpack_buffer == tf_buffer {
3270                self.base.webgl_error(InvalidOperation);
3271                return Ok(());
3272            }
3273        }
3274
3275        if pbo_offset < 0 || pbo_offset as usize > pixel_unpack_buffer.capacity() {
3276            self.base.webgl_error(InvalidValue);
3277            return Ok(());
3278        }
3279
3280        let unpacking_alignment = self.base.texture_unpacking_alignment();
3281
3282        let validator = TexImage2DValidator::new(
3283            &self.base,
3284            target,
3285            level,
3286            internalformat as u32,
3287            width,
3288            height,
3289            border,
3290            format,
3291            type_,
3292        );
3293
3294        let TexImage2DValidatorResult {
3295            texture,
3296            target,
3297            width,
3298            height,
3299            level,
3300            border,
3301            internal_format,
3302            format,
3303            data_type,
3304        } = match validator.validate() {
3305            Ok(result) => result,
3306            Err(_) => return Ok(()),
3307        };
3308
3309        self.base.tex_image_2d(
3310            &texture,
3311            target,
3312            data_type,
3313            internal_format,
3314            format,
3315            level,
3316            border,
3317            unpacking_alignment,
3318            Size2D::new(width, height),
3319            TexSource::BufferOffset(pbo_offset),
3320        );
3321
3322        Ok(())
3323    }
3324
3325    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3326    fn TexImage2D___(
3327        &self,
3328        target: u32,
3329        level: i32,
3330        internalformat: i32,
3331        width: i32,
3332        height: i32,
3333        border: i32,
3334        format: u32,
3335        type_: u32,
3336        source: TexImageSource,
3337    ) -> Fallible<()> {
3338        if self.bound_pixel_unpack_buffer.get().is_some() {
3339            self.base.webgl_error(InvalidOperation);
3340            return Ok(());
3341        }
3342
3343        let validator = TexImage2DValidator::new(
3344            &self.base,
3345            target,
3346            level,
3347            internalformat as u32,
3348            width,
3349            height,
3350            border,
3351            format,
3352            type_,
3353        );
3354
3355        let TexImage2DValidatorResult {
3356            texture,
3357            target,
3358            width: _,
3359            height: _,
3360            level,
3361            border,
3362            internal_format,
3363            format,
3364            data_type,
3365        } = match validator.validate() {
3366            Ok(result) => result,
3367            Err(_) => return Ok(()),
3368        };
3369
3370        let unpacking_alignment = self.base.texture_unpacking_alignment();
3371
3372        let pixels = match self.base.get_image_pixels(source)? {
3373            Some(pixels) => pixels,
3374            None => return Ok(()),
3375        };
3376
3377        self.base.tex_image_2d(
3378            &texture,
3379            target,
3380            data_type,
3381            internal_format,
3382            format,
3383            level,
3384            border,
3385            unpacking_alignment,
3386            pixels.size(),
3387            TexSource::Pixels(pixels),
3388        );
3389
3390        Ok(())
3391    }
3392
3393    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3394    #[allow(unsafe_code)]
3395    fn TexImage2D____(
3396        &self,
3397        target: u32,
3398        level: i32,
3399        internalformat: i32,
3400        width: i32,
3401        height: i32,
3402        border: i32,
3403        format: u32,
3404        type_: u32,
3405        src_data: CustomAutoRooterGuard<ArrayBufferView>,
3406        src_offset: u32,
3407    ) -> Fallible<()> {
3408        if self.bound_pixel_unpack_buffer.get().is_some() {
3409            self.base.webgl_error(InvalidOperation);
3410            return Ok(());
3411        }
3412
3413        if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV {
3414            self.base.webgl_error(InvalidOperation);
3415            return Ok(());
3416        }
3417
3418        let validator = TexImage2DValidator::new(
3419            &self.base,
3420            target,
3421            level,
3422            internalformat as u32,
3423            width,
3424            height,
3425            border,
3426            format,
3427            type_,
3428        );
3429
3430        let TexImage2DValidatorResult {
3431            texture,
3432            target,
3433            width,
3434            height,
3435            level,
3436            border,
3437            internal_format,
3438            format,
3439            data_type,
3440        } = match validator.validate() {
3441            Ok(result) => result,
3442            Err(_) => return Ok(()),
3443        };
3444
3445        let unpacking_alignment = self.base.texture_unpacking_alignment();
3446
3447        let src_elem_size = src_data.get_array_type().byte_size().unwrap();
3448        let src_byte_offset = src_offset as usize * src_elem_size;
3449
3450        if src_data.len() <= src_byte_offset {
3451            self.base.webgl_error(InvalidOperation);
3452            return Ok(());
3453        }
3454
3455        let buff = IpcSharedMemory::from_bytes(unsafe { &src_data.as_slice()[src_byte_offset..] });
3456
3457        let expected_byte_length = match self.base.validate_tex_image_2d_data(
3458            width,
3459            height,
3460            format,
3461            data_type,
3462            unpacking_alignment,
3463            Some(&*src_data),
3464        ) {
3465            Ok(byte_length) => byte_length,
3466            Err(()) => return Ok(()),
3467        };
3468
3469        if expected_byte_length as usize > buff.len() {
3470            self.base.webgl_error(InvalidOperation);
3471            return Ok(());
3472        }
3473
3474        let size = Size2D::new(width, height);
3475
3476        let (alpha_treatment, y_axis_treatment) =
3477            self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3478
3479        self.base.tex_image_2d(
3480            &texture,
3481            target,
3482            data_type,
3483            internal_format,
3484            format,
3485            level,
3486            border,
3487            unpacking_alignment,
3488            size,
3489            TexSource::Pixels(TexPixels::from_array(
3490                buff,
3491                size,
3492                alpha_treatment,
3493                y_axis_treatment,
3494            )),
3495        );
3496
3497        Ok(())
3498    }
3499
3500    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3501    fn TexSubImage2D(
3502        &self,
3503        target: u32,
3504        level: i32,
3505        xoffset: i32,
3506        yoffset: i32,
3507        width: i32,
3508        height: i32,
3509        format: u32,
3510        data_type: u32,
3511        pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3512    ) -> Fallible<()> {
3513        self.base.TexSubImage2D(
3514            target, level, xoffset, yoffset, width, height, format, data_type, pixels,
3515        )
3516    }
3517
3518    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3519    fn TexSubImage2D_(
3520        &self,
3521        target: u32,
3522        level: i32,
3523        xoffset: i32,
3524        yoffset: i32,
3525        format: u32,
3526        data_type: u32,
3527        source: TexImageSource,
3528    ) -> ErrorResult {
3529        self.base
3530            .TexSubImage2D_(target, level, xoffset, yoffset, format, data_type, source)
3531    }
3532
3533    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3534    fn TexParameterf(&self, target: u32, name: u32, value: f32) {
3535        self.base.TexParameterf(target, name, value)
3536    }
3537
3538    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3539    fn TexParameteri(&self, target: u32, name: u32, value: i32) {
3540        self.base.TexParameteri(target, name, value)
3541    }
3542
3543    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3544    fn CheckFramebufferStatus(&self, target: u32) -> u32 {
3545        let fb_slot = match target {
3546            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3547                self.base.get_draw_framebuffer_slot()
3548            },
3549            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3550            _ => {
3551                self.base.webgl_error(InvalidEnum);
3552                return 0;
3553            },
3554        };
3555        match fb_slot.get() {
3556            Some(fb) => fb.check_status(),
3557            None => constants::FRAMEBUFFER_COMPLETE,
3558        }
3559    }
3560
3561    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
3562    fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
3563        self.base
3564            .RenderbufferStorage(target, internal_format, width, height)
3565    }
3566
3567    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4S>
3568    fn BlitFramebuffer(
3569        &self,
3570        src_x0: i32,
3571        src_y0: i32,
3572        src_x1: i32,
3573        src_y1: i32,
3574        dst_x0: i32,
3575        dst_y0: i32,
3576        dst_x1: i32,
3577        dst_y1: i32,
3578        mask: u32,
3579        filter: u32,
3580    ) {
3581        bitflags! {
3582            struct BlitFrameBufferFlags: u32 {
3583                const DEPTH = constants::DEPTH_BUFFER_BIT;
3584                const COLOR = constants::COLOR_BUFFER_BIT;
3585                const STENCIL = constants::STENCIL_BUFFER_BIT;
3586                const DEPTH_STENCIL = constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT;
3587            }
3588        };
3589        let Some(bits) = BlitFrameBufferFlags::from_bits(mask) else {
3590            return self.base.webgl_error(InvalidValue);
3591        };
3592        let attributes = self.base.GetContextAttributes().unwrap();
3593
3594        if bits.intersects(BlitFrameBufferFlags::DEPTH_STENCIL) {
3595            match filter {
3596                constants::LINEAR => return self.base.webgl_error(InvalidOperation),
3597                constants::NEAREST => {},
3598                _ => return self.base.webgl_error(InvalidOperation),
3599            }
3600        }
3601
3602        let src_fb = self.base.get_read_framebuffer_slot().get();
3603        let dst_fb = self.base.get_draw_framebuffer_slot().get();
3604
3605        let get_default_formats = || -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> {
3606            // All attempts to blit to an antialiased back buffer should fail.
3607            if attributes.antialias {
3608                return Err(InvalidOperation);
3609            };
3610            let color = if attributes.alpha {
3611                Some(constants::RGBA8)
3612            } else {
3613                Some(constants::RGB8)
3614            };
3615            let (depth, stencil) = match (attributes.depth, attributes.stencil) {
3616                (true, true) => (
3617                    Some(constants::DEPTH24_STENCIL8),
3618                    Some(constants::DEPTH24_STENCIL8),
3619                ),
3620                (true, false) => (Some(constants::DEPTH_COMPONENT16), None),
3621                (false, true) => (None, Some(constants::STENCIL_INDEX8)),
3622                _ => (None, None),
3623            };
3624            Ok((color, depth, stencil))
3625        };
3626
3627        let (src_color, src_depth, src_stencil) = match src_fb {
3628            Some(fb) => {
3629                handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3630            },
3631            None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3632        };
3633        let (dst_color, dst_depth, dst_stencil) = match dst_fb {
3634            Some(fb) => {
3635                handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3636            },
3637            None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3638        };
3639
3640        if bits.intersects(BlitFrameBufferFlags::COLOR) && src_color != dst_color {
3641            return self.base.webgl_error(InvalidOperation);
3642        }
3643        if bits.intersects(BlitFrameBufferFlags::DEPTH) && src_depth != dst_depth {
3644            return self.base.webgl_error(InvalidOperation);
3645        }
3646        if bits.intersects(BlitFrameBufferFlags::STENCIL) && src_stencil != dst_stencil {
3647            return self.base.webgl_error(InvalidOperation);
3648        }
3649
3650        let src_width = src_x1.checked_sub(src_x0);
3651        let dst_width = dst_x1.checked_sub(dst_x0);
3652        let src_height = src_y1.checked_sub(src_y0);
3653        let dst_height = dst_y1.checked_sub(dst_y0);
3654
3655        if src_width.is_none() ||
3656            dst_width.is_none() ||
3657            src_height.is_none() ||
3658            dst_height.is_none()
3659        {
3660            return self.base.webgl_error(InvalidOperation);
3661        }
3662
3663        self.base.send_command(WebGLCommand::BlitFrameBuffer(
3664            src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
3665        ));
3666    }
3667
3668    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3669    fn FramebufferRenderbuffer(
3670        &self,
3671        target: u32,
3672        attachment: u32,
3673        renderbuffertarget: u32,
3674        rb: Option<&WebGLRenderbuffer>,
3675    ) {
3676        if let Some(rb) = rb {
3677            handle_potential_webgl_error!(self.base, self.base.validate_ownership(rb), return);
3678        }
3679
3680        let fb_slot = match target {
3681            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3682                self.base.get_draw_framebuffer_slot()
3683            },
3684            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3685            _ => return self.base.webgl_error(InvalidEnum),
3686        };
3687
3688        if renderbuffertarget != constants::RENDERBUFFER {
3689            return self.base.webgl_error(InvalidEnum);
3690        }
3691
3692        match fb_slot.get() {
3693            Some(fb) => match attachment {
3694                constants::DEPTH_STENCIL_ATTACHMENT => {
3695                    handle_potential_webgl_error!(
3696                        self.base,
3697                        fb.renderbuffer(constants::DEPTH_ATTACHMENT, rb)
3698                    );
3699                    handle_potential_webgl_error!(
3700                        self.base,
3701                        fb.renderbuffer(constants::STENCIL_ATTACHMENT, rb)
3702                    );
3703                },
3704                _ => handle_potential_webgl_error!(self.base, fb.renderbuffer(attachment, rb)),
3705            },
3706            None => self.base.webgl_error(InvalidOperation),
3707        };
3708    }
3709
3710    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3711    fn FramebufferTexture2D(
3712        &self,
3713        target: u32,
3714        attachment: u32,
3715        textarget: u32,
3716        texture: Option<&WebGLTexture>,
3717        level: i32,
3718    ) {
3719        if let Some(texture) = texture {
3720            handle_potential_webgl_error!(self.base, self.base.validate_ownership(texture), return);
3721        }
3722
3723        let fb_slot = match target {
3724            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3725                self.base.get_draw_framebuffer_slot()
3726            },
3727            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3728            _ => return self.base.webgl_error(InvalidEnum),
3729        };
3730        match fb_slot.get() {
3731            Some(fb) => handle_potential_webgl_error!(
3732                self.base,
3733                fb.texture2d(attachment, textarget, texture, level)
3734            ),
3735            None => self.base.webgl_error(InvalidOperation),
3736        }
3737    }
3738
3739    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
3740    fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
3741        self.base.GetAttachedShaders(program)
3742    }
3743
3744    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3745    fn DrawArraysInstanced(&self, mode: u32, first: i32, count: i32, primcount: i32) {
3746        self.validate_uniform_block_for_draw();
3747        self.validate_vertex_attribs_for_draw();
3748        handle_potential_webgl_error!(
3749            self.base,
3750            self.base
3751                .draw_arrays_instanced(mode, first, count, primcount)
3752        )
3753    }
3754
3755    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3756    fn DrawElementsInstanced(
3757        &self,
3758        mode: u32,
3759        count: i32,
3760        type_: u32,
3761        offset: i64,
3762        primcount: i32,
3763    ) {
3764        self.validate_uniform_block_for_draw();
3765        self.validate_vertex_attribs_for_draw();
3766        handle_potential_webgl_error!(
3767            self.base,
3768            self.base
3769                .draw_elements_instanced(mode, count, type_, offset, primcount)
3770        )
3771    }
3772
3773    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3774    fn DrawRangeElements(
3775        &self,
3776        mode: u32,
3777        start: u32,
3778        end: u32,
3779        count: i32,
3780        type_: u32,
3781        offset: i64,
3782    ) {
3783        if end < start {
3784            self.base.webgl_error(InvalidValue);
3785            return;
3786        }
3787        self.validate_uniform_block_for_draw();
3788        self.validate_vertex_attribs_for_draw();
3789        handle_potential_webgl_error!(
3790            self.base,
3791            self.base
3792                .draw_elements_instanced(mode, count, type_, offset, 1)
3793        )
3794    }
3795
3796    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3797    fn VertexAttribDivisor(&self, index: u32, divisor: u32) {
3798        self.base.vertex_attrib_divisor(index, divisor);
3799    }
3800
3801    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3802    fn CreateQuery(&self) -> Option<DomRoot<WebGLQuery>> {
3803        Some(WebGLQuery::new(&self.base, CanGc::note()))
3804    }
3805
3806    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3807    #[rustfmt::skip]
3808    fn DeleteQuery(&self, query: Option<&WebGLQuery>) {
3809        if let Some(query) = query {
3810            handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3811
3812            if let Some(query_target) = query.target() {
3813                let slot = match query_target {
3814                    constants::ANY_SAMPLES_PASSED |
3815                    constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3816                        &self.occlusion_query
3817                    },
3818                    constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3819                        &self.primitives_query
3820                    },
3821                    _ => unreachable!(),
3822                };
3823                if let Some(stored_query) = slot.get() {
3824                    if stored_query.target() == query.target() {
3825                        slot.set(None);
3826                    }
3827                }
3828            }
3829
3830            query.delete(Operation::Infallible);
3831        }
3832    }
3833
3834    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3835    fn IsQuery(&self, query: Option<&WebGLQuery>) -> bool {
3836        match query {
3837            Some(query) => self.base.validate_ownership(query).is_ok() && query.is_valid(),
3838            None => false,
3839        }
3840    }
3841
3842    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3843    fn CreateSampler(&self) -> Option<DomRoot<WebGLSampler>> {
3844        Some(WebGLSampler::new(&self.base, CanGc::note()))
3845    }
3846
3847    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3848    fn DeleteSampler(&self, sampler: Option<&WebGLSampler>) {
3849        if let Some(sampler) = sampler {
3850            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
3851            for slot in self.samplers.iter() {
3852                if slot.get().is_some_and(|s| sampler == &*s) {
3853                    slot.set(None);
3854                }
3855            }
3856            sampler.delete(Operation::Infallible);
3857        }
3858    }
3859
3860    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3861    fn IsSampler(&self, sampler: Option<&WebGLSampler>) -> bool {
3862        match sampler {
3863            Some(sampler) => self.base.validate_ownership(sampler).is_ok() && sampler.is_valid(),
3864            None => false,
3865        }
3866    }
3867
3868    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3869    #[rustfmt::skip]
3870    fn BeginQuery(&self, target: u32, query: &WebGLQuery) {
3871        handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3872
3873        let active_query = match target {
3874            constants::ANY_SAMPLES_PASSED |
3875            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3876                &self.occlusion_query
3877            },
3878            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3879                &self.primitives_query
3880            },
3881            _ => {
3882                self.base.webgl_error(InvalidEnum);
3883                return;
3884            },
3885        };
3886        if active_query.get().is_some() {
3887            self.base.webgl_error(InvalidOperation);
3888            return;
3889        }
3890        let result = query.begin(&self.base, target);
3891        match result {
3892            Ok(_) => active_query.set(Some(query)),
3893            Err(error) => self.base.webgl_error(error),
3894        }
3895    }
3896
3897    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3898    #[rustfmt::skip]
3899    fn EndQuery(&self, target: u32) {
3900        let active_query = match target {
3901            constants::ANY_SAMPLES_PASSED |
3902            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3903                self.occlusion_query.take()
3904            },
3905            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3906                self.primitives_query.take()
3907            },
3908            _ => {
3909                self.base.webgl_error(InvalidEnum);
3910                return;
3911            },
3912        };
3913        match active_query {
3914            None => self.base.webgl_error(InvalidOperation),
3915            Some(query) => {
3916                let result = query.end(&self.base, target);
3917                if let Err(error) = result {
3918                    self.base.webgl_error(error);
3919                }
3920            },
3921        }
3922    }
3923
3924    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3925    #[rustfmt::skip]
3926    fn GetQuery(&self, target: u32, pname: u32) -> Option<DomRoot<WebGLQuery>> {
3927        if pname != constants::CURRENT_QUERY {
3928            self.base.webgl_error(InvalidEnum);
3929            return None;
3930        }
3931        let active_query = match target {
3932            constants::ANY_SAMPLES_PASSED |
3933            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3934                self.occlusion_query.get()
3935            },
3936            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3937                self.primitives_query.get()
3938            },
3939            _ => {
3940                self.base.webgl_error(InvalidEnum);
3941                None
3942            },
3943        };
3944        if let Some(query) = active_query.as_ref() {
3945            if query.target() != Some(target) {
3946                return None;
3947            }
3948        }
3949        active_query
3950    }
3951
3952    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3953    #[rustfmt::skip]
3954    fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) {
3955        handle_potential_webgl_error!(
3956            self.base,
3957            self.base.validate_ownership(query),
3958            return retval.set(NullValue())
3959        );
3960        match query.get_parameter(&self.base, pname) {
3961            Ok(value) => match pname {
3962                constants::QUERY_RESULT => retval.set(UInt32Value(value)),
3963                constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)),
3964                _ => unreachable!(),
3965            },
3966            Err(error) => {
3967                self.base.webgl_error(error);
3968                retval.set(NullValue())
3969            },
3970        }
3971    }
3972
3973    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
3974    fn FenceSync(&self, condition: u32, flags: u32) -> Option<DomRoot<WebGLSync>> {
3975        if flags != 0 {
3976            self.base.webgl_error(InvalidValue);
3977            return None;
3978        }
3979        if condition != constants::SYNC_GPU_COMMANDS_COMPLETE {
3980            self.base.webgl_error(InvalidEnum);
3981            return None;
3982        }
3983
3984        Some(WebGLSync::new(&self.base, CanGc::note()))
3985    }
3986
3987    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
3988    fn IsSync(&self, sync: Option<&WebGLSync>) -> bool {
3989        match sync {
3990            Some(sync) => {
3991                if !sync.is_valid() {
3992                    return false;
3993                }
3994                handle_potential_webgl_error!(
3995                    self.base,
3996                    self.base.validate_ownership(sync),
3997                    return false
3998                );
3999                let (sender, receiver) = webgl_channel().unwrap();
4000                self.base
4001                    .send_command(WebGLCommand::IsSync(sync.id(), sender));
4002                receiver.recv().unwrap()
4003            },
4004            None => false,
4005        }
4006    }
4007
4008    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4009    fn ClientWaitSync(&self, sync: &WebGLSync, flags: u32, timeout: u64) -> u32 {
4010        if !sync.is_valid() {
4011            self.base.webgl_error(InvalidOperation);
4012            return constants::WAIT_FAILED;
4013        }
4014        handle_potential_webgl_error!(
4015            self.base,
4016            self.base.validate_ownership(sync),
4017            return constants::WAIT_FAILED
4018        );
4019        if flags != 0 && flags != constants::SYNC_FLUSH_COMMANDS_BIT {
4020            self.base.webgl_error(InvalidValue);
4021            return constants::WAIT_FAILED;
4022        }
4023        if timeout > self.base.limits().max_client_wait_timeout_webgl.as_nanos() as u64 {
4024            self.base.webgl_error(InvalidOperation);
4025            return constants::WAIT_FAILED;
4026        }
4027
4028        match sync.client_wait_sync(&self.base, flags, timeout) {
4029            Some(status) => status,
4030            None => constants::WAIT_FAILED,
4031        }
4032    }
4033
4034    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4035    fn WaitSync(&self, sync: &WebGLSync, flags: u32, timeout: i64) {
4036        if !sync.is_valid() {
4037            self.base.webgl_error(InvalidOperation);
4038            return;
4039        }
4040        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4041        if flags != 0 {
4042            self.base.webgl_error(InvalidValue);
4043            return;
4044        }
4045        if timeout != constants::TIMEOUT_IGNORED {
4046            self.base.webgl_error(InvalidValue);
4047            return;
4048        }
4049
4050        self.base
4051            .send_command(WebGLCommand::WaitSync(sync.id(), flags, timeout));
4052    }
4053
4054    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4055    fn GetSyncParameter(
4056        &self,
4057        _cx: JSContext,
4058        sync: &WebGLSync,
4059        pname: u32,
4060        mut retval: MutableHandleValue,
4061    ) {
4062        if !sync.is_valid() {
4063            self.base.webgl_error(InvalidOperation);
4064            return retval.set(NullValue());
4065        }
4066        handle_potential_webgl_error!(
4067            self.base,
4068            self.base.validate_ownership(sync),
4069            return retval.set(NullValue())
4070        );
4071        match pname {
4072            constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
4073                let (sender, receiver) = webgl_channel().unwrap();
4074                self.base
4075                    .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
4076                retval.set(UInt32Value(receiver.recv().unwrap()))
4077            },
4078            constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
4079                Some(status) => retval.set(UInt32Value(status)),
4080                None => retval.set(UInt32Value(constants::UNSIGNALED)),
4081            },
4082            _ => {
4083                self.base.webgl_error(InvalidEnum);
4084                retval.set(NullValue())
4085            },
4086        }
4087    }
4088
4089    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4090    fn DeleteSync(&self, sync: Option<&WebGLSync>) {
4091        if let Some(sync) = sync {
4092            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4093            sync.delete(Operation::Infallible);
4094        }
4095    }
4096
4097    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4098    fn BindSampler(&self, unit: u32, sampler: Option<&WebGLSampler>) {
4099        if let Some(sampler) = sampler {
4100            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4101
4102            if unit as usize >= self.samplers.len() {
4103                self.base.webgl_error(InvalidValue);
4104                return;
4105            }
4106
4107            let result = sampler.bind(&self.base, unit);
4108            match result {
4109                Ok(_) => self.samplers[unit as usize].set(Some(sampler)),
4110                Err(error) => self.base.webgl_error(error),
4111            }
4112        }
4113    }
4114
4115    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
4116    fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
4117        self.base.bind_vertex_array_webgl2(array);
4118    }
4119
4120    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4121    fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
4122        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4123        let param = WebGLSamplerValue::GLenum(param as u32);
4124        let result = sampler.set_parameter(&self.base, pname, param);
4125        if let Err(error) = result {
4126            self.base.webgl_error(error);
4127        }
4128    }
4129
4130    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4131    fn SamplerParameterf(&self, sampler: &WebGLSampler, pname: u32, param: f32) {
4132        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4133        let param = WebGLSamplerValue::Float(param);
4134        let result = sampler.set_parameter(&self.base, pname, param);
4135        if let Err(error) = result {
4136            self.base.webgl_error(error);
4137        }
4138    }
4139
4140    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4141    fn GetSamplerParameter(
4142        &self,
4143        _cx: JSContext,
4144        sampler: &WebGLSampler,
4145        pname: u32,
4146        mut retval: MutableHandleValue,
4147    ) {
4148        handle_potential_webgl_error!(
4149            self.base,
4150            self.base.validate_ownership(sampler),
4151            return retval.set(NullValue())
4152        );
4153        match sampler.get_parameter(&self.base, pname) {
4154            Ok(value) => match value {
4155                WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)),
4156                WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)),
4157            },
4158            Err(error) => {
4159                self.base.webgl_error(error);
4160                retval.set(NullValue())
4161            },
4162        }
4163    }
4164
4165    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4166    fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
4167        Some(WebGLTransformFeedback::new(&self.base, CanGc::note()))
4168    }
4169
4170    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4171    fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
4172        if let Some(tf) = tf {
4173            handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
4174            if tf.is_active() {
4175                self.base.webgl_error(InvalidOperation);
4176                return;
4177            }
4178            tf.delete(Operation::Infallible);
4179            self.current_transform_feedback.set(None);
4180        }
4181    }
4182
4183    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4184    fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
4185        match tf {
4186            Some(tf) => {
4187                if !tf.is_valid() {
4188                    return false;
4189                }
4190                handle_potential_webgl_error!(
4191                    self.base,
4192                    self.base.validate_ownership(tf),
4193                    return false
4194                );
4195                let (sender, receiver) = webgl_channel().unwrap();
4196                self.base
4197                    .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
4198                receiver.recv().unwrap()
4199            },
4200            None => false,
4201        }
4202    }
4203
4204    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4205    fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
4206        if target != constants::TRANSFORM_FEEDBACK {
4207            self.base.webgl_error(InvalidEnum);
4208            return;
4209        }
4210        match tf {
4211            Some(transform_feedback) => {
4212                handle_potential_webgl_error!(
4213                    self.base,
4214                    self.base.validate_ownership(transform_feedback),
4215                    return
4216                );
4217                if !transform_feedback.is_valid() {
4218                    self.base.webgl_error(InvalidOperation);
4219                    return;
4220                }
4221                if let Some(current_tf) = self.current_transform_feedback.get() {
4222                    if current_tf.is_active() && !current_tf.is_paused() {
4223                        self.base.webgl_error(InvalidOperation);
4224                        return;
4225                    }
4226                }
4227                transform_feedback.bind(&self.base, target);
4228                self.current_transform_feedback
4229                    .set(Some(transform_feedback));
4230            },
4231            None => self
4232                .base
4233                .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
4234        }
4235    }
4236
4237    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4238    #[allow(non_snake_case)]
4239    fn BeginTransformFeedback(&self, primitiveMode: u32) {
4240        match primitiveMode {
4241            constants::POINTS | constants::LINES | constants::TRIANGLES => {},
4242            _ => {
4243                self.base.webgl_error(InvalidEnum);
4244                return;
4245            },
4246        };
4247        let current_tf = match self.current_transform_feedback.get() {
4248            Some(current_tf) => current_tf,
4249            None => {
4250                self.base.webgl_error(InvalidOperation);
4251                return;
4252            },
4253        };
4254        if current_tf.is_active() {
4255            self.base.webgl_error(InvalidOperation);
4256            return;
4257        };
4258        let program = match self.base.current_program() {
4259            Some(program) => program,
4260            None => {
4261                self.base.webgl_error(InvalidOperation);
4262                return;
4263            },
4264        };
4265        if !program.is_linked() || program.transform_feedback_varyings_length() == 0 {
4266            self.base.webgl_error(InvalidOperation);
4267            return;
4268        };
4269        current_tf.begin(&self.base, primitiveMode);
4270    }
4271
4272    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4273    fn EndTransformFeedback(&self) {
4274        if let Some(current_tf) = self.current_transform_feedback.get() {
4275            if !current_tf.is_active() {
4276                self.base.webgl_error(InvalidOperation);
4277                return;
4278            }
4279            current_tf.end(&self.base);
4280        }
4281    }
4282
4283    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4284    fn ResumeTransformFeedback(&self) {
4285        if let Some(current_tf) = self.current_transform_feedback.get() {
4286            if !current_tf.is_active() || !current_tf.is_paused() {
4287                self.base.webgl_error(InvalidOperation);
4288                return;
4289            }
4290            current_tf.resume(&self.base);
4291        }
4292    }
4293
4294    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4295    fn PauseTransformFeedback(&self) {
4296        if let Some(current_tf) = self.current_transform_feedback.get() {
4297            if !current_tf.is_active() || current_tf.is_paused() {
4298                self.base.webgl_error(InvalidOperation);
4299                return;
4300            }
4301            current_tf.pause(&self.base);
4302        }
4303    }
4304
4305    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4306    #[allow(non_snake_case)]
4307    fn TransformFeedbackVaryings(
4308        &self,
4309        program: &WebGLProgram,
4310        varyings: Vec<DOMString>,
4311        bufferMode: u32,
4312    ) {
4313        handle_potential_webgl_error!(self.base, program.validate(), return);
4314        let strs = varyings
4315            .iter()
4316            .map(|name| String::from(name.to_owned()))
4317            .collect::<Vec<String>>();
4318        match bufferMode {
4319            constants::INTERLEAVED_ATTRIBS => {
4320                self.base
4321                    .send_command(WebGLCommand::TransformFeedbackVaryings(
4322                        program.id(),
4323                        strs,
4324                        bufferMode,
4325                    ));
4326            },
4327            constants::SEPARATE_ATTRIBS => {
4328                let max_tf_sp_att =
4329                    self.base.limits().max_transform_feedback_separate_attribs as usize;
4330                if strs.len() >= max_tf_sp_att {
4331                    self.base.webgl_error(InvalidValue);
4332                    return;
4333                }
4334                self.base
4335                    .send_command(WebGLCommand::TransformFeedbackVaryings(
4336                        program.id(),
4337                        strs,
4338                        bufferMode,
4339                    ));
4340            },
4341            _ => self.base.webgl_error(InvalidEnum),
4342        }
4343    }
4344
4345    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4346    fn GetTransformFeedbackVarying(
4347        &self,
4348        program: &WebGLProgram,
4349        index: u32,
4350    ) -> Option<DomRoot<WebGLActiveInfo>> {
4351        handle_potential_webgl_error!(self.base, program.validate(), return None);
4352        if index >= program.transform_feedback_varyings_length() as u32 {
4353            self.base.webgl_error(InvalidValue);
4354            return None;
4355        }
4356
4357        let (sender, receiver) = webgl_channel().unwrap();
4358        self.base
4359            .send_command(WebGLCommand::GetTransformFeedbackVarying(
4360                program.id(),
4361                index,
4362                sender,
4363            ));
4364        let (size, ty, name) = receiver.recv().unwrap();
4365        Some(WebGLActiveInfo::new(
4366            self.base.global().as_window(),
4367            size,
4368            ty,
4369            DOMString::from(name),
4370            CanGc::note(),
4371        ))
4372    }
4373
4374    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4375    fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
4376        let (generic_slot, indexed_bindings) = match target {
4377            constants::TRANSFORM_FEEDBACK_BUFFER => (
4378                &self.bound_transform_feedback_buffer,
4379                &self.indexed_transform_feedback_buffer_bindings,
4380            ),
4381            constants::UNIFORM_BUFFER => (
4382                &self.bound_uniform_buffer,
4383                &self.indexed_uniform_buffer_bindings,
4384            ),
4385            _ => return self.base.webgl_error(InvalidEnum),
4386        };
4387        let indexed_binding = match indexed_bindings.get(index as usize) {
4388            Some(slot) => slot,
4389            None => return self.base.webgl_error(InvalidValue),
4390        };
4391
4392        if let Some(buffer) = buffer {
4393            handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4394
4395            if buffer.is_marked_for_deletion() {
4396                return self.base.webgl_error(InvalidOperation);
4397            }
4398            handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4399
4400            // for both the generic and the indexed bindings
4401            buffer.increment_attached_counter();
4402            buffer.increment_attached_counter();
4403        }
4404
4405        self.base.send_command(WebGLCommand::BindBufferBase(
4406            target,
4407            index,
4408            buffer.map(|b| b.id()),
4409        ));
4410
4411        for slot in &[generic_slot, &indexed_binding.buffer] {
4412            if let Some(old) = slot.get() {
4413                old.decrement_attached_counter(Operation::Infallible);
4414            }
4415            slot.set(buffer);
4416        }
4417        indexed_binding.start.set(0);
4418        indexed_binding.size.set(0);
4419    }
4420
4421    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4422    fn BindBufferRange(
4423        &self,
4424        target: u32,
4425        index: u32,
4426        buffer: Option<&WebGLBuffer>,
4427        offset: i64,
4428        size: i64,
4429    ) {
4430        let (generic_slot, indexed_bindings) = match target {
4431            constants::TRANSFORM_FEEDBACK_BUFFER => (
4432                &self.bound_transform_feedback_buffer,
4433                &self.indexed_transform_feedback_buffer_bindings,
4434            ),
4435            constants::UNIFORM_BUFFER => (
4436                &self.bound_uniform_buffer,
4437                &self.indexed_uniform_buffer_bindings,
4438            ),
4439            _ => return self.base.webgl_error(InvalidEnum),
4440        };
4441        let indexed_binding = match indexed_bindings.get(index as usize) {
4442            Some(slot) => slot,
4443            None => return self.base.webgl_error(InvalidValue),
4444        };
4445
4446        if offset < 0 || size < 0 {
4447            return self.base.webgl_error(InvalidValue);
4448        }
4449        if buffer.is_some() && size == 0 {
4450            return self.base.webgl_error(InvalidValue);
4451        }
4452
4453        match target {
4454            constants::TRANSFORM_FEEDBACK_BUFFER => {
4455                if size % 4 != 0 && offset % 4 != 0 {
4456                    return self.base.webgl_error(InvalidValue);
4457                }
4458            },
4459            constants::UNIFORM_BUFFER => {
4460                let offset_alignment = self.base.limits().uniform_buffer_offset_alignment;
4461                if offset % offset_alignment as i64 != 0 {
4462                    return self.base.webgl_error(InvalidValue);
4463                }
4464            },
4465            _ => unreachable!(),
4466        }
4467
4468        if let Some(buffer) = buffer {
4469            handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4470
4471            if buffer.is_marked_for_deletion() {
4472                return self.base.webgl_error(InvalidOperation);
4473            }
4474            handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4475
4476            // for both the generic and the indexed bindings
4477            buffer.increment_attached_counter();
4478            buffer.increment_attached_counter();
4479        }
4480
4481        self.base.send_command(WebGLCommand::BindBufferRange(
4482            target,
4483            index,
4484            buffer.map(|b| b.id()),
4485            offset,
4486            size,
4487        ));
4488
4489        for slot in &[generic_slot, &indexed_binding.buffer] {
4490            if let Some(old) = slot.get() {
4491                old.decrement_attached_counter(Operation::Infallible);
4492            }
4493            slot.set(buffer);
4494        }
4495        indexed_binding.start.set(offset);
4496        indexed_binding.size.set(size);
4497    }
4498
4499    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4500    fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> {
4501        handle_potential_webgl_error!(
4502            self.base,
4503            self.base.validate_ownership(program),
4504            return None
4505        );
4506        let indices = handle_potential_webgl_error!(
4507            self.base,
4508            program.get_uniform_indices(names),
4509            return None
4510        );
4511        Some(indices)
4512    }
4513
4514    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4515    fn GetActiveUniforms(
4516        &self,
4517        cx: JSContext,
4518        program: &WebGLProgram,
4519        indices: Vec<u32>,
4520        pname: u32,
4521        mut rval: MutableHandleValue,
4522    ) {
4523        handle_potential_webgl_error!(
4524            self.base,
4525            self.base.validate_ownership(program),
4526            return rval.set(NullValue())
4527        );
4528        let values = handle_potential_webgl_error!(
4529            self.base,
4530            program.get_active_uniforms(indices, pname),
4531            return rval.set(NullValue())
4532        );
4533
4534        match pname {
4535            constants::UNIFORM_SIZE |
4536            constants::UNIFORM_TYPE |
4537            constants::UNIFORM_BLOCK_INDEX |
4538            constants::UNIFORM_OFFSET |
4539            constants::UNIFORM_ARRAY_STRIDE |
4540            constants::UNIFORM_MATRIX_STRIDE => {
4541                values.safe_to_jsval(cx, rval, CanGc::note());
4542            },
4543            constants::UNIFORM_IS_ROW_MAJOR => {
4544                let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
4545                values.safe_to_jsval(cx, rval, CanGc::note());
4546            },
4547            _ => unreachable!(),
4548        }
4549    }
4550
4551    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4552    fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 {
4553        handle_potential_webgl_error!(
4554            self.base,
4555            self.base.validate_ownership(program),
4556            return constants::INVALID_INDEX
4557        );
4558        handle_potential_webgl_error!(
4559            self.base,
4560            program.get_uniform_block_index(block_name),
4561            constants::INVALID_INDEX
4562        )
4563    }
4564
4565    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4566    #[allow(unsafe_code)]
4567    fn GetActiveUniformBlockParameter(
4568        &self,
4569        cx: JSContext,
4570        program: &WebGLProgram,
4571        block_index: u32,
4572        pname: u32,
4573        mut retval: MutableHandleValue,
4574    ) {
4575        handle_potential_webgl_error!(
4576            self.base,
4577            self.base.validate_ownership(program),
4578            return retval.set(NullValue())
4579        );
4580        let values = handle_potential_webgl_error!(
4581            self.base,
4582            program.get_active_uniform_block_parameter(block_index, pname),
4583            return retval.set(NullValue())
4584        );
4585        match pname {
4586            constants::UNIFORM_BLOCK_BINDING |
4587            constants::UNIFORM_BLOCK_DATA_SIZE |
4588            constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
4589                assert!(values.len() == 1);
4590                retval.set(UInt32Value(values[0] as u32))
4591            },
4592            constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
4593                let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
4594                rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
4595                Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap();
4596                retval.set(ObjectValue(result.get()))
4597            },
4598            constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
4599            constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
4600                assert!(values.len() == 1);
4601                retval.set(BooleanValue(values[0] != 0))
4602            },
4603            _ => unreachable!(),
4604        }
4605    }
4606
4607    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4608    fn GetActiveUniformBlockName(
4609        &self,
4610        program: &WebGLProgram,
4611        block_index: u32,
4612    ) -> Option<DOMString> {
4613        handle_potential_webgl_error!(
4614            self.base,
4615            self.base.validate_ownership(program),
4616            return None
4617        );
4618        let name = handle_potential_webgl_error!(
4619            self.base,
4620            program.get_active_uniform_block_name(block_index),
4621            return None
4622        );
4623        Some(DOMString::from(name))
4624    }
4625
4626    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4627    fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) {
4628        handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return);
4629
4630        if block_binding >= self.base.limits().max_uniform_buffer_bindings {
4631            return self.base.webgl_error(InvalidValue);
4632        }
4633
4634        handle_potential_webgl_error!(
4635            self.base,
4636            program.bind_uniform_block(block_index, block_binding)
4637        )
4638    }
4639
4640    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4641    fn ClearBufferfv(
4642        &self,
4643        buffer: u32,
4644        draw_buffer: i32,
4645        values: Float32ArrayOrUnrestrictedFloatSequence,
4646        src_offset: u32,
4647    ) {
4648        let array = match values {
4649            Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4650            Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4651        };
4652        self.clear_buffer::<f32>(
4653            buffer,
4654            draw_buffer,
4655            &[constants::COLOR, constants::DEPTH],
4656            src_offset,
4657            array,
4658            WebGLCommand::ClearBufferfv,
4659        )
4660    }
4661
4662    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4663    fn ClearBufferiv(
4664        &self,
4665        buffer: u32,
4666        draw_buffer: i32,
4667        values: Int32ArrayOrLongSequence,
4668        src_offset: u32,
4669    ) {
4670        let array = match values {
4671            Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
4672            Int32ArrayOrLongSequence::LongSequence(v) => v,
4673        };
4674        self.clear_buffer::<i32>(
4675            buffer,
4676            draw_buffer,
4677            &[constants::COLOR, constants::STENCIL],
4678            src_offset,
4679            array,
4680            WebGLCommand::ClearBufferiv,
4681        )
4682    }
4683
4684    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4685    fn ClearBufferuiv(
4686        &self,
4687        buffer: u32,
4688        draw_buffer: i32,
4689        values: Uint32ArrayOrUnsignedLongSequence,
4690        src_offset: u32,
4691    ) {
4692        let array = match values {
4693            Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
4694            Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
4695        };
4696        self.clear_buffer::<u32>(
4697            buffer,
4698            draw_buffer,
4699            &[constants::COLOR],
4700            src_offset,
4701            array,
4702            WebGLCommand::ClearBufferuiv,
4703        )
4704    }
4705
4706    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4707    fn ClearBufferfi(&self, buffer: u32, draw_buffer: i32, depth: f32, stencil: i32) {
4708        if buffer != constants::DEPTH_STENCIL {
4709            return self.base.webgl_error(InvalidEnum);
4710        }
4711
4712        handle_potential_webgl_error!(
4713            self.base,
4714            self.clearbuffer_array_size(buffer, draw_buffer),
4715            return
4716        );
4717
4718        self.base.send_command(WebGLCommand::ClearBufferfi(
4719            buffer,
4720            draw_buffer,
4721            depth,
4722            stencil,
4723        ));
4724    }
4725
4726    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4727    fn InvalidateFramebuffer(&self, target: u32, attachments: Vec<u32>) {
4728        if !self.valid_fb_attachment_values(target, &attachments) {
4729            return;
4730        }
4731
4732        self.base
4733            .send_command(WebGLCommand::InvalidateFramebuffer(target, attachments))
4734    }
4735
4736    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4737    fn InvalidateSubFramebuffer(
4738        &self,
4739        target: u32,
4740        attachments: Vec<u32>,
4741        x: i32,
4742        y: i32,
4743        width: i32,
4744        height: i32,
4745    ) {
4746        if !self.valid_fb_attachment_values(target, &attachments) {
4747            return;
4748        }
4749
4750        if width < 0 || height < 0 {
4751            return self.base.webgl_error(InvalidValue);
4752        }
4753
4754        self.base
4755            .send_command(WebGLCommand::InvalidateSubFramebuffer(
4756                target,
4757                attachments,
4758                x,
4759                y,
4760                width,
4761                height,
4762            ))
4763    }
4764
4765    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4766    fn FramebufferTextureLayer(
4767        &self,
4768        target: u32,
4769        attachment: u32,
4770        texture: Option<&WebGLTexture>,
4771        level: i32,
4772        layer: i32,
4773    ) {
4774        if let Some(tex) = texture {
4775            handle_potential_webgl_error!(self.base, self.base.validate_ownership(tex), return);
4776        }
4777
4778        let fb_slot = match target {
4779            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
4780                self.base.get_draw_framebuffer_slot()
4781            },
4782            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
4783            _ => return self.base.webgl_error(InvalidEnum),
4784        };
4785
4786        match fb_slot.get() {
4787            Some(fb) => handle_potential_webgl_error!(
4788                self.base,
4789                fb.texture_layer(attachment, texture, level, layer)
4790            ),
4791            None => self.base.webgl_error(InvalidOperation),
4792        }
4793    }
4794
4795    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5>
4796    #[allow(unsafe_code)]
4797    fn GetInternalformatParameter(
4798        &self,
4799        cx: JSContext,
4800        target: u32,
4801        internal_format: u32,
4802        pname: u32,
4803        mut retval: MutableHandleValue,
4804    ) {
4805        if target != constants::RENDERBUFFER {
4806            self.base.webgl_error(InvalidEnum);
4807            return retval.set(NullValue());
4808        }
4809
4810        match handle_potential_webgl_error!(
4811            self.base,
4812            InternalFormatParameter::from_u32(pname),
4813            return retval.set(NullValue())
4814        ) {
4815            InternalFormatParameter::IntVec(param) => unsafe {
4816                let (sender, receiver) = webgl_channel().unwrap();
4817                self.base
4818                    .send_command(WebGLCommand::GetInternalFormatIntVec(
4819                        target,
4820                        internal_format,
4821                        param,
4822                        sender,
4823                    ));
4824
4825                rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
4826                Int32Array::create(
4827                    *cx,
4828                    CreateWith::Slice(&receiver.recv().unwrap()),
4829                    rval.handle_mut(),
4830                )
4831                .unwrap();
4832                retval.set(ObjectValue(rval.get()))
4833            },
4834        }
4835    }
4836
4837    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5>
4838    fn RenderbufferStorageMultisample(
4839        &self,
4840        target: u32,
4841        samples: i32,
4842        internal_format: u32,
4843        width: i32,
4844        height: i32,
4845    ) {
4846        self.base
4847            .renderbuffer_storage(target, samples, internal_format, width, height)
4848    }
4849
4850    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4851    fn ReadBuffer(&self, src: u32) {
4852        match src {
4853            constants::BACK | constants::NONE => {},
4854            _ if self.base.valid_color_attachment_enum(src) => {},
4855            _ => return self.base.webgl_error(InvalidEnum),
4856        }
4857
4858        if let Some(fb) = self.base.get_read_framebuffer_slot().get() {
4859            handle_potential_webgl_error!(self.base, fb.set_read_buffer(src))
4860        } else {
4861            match src {
4862                constants::NONE | constants::BACK => {},
4863                _ => return self.base.webgl_error(InvalidOperation),
4864            }
4865
4866            self.default_fb_readbuffer.set(src);
4867            self.base.send_command(WebGLCommand::ReadBuffer(src));
4868        }
4869    }
4870
4871    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4872    fn DrawBuffers(&self, buffers: Vec<u32>) {
4873        if let Some(fb) = self.base.get_draw_framebuffer_slot().get() {
4874            handle_potential_webgl_error!(self.base, fb.set_draw_buffers(buffers))
4875        } else {
4876            if buffers.len() != 1 {
4877                return self.base.webgl_error(InvalidOperation);
4878            }
4879
4880            match buffers[0] {
4881                constants::NONE | constants::BACK => {},
4882                _ => return self.base.webgl_error(InvalidOperation),
4883            }
4884
4885            self.default_fb_drawbuffer.set(buffers[0]);
4886            self.base.send_command(WebGLCommand::DrawBuffers(buffers));
4887        }
4888    }
4889
4890    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
4891    fn TexStorage2D(
4892        &self,
4893        target: u32,
4894        levels: i32,
4895        internal_format: u32,
4896        width: i32,
4897        height: i32,
4898    ) {
4899        self.tex_storage(2, target, levels, internal_format, width, height, 1)
4900    }
4901
4902    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
4903    fn TexStorage3D(
4904        &self,
4905        target: u32,
4906        levels: i32,
4907        internal_format: u32,
4908        width: i32,
4909        height: i32,
4910        depth: i32,
4911    ) {
4912        self.tex_storage(3, target, levels, internal_format, width, height, depth)
4913    }
4914
4915    /// <https://immersive-web.github.io/webxr/#dom-webglrenderingcontextbase-makexrcompatible>
4916    #[cfg(feature = "webxr")]
4917    fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4918        // XXXManishearth Fill in with compatibility checks when rust-webxr supports this
4919        let p = Promise::new(&self.global(), can_gc);
4920        p.resolve_native(&(), can_gc);
4921        p
4922    }
4923}
4924
4925impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
4926    #[allow(unsafe_code)]
4927    fn canvas_data_source(self) -> Option<ImageKey> {
4928        let this = self.unsafe_get();
4929        unsafe { (*this.base.to_layout().unsafe_get()).layout_handle() }
4930    }
4931}
4932
4933impl WebGL2RenderingContextHelpers for WebGL2RenderingContext {
4934    fn is_webgl2_enabled(cx: JSContext, global: HandleObject) -> bool {
4935        Self::is_webgl2_enabled(cx, global)
4936    }
4937}