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);
698                },
699                Some(Texture(texture)) => {
700                    texture.safe_to_jsval(cx, rval);
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);
1046                return;
1047            },
1048            constants::SHADING_LANGUAGE_VERSION => {
1049                "WebGL GLSL ES 3.00".safe_to_jsval(cx, rval);
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);
1069                return;
1070            },
1071            constants::COPY_READ_BUFFER_BINDING => {
1072                self.bound_copy_read_buffer.get().safe_to_jsval(cx, rval);
1073                return;
1074            },
1075            constants::COPY_WRITE_BUFFER_BINDING => {
1076                self.bound_copy_write_buffer.get().safe_to_jsval(cx, rval);
1077                return;
1078            },
1079            constants::PIXEL_PACK_BUFFER_BINDING => {
1080                self.bound_pixel_pack_buffer.get().safe_to_jsval(cx, rval);
1081                return;
1082            },
1083            constants::PIXEL_UNPACK_BUFFER_BINDING => {
1084                self.bound_pixel_unpack_buffer.get().safe_to_jsval(cx, rval);
1085                return;
1086            },
1087            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => {
1088                self.bound_transform_feedback_buffer
1089                    .get()
1090                    .safe_to_jsval(cx, rval);
1091                return;
1092            },
1093            constants::UNIFORM_BUFFER_BINDING => {
1094                self.bound_uniform_buffer.get().safe_to_jsval(cx, rval);
1095                return;
1096            },
1097            constants::TRANSFORM_FEEDBACK_BINDING => {
1098                self.current_transform_feedback
1099                    .get()
1100                    .safe_to_jsval(cx, rval);
1101                return;
1102            },
1103            constants::ELEMENT_ARRAY_BUFFER_BINDING => {
1104                let buffer = self.current_vao().element_array_buffer().get();
1105                buffer.safe_to_jsval(cx, rval);
1106                return;
1107            },
1108            constants::VERTEX_ARRAY_BINDING => {
1109                let vao = self.current_vao();
1110                let vao = vao.id().map(|_| &*vao);
1111                vao.safe_to_jsval(cx, rval);
1112                return;
1113            },
1114            // NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side
1115            constants::READ_FRAMEBUFFER_BINDING => {
1116                self.base
1117                    .get_read_framebuffer_slot()
1118                    .get()
1119                    .safe_to_jsval(cx, rval);
1120                return;
1121            },
1122            constants::READ_BUFFER => {
1123                let buffer = match self.base.get_read_framebuffer_slot().get() {
1124                    Some(fb) => fb.read_buffer(),
1125                    None => self.default_fb_readbuffer.get(),
1126                };
1127                rval.set(UInt32Value(buffer));
1128                return;
1129            },
1130            constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
1131                let buffer = match self.base.get_read_framebuffer_slot().get() {
1132                    Some(fb) => {
1133                        let idx = parameter - constants::DRAW_BUFFER0;
1134                        fb.draw_buffer_i(idx as usize)
1135                    },
1136                    None if parameter == constants::DRAW_BUFFER0 => {
1137                        self.default_fb_readbuffer.get()
1138                    },
1139                    None => constants::NONE,
1140                };
1141                rval.set(UInt32Value(buffer));
1142                return;
1143            },
1144            constants::MAX_TEXTURE_LOD_BIAS => {
1145                rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64));
1146                return;
1147            },
1148            constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
1149                rval.set(DoubleValue(
1150                    self.base.limits().max_combined_fragment_uniform_components as f64,
1151                ));
1152                return;
1153            },
1154            constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
1155                rval.set(DoubleValue(
1156                    self.base.limits().max_combined_vertex_uniform_components as f64,
1157                ));
1158                return;
1159            },
1160            constants::MAX_ELEMENT_INDEX => {
1161                rval.set(DoubleValue(self.base.limits().max_element_index as f64));
1162                return;
1163            },
1164            constants::MAX_UNIFORM_BLOCK_SIZE => {
1165                rval.set(DoubleValue(
1166                    self.base.limits().max_uniform_block_size as f64,
1167                ));
1168                return;
1169            },
1170            constants::MIN_PROGRAM_TEXEL_OFFSET => {
1171                rval.set(Int32Value(self.base.limits().min_program_texel_offset));
1172                return;
1173            },
1174            _ => {},
1175        }
1176
1177        let limit = match parameter {
1178            constants::MAX_3D_TEXTURE_SIZE => Some(self.base.limits().max_3d_texture_size),
1179            constants::MAX_ARRAY_TEXTURE_LAYERS => {
1180                Some(self.base.limits().max_array_texture_layers)
1181            },
1182            constants::MAX_COLOR_ATTACHMENTS => Some(self.base.limits().max_color_attachments),
1183            constants::MAX_COMBINED_UNIFORM_BLOCKS => {
1184                Some(self.base.limits().max_combined_uniform_blocks)
1185            },
1186            constants::MAX_DRAW_BUFFERS => Some(self.base.limits().max_draw_buffers),
1187            constants::MAX_ELEMENTS_INDICES => Some(self.base.limits().max_elements_indices),
1188            constants::MAX_ELEMENTS_VERTICES => Some(self.base.limits().max_elements_vertices),
1189            constants::MAX_FRAGMENT_INPUT_COMPONENTS => {
1190                Some(self.base.limits().max_fragment_input_components)
1191            },
1192            constants::MAX_FRAGMENT_UNIFORM_BLOCKS => {
1193                Some(self.base.limits().max_fragment_uniform_blocks)
1194            },
1195            constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => {
1196                Some(self.base.limits().max_fragment_uniform_components)
1197            },
1198            constants::MAX_PROGRAM_TEXEL_OFFSET => {
1199                Some(self.base.limits().max_program_texel_offset)
1200            },
1201            constants::MAX_SAMPLES => Some(self.base.limits().max_samples),
1202            constants::MAX_UNIFORM_BUFFER_BINDINGS => {
1203                Some(self.base.limits().max_uniform_buffer_bindings)
1204            },
1205            constants::MAX_VARYING_COMPONENTS => Some(self.base.limits().max_varying_components),
1206            constants::MAX_VERTEX_OUTPUT_COMPONENTS => {
1207                Some(self.base.limits().max_vertex_output_components)
1208            },
1209            constants::MAX_VERTEX_UNIFORM_BLOCKS => {
1210                Some(self.base.limits().max_vertex_uniform_blocks)
1211            },
1212            constants::MAX_VERTEX_UNIFORM_COMPONENTS => {
1213                Some(self.base.limits().max_vertex_uniform_components)
1214            },
1215            constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => {
1216                Some(self.base.limits().uniform_buffer_offset_alignment)
1217            },
1218            _ => None,
1219        };
1220        if let Some(limit) = limit {
1221            rval.set(UInt32Value(limit));
1222            return;
1223        }
1224
1225        self.base.GetParameter(cx, parameter, rval)
1226    }
1227
1228    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1229    fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) {
1230        self.base.GetTexParameter(cx, target, pname, retval)
1231    }
1232
1233    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1234    fn GetError(&self) -> u32 {
1235        self.base.GetError()
1236    }
1237
1238    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.2>
1239    fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
1240        self.base.GetContextAttributes()
1241    }
1242
1243    // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.13
1244    fn IsContextLost(&self) -> bool {
1245        self.base.IsContextLost()
1246    }
1247
1248    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14>
1249    fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
1250        self.base.GetSupportedExtensions()
1251    }
1252
1253    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.14>
1254    fn GetExtension(&self, cx: JSContext, name: DOMString) -> Option<NonNull<JSObject>> {
1255        self.base.GetExtension(cx, name)
1256    }
1257
1258    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
1259    fn GetFramebufferAttachmentParameter(
1260        &self,
1261        cx: JSContext,
1262        target: u32,
1263        attachment: u32,
1264        pname: u32,
1265        mut rval: MutableHandleValue,
1266    ) {
1267        let fb_slot = match target {
1268            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
1269                self.base.get_draw_framebuffer_slot()
1270            },
1271            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
1272            _ => {
1273                self.base.webgl_error(InvalidEnum);
1274                rval.set(NullValue());
1275                return;
1276            },
1277        };
1278
1279        if let Some(fb) = fb_slot.get() {
1280            // A selected framebuffer is bound to the target
1281            handle_potential_webgl_error!(
1282                self.base,
1283                fb.validate_transparent(),
1284                return rval.set(NullValue())
1285            );
1286            handle_potential_webgl_error!(
1287                self.base,
1288                self.get_specific_fb_attachment_param(
1289                    cx,
1290                    &fb,
1291                    target,
1292                    attachment,
1293                    pname,
1294                    rval.reborrow()
1295                ),
1296                rval.set(NullValue())
1297            )
1298        } else {
1299            // The default framebuffer is bound to the target
1300            handle_potential_webgl_error!(
1301                self.base,
1302                self.get_default_fb_attachment_param(attachment, pname, rval.reborrow()),
1303                rval.set(NullValue())
1304            )
1305        }
1306    }
1307
1308    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1309    fn GetRenderbufferParameter(
1310        &self,
1311        cx: JSContext,
1312        target: u32,
1313        pname: u32,
1314        retval: MutableHandleValue,
1315    ) {
1316        self.base
1317            .GetRenderbufferParameter(cx, target, pname, retval)
1318    }
1319
1320    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1321    fn ActiveTexture(&self, texture: u32) {
1322        self.base.ActiveTexture(texture)
1323    }
1324
1325    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1326    fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
1327        self.base.BlendColor(r, g, b, a)
1328    }
1329
1330    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1331    fn BlendEquation(&self, mode: u32) {
1332        self.base.BlendEquation(mode)
1333    }
1334
1335    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1336    fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
1337        self.base.BlendEquationSeparate(mode_rgb, mode_alpha)
1338    }
1339
1340    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1341    fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
1342        self.base.BlendFunc(src_factor, dest_factor)
1343    }
1344
1345    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1346    fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
1347        self.base
1348            .BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1349    }
1350
1351    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1352    fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1353        self.base.AttachShader(program, shader)
1354    }
1355
1356    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1357    fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
1358        self.base.DetachShader(program, shader)
1359    }
1360
1361    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1362    fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
1363        self.base.BindAttribLocation(program, index, name)
1364    }
1365
1366    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
1367    fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
1368        let current_vao;
1369        let slot = match target {
1370            constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
1371            constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
1372            constants::PIXEL_PACK_BUFFER => &self.bound_pixel_pack_buffer,
1373            constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
1374            constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
1375            constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
1376            constants::ELEMENT_ARRAY_BUFFER => {
1377                current_vao = self.current_vao();
1378                current_vao.element_array_buffer()
1379            },
1380            _ => return self.base.BindBuffer(target, buffer),
1381        };
1382        self.base.bind_buffer_maybe(slot, target, buffer);
1383    }
1384
1385    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1386    fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
1387        handle_potential_webgl_error!(
1388            self.base,
1389            self.base.validate_new_framebuffer_binding(framebuffer),
1390            return
1391        );
1392
1393        let (bind_read, bind_draw) = match target {
1394            constants::FRAMEBUFFER => (true, true),
1395            constants::READ_FRAMEBUFFER => (true, false),
1396            constants::DRAW_FRAMEBUFFER => (false, true),
1397            _ => return self.base.webgl_error(InvalidEnum),
1398        };
1399        if bind_read {
1400            self.base.bind_framebuffer_to(
1401                target,
1402                framebuffer,
1403                self.base.get_read_framebuffer_slot(),
1404            );
1405        }
1406        if bind_draw {
1407            self.base.bind_framebuffer_to(
1408                target,
1409                framebuffer,
1410                self.base.get_draw_framebuffer_slot(),
1411            );
1412        }
1413    }
1414
1415    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1416    fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
1417        self.base.BindRenderbuffer(target, renderbuffer)
1418    }
1419
1420    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1421    fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
1422        self.base.BindTexture(target, texture)
1423    }
1424
1425    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1426    fn GenerateMipmap(&self, target: u32) {
1427        self.base.GenerateMipmap(target)
1428    }
1429
1430    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1431    fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
1432        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1433        let bound_buffer =
1434            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1435        self.base.buffer_data(target, data, usage, bound_buffer)
1436    }
1437
1438    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1439    fn BufferData(&self, target: u32, size: i64, usage: u32) {
1440        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1441        let bound_buffer =
1442            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1443        self.base.buffer_data_(target, size, usage, bound_buffer)
1444    }
1445
1446    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1447    #[allow(unsafe_code)]
1448    fn BufferData__(
1449        &self,
1450        target: u32,
1451        data: CustomAutoRooterGuard<ArrayBufferView>,
1452        usage: u32,
1453        elem_offset: u32,
1454        length: u32,
1455    ) {
1456        let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
1457        let bound_buffer =
1458            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1459        let bound_buffer =
1460            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1461
1462        let elem_size = data.get_array_type().byte_size().unwrap();
1463        let elem_count = data.len() / elem_size;
1464        let elem_offset = elem_offset as usize;
1465        let byte_offset = elem_offset * elem_size;
1466
1467        if byte_offset > data.len() {
1468            return self.base.webgl_error(InvalidValue);
1469        }
1470
1471        let copy_count = if length == 0 {
1472            elem_count - elem_offset
1473        } else {
1474            length as usize
1475        };
1476        if copy_count == 0 {
1477            return;
1478        }
1479        let copy_bytes = copy_count * elem_size;
1480
1481        if byte_offset + copy_bytes > data.len() {
1482            return self.base.webgl_error(InvalidValue);
1483        }
1484
1485        let data_end = byte_offset + copy_bytes;
1486        let data: &[u8] = unsafe { &data.as_slice()[byte_offset..data_end] };
1487        handle_potential_webgl_error!(self.base, bound_buffer.buffer_data(target, data, usage));
1488    }
1489
1490    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1491    fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
1492        let bound_buffer =
1493            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1494        self.base
1495            .buffer_sub_data(target, offset, data, bound_buffer)
1496    }
1497
1498    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1499    #[allow(unsafe_code)]
1500    fn BufferSubData_(
1501        &self,
1502        target: u32,
1503        dst_byte_offset: i64,
1504        src_data: CustomAutoRooterGuard<ArrayBufferView>,
1505        src_elem_offset: u32,
1506        length: u32,
1507    ) {
1508        let bound_buffer =
1509            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1510        let bound_buffer =
1511            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1512
1513        let src_elem_size = src_data.get_array_type().byte_size().unwrap();
1514        let src_elem_count = src_data.len() / src_elem_size;
1515        let src_elem_offset = src_elem_offset as usize;
1516        let src_byte_offset = src_elem_offset * src_elem_size;
1517
1518        if dst_byte_offset < 0 || src_byte_offset > src_data.len() {
1519            return self.base.webgl_error(InvalidValue);
1520        }
1521
1522        let copy_count = if length == 0 {
1523            src_elem_count - src_elem_offset
1524        } else {
1525            length as usize
1526        };
1527        if copy_count == 0 {
1528            return;
1529        }
1530        let copy_bytes = copy_count * src_elem_size;
1531
1532        let dst_byte_offset = dst_byte_offset as usize;
1533        if dst_byte_offset + copy_bytes > bound_buffer.capacity() ||
1534            src_byte_offset + copy_bytes > src_data.len()
1535        {
1536            return self.base.webgl_error(InvalidValue);
1537        }
1538
1539        let (sender, receiver) = ipc::bytes_channel().unwrap();
1540        self.base.send_command(WebGLCommand::BufferSubData(
1541            target,
1542            dst_byte_offset as isize,
1543            receiver,
1544        ));
1545        let src_end = src_byte_offset + copy_bytes;
1546        let data: &[u8] = unsafe { &src_data.as_slice()[src_byte_offset..src_end] };
1547        sender.send(data).unwrap();
1548    }
1549
1550    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1551    fn CopyBufferSubData(
1552        &self,
1553        read_target: u32,
1554        write_target: u32,
1555        read_offset: i64,
1556        write_offset: i64,
1557        size: i64,
1558    ) {
1559        if read_offset < 0 || write_offset < 0 || size < 0 {
1560            return self.base.webgl_error(InvalidValue);
1561        }
1562
1563        let read_buffer =
1564            handle_potential_webgl_error!(self.base, self.bound_buffer(read_target), return);
1565        let read_buffer =
1566            handle_potential_webgl_error!(self.base, read_buffer.ok_or(InvalidOperation), return);
1567
1568        let write_buffer =
1569            handle_potential_webgl_error!(self.base, self.bound_buffer(write_target), return);
1570        let write_buffer =
1571            handle_potential_webgl_error!(self.base, write_buffer.ok_or(InvalidOperation), return);
1572
1573        let read_until = read_offset + size;
1574        let write_until = write_offset + size;
1575        if read_until as usize > read_buffer.capacity() ||
1576            write_until as usize > write_buffer.capacity()
1577        {
1578            return self.base.webgl_error(InvalidValue);
1579        }
1580
1581        if read_target == write_target {
1582            let is_separate = read_until <= write_offset || write_until <= read_offset;
1583            if !is_separate {
1584                return self.base.webgl_error(InvalidValue);
1585            }
1586        }
1587        let src_is_elemarray = read_buffer
1588            .target()
1589            .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1590        let dst_is_elemarray = write_buffer
1591            .target()
1592            .is_some_and(|t| t == constants::ELEMENT_ARRAY_BUFFER);
1593        if src_is_elemarray != dst_is_elemarray {
1594            return self.base.webgl_error(InvalidOperation);
1595        }
1596
1597        self.base.send_command(WebGLCommand::CopyBufferSubData(
1598            read_target,
1599            write_target,
1600            read_offset,
1601            write_offset,
1602            size,
1603        ));
1604    }
1605
1606    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3>
1607    #[allow(unsafe_code)]
1608    fn GetBufferSubData(
1609        &self,
1610        target: u32,
1611        src_byte_offset: i64,
1612        mut dst_buffer: CustomAutoRooterGuard<ArrayBufferView>,
1613        dst_elem_offset: u32,
1614        length: u32,
1615    ) {
1616        let bound_buffer =
1617            handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
1618        let bound_buffer =
1619            handle_potential_webgl_error!(self.base, bound_buffer.ok_or(InvalidOperation), return);
1620
1621        let dst_elem_size = dst_buffer.get_array_type().byte_size().unwrap();
1622        let dst_elem_count = dst_buffer.len() / dst_elem_size;
1623        let dst_elem_offset = dst_elem_offset as usize;
1624        let dst_byte_offset = dst_elem_offset * dst_elem_size;
1625
1626        if src_byte_offset < 0 || dst_byte_offset > dst_buffer.len() {
1627            return self.base.webgl_error(InvalidValue);
1628        }
1629
1630        let copy_count = if length == 0 {
1631            dst_elem_count - dst_elem_offset
1632        } else {
1633            length as usize
1634        };
1635        if copy_count == 0 {
1636            return;
1637        }
1638        let copy_bytes = copy_count * dst_elem_size;
1639
1640        // TODO(mmatyas): Transform Feedback
1641
1642        let src_byte_offset = src_byte_offset as usize;
1643        if src_byte_offset + copy_bytes > bound_buffer.capacity() ||
1644            dst_byte_offset + copy_bytes > dst_buffer.len()
1645        {
1646            return self.base.webgl_error(InvalidValue);
1647        }
1648
1649        let (sender, receiver) = ipc::bytes_channel().unwrap();
1650        self.base.send_command(WebGLCommand::GetBufferSubData(
1651            target,
1652            src_byte_offset,
1653            copy_bytes,
1654            sender,
1655        ));
1656        let data = receiver.recv().unwrap();
1657        let dst_end = dst_byte_offset + copy_bytes;
1658        unsafe {
1659            dst_buffer.as_mut_slice()[dst_byte_offset..dst_end].copy_from_slice(&data);
1660        }
1661    }
1662
1663    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
1664    #[allow(unsafe_code)]
1665    fn CompressedTexImage2D(
1666        &self,
1667        target: u32,
1668        level: i32,
1669        internal_format: u32,
1670        width: i32,
1671        height: i32,
1672        border: i32,
1673        pixels: CustomAutoRooterGuard<ArrayBufferView>,
1674        src_offset: u32,
1675        src_length_override: u32,
1676    ) {
1677        let mut data = unsafe { pixels.as_slice() };
1678        let start = src_offset as usize;
1679        let end = (src_offset + src_length_override) as usize;
1680        if start > data.len() || end > data.len() {
1681            self.base.webgl_error(InvalidValue);
1682            return;
1683        }
1684        if src_length_override != 0 {
1685            data = &data[start..end];
1686        }
1687        self.base.compressed_tex_image_2d(
1688            target,
1689            level,
1690            internal_format,
1691            width,
1692            height,
1693            border,
1694            data,
1695        )
1696    }
1697
1698    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1699    #[allow(unsafe_code)]
1700    fn CompressedTexSubImage2D(
1701        &self,
1702        target: u32,
1703        level: i32,
1704        xoffset: i32,
1705        yoffset: i32,
1706        width: i32,
1707        height: i32,
1708        format: u32,
1709        pixels: CustomAutoRooterGuard<ArrayBufferView>,
1710        src_offset: u32,
1711        src_length_override: u32,
1712    ) {
1713        let mut data = unsafe { pixels.as_slice() };
1714        let start = src_offset as usize;
1715        let end = (src_offset + src_length_override) as usize;
1716        if start > data.len() || end > data.len() {
1717            self.base.webgl_error(InvalidValue);
1718            return;
1719        }
1720        if src_length_override != 0 {
1721            data = &data[start..end];
1722        }
1723        self.base.compressed_tex_sub_image_2d(
1724            target, level, xoffset, yoffset, width, height, format, data,
1725        )
1726    }
1727
1728    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1729    fn CopyTexImage2D(
1730        &self,
1731        target: u32,
1732        level: i32,
1733        internal_format: u32,
1734        x: i32,
1735        y: i32,
1736        width: i32,
1737        height: i32,
1738        border: i32,
1739    ) {
1740        self.base
1741            .CopyTexImage2D(target, level, internal_format, x, y, width, height, border)
1742    }
1743
1744    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1745    fn CopyTexSubImage2D(
1746        &self,
1747        target: u32,
1748        level: i32,
1749        xoffset: i32,
1750        yoffset: i32,
1751        x: i32,
1752        y: i32,
1753        width: i32,
1754        height: i32,
1755    ) {
1756        self.base
1757            .CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height)
1758    }
1759
1760    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1761    fn Clear(&self, mask: u32) {
1762        self.base.Clear(mask)
1763    }
1764
1765    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1766    fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
1767        self.base.ClearColor(red, green, blue, alpha)
1768    }
1769
1770    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1771    fn ClearDepth(&self, depth: f32) {
1772        self.base.ClearDepth(depth)
1773    }
1774
1775    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1776    fn ClearStencil(&self, stencil: i32) {
1777        self.base.ClearStencil(stencil)
1778    }
1779
1780    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1781    fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
1782        self.base.ColorMask(r, g, b, a)
1783    }
1784
1785    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1786    fn CullFace(&self, mode: u32) {
1787        self.base.CullFace(mode)
1788    }
1789
1790    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1791    fn FrontFace(&self, mode: u32) {
1792        self.base.FrontFace(mode)
1793    }
1794    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1795    fn DepthFunc(&self, func: u32) {
1796        self.base.DepthFunc(func)
1797    }
1798
1799    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1800    fn DepthMask(&self, flag: bool) {
1801        self.base.DepthMask(flag)
1802    }
1803
1804    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1805    fn DepthRange(&self, near: f32, far: f32) {
1806        self.base.DepthRange(near, far)
1807    }
1808
1809    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1810    fn Enable(&self, cap: u32) {
1811        match cap {
1812            constants::RASTERIZER_DISCARD => {
1813                self.enable_rasterizer_discard.set(true);
1814                self.base.send_command(WebGLCommand::Enable(cap));
1815            },
1816            _ => self.base.Enable(cap),
1817        }
1818    }
1819
1820    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
1821    fn Disable(&self, cap: u32) {
1822        match cap {
1823            constants::RASTERIZER_DISCARD => {
1824                self.enable_rasterizer_discard.set(false);
1825                self.base.send_command(WebGLCommand::Disable(cap));
1826            },
1827            _ => self.base.Disable(cap),
1828        }
1829    }
1830
1831    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1832    fn CompileShader(&self, shader: &WebGLShader) {
1833        self.base.CompileShader(shader)
1834    }
1835
1836    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1837    fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1838        self.base.CreateBuffer()
1839    }
1840
1841    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1842    fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
1843        self.base.CreateFramebuffer()
1844    }
1845
1846    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1847    fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
1848        self.base.CreateRenderbuffer()
1849    }
1850
1851    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1852    fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
1853        self.base.CreateTexture()
1854    }
1855
1856    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1857    fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
1858        self.base.CreateProgram()
1859    }
1860
1861    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1862    fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
1863        self.base.CreateShader(shader_type)
1864    }
1865
1866    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
1867    fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1868        self.base.create_vertex_array_webgl2()
1869    }
1870
1871    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
1872    fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
1873        let buffer = match buffer {
1874            Some(buffer) => buffer,
1875            None => return,
1876        };
1877        handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
1878        if buffer.is_marked_for_deletion() {
1879            return;
1880        }
1881        self.current_vao().unbind_buffer(buffer);
1882        self.unbind_from(self.base.array_buffer_slot(), buffer);
1883        self.unbind_from(&self.bound_copy_read_buffer, buffer);
1884        self.unbind_from(&self.bound_copy_write_buffer, buffer);
1885        self.unbind_from(&self.bound_pixel_pack_buffer, buffer);
1886        self.unbind_from(&self.bound_pixel_unpack_buffer, buffer);
1887        self.unbind_from(&self.bound_transform_feedback_buffer, buffer);
1888        self.unbind_from(&self.bound_uniform_buffer, buffer);
1889
1890        for binding in self.indexed_uniform_buffer_bindings.iter() {
1891            self.unbind_from(&binding.buffer, buffer);
1892        }
1893        for binding in self.indexed_transform_feedback_buffer_bindings.iter() {
1894            self.unbind_from(&binding.buffer, buffer);
1895        }
1896
1897        buffer.mark_for_deletion(Operation::Infallible);
1898    }
1899
1900    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
1901    fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
1902        self.base.DeleteFramebuffer(framebuffer)
1903    }
1904
1905    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
1906    fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
1907        self.base.DeleteRenderbuffer(renderbuffer)
1908    }
1909
1910    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
1911    fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
1912        self.base.DeleteTexture(texture)
1913    }
1914
1915    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1916    fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
1917        self.base.DeleteProgram(program)
1918    }
1919
1920    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1921    fn DeleteShader(&self, shader: Option<&WebGLShader>) {
1922        self.base.DeleteShader(shader)
1923    }
1924
1925    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
1926    fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
1927        self.base.delete_vertex_array_webgl2(vertex_array);
1928    }
1929
1930    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1931    fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
1932        self.validate_uniform_block_for_draw();
1933        self.validate_vertex_attribs_for_draw();
1934        self.base.DrawArrays(mode, first, count)
1935    }
1936
1937    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11>
1938    fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
1939        self.validate_uniform_block_for_draw();
1940        self.validate_vertex_attribs_for_draw();
1941        self.base.DrawElements(mode, count, type_, offset)
1942    }
1943
1944    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1945    fn EnableVertexAttribArray(&self, attrib_id: u32) {
1946        self.base.EnableVertexAttribArray(attrib_id)
1947    }
1948
1949    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1950    fn DisableVertexAttribArray(&self, attrib_id: u32) {
1951        self.base.DisableVertexAttribArray(attrib_id)
1952    }
1953
1954    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1955    fn GetActiveUniform(
1956        &self,
1957        program: &WebGLProgram,
1958        index: u32,
1959    ) -> Option<DomRoot<WebGLActiveInfo>> {
1960        self.base.GetActiveUniform(program, index)
1961    }
1962
1963    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1964    fn GetActiveAttrib(
1965        &self,
1966        program: &WebGLProgram,
1967        index: u32,
1968    ) -> Option<DomRoot<WebGLActiveInfo>> {
1969        self.base.GetActiveAttrib(program, index)
1970    }
1971
1972    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
1973    fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1974        self.base.GetAttribLocation(program, name)
1975    }
1976
1977    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.7>
1978    fn GetFragDataLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
1979        handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return -1);
1980        handle_potential_webgl_error!(self.base, program.get_frag_data_location(name), -1)
1981    }
1982
1983    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1984    fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
1985        self.base.GetProgramInfoLog(program)
1986    }
1987
1988    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
1989    fn GetProgramParameter(
1990        &self,
1991        cx: JSContext,
1992        program: &WebGLProgram,
1993        param_id: u32,
1994        mut retval: MutableHandleValue,
1995    ) {
1996        handle_potential_webgl_error!(
1997            self.base,
1998            self.base.validate_ownership(program),
1999            return retval.set(NullValue())
2000        );
2001        if program.is_deleted() {
2002            self.base.webgl_error(InvalidOperation);
2003            return retval.set(NullValue());
2004        }
2005        match param_id {
2006            constants::TRANSFORM_FEEDBACK_VARYINGS => {
2007                retval.set(Int32Value(program.transform_feedback_varyings_length()))
2008            },
2009            constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
2010                retval.set(Int32Value(program.transform_feedback_buffer_mode()))
2011            },
2012            _ => self.base.GetProgramParameter(cx, program, param_id, retval),
2013        }
2014    }
2015
2016    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2017    fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
2018        self.base.GetShaderInfoLog(shader)
2019    }
2020
2021    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2022    fn GetShaderParameter(
2023        &self,
2024        cx: JSContext,
2025        shader: &WebGLShader,
2026        param_id: u32,
2027        retval: MutableHandleValue,
2028    ) {
2029        self.base.GetShaderParameter(cx, shader, param_id, retval)
2030    }
2031
2032    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2033    fn GetShaderPrecisionFormat(
2034        &self,
2035        shader_type: u32,
2036        precision_type: u32,
2037    ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
2038        self.base
2039            .GetShaderPrecisionFormat(shader_type, precision_type)
2040    }
2041
2042    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2043    fn GetIndexedParameter(
2044        &self,
2045        cx: JSContext,
2046        target: u32,
2047        index: u32,
2048        mut retval: MutableHandleValue,
2049    ) {
2050        let bindings = match target {
2051            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
2052            constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
2053            constants::TRANSFORM_FEEDBACK_BUFFER_START => {
2054                &self.indexed_transform_feedback_buffer_bindings
2055            },
2056            constants::UNIFORM_BUFFER_BINDING |
2057            constants::UNIFORM_BUFFER_SIZE |
2058            constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
2059            _ => {
2060                self.base.webgl_error(InvalidEnum);
2061                return retval.set(NullValue());
2062            },
2063        };
2064
2065        let binding = match bindings.get(index as usize) {
2066            Some(binding) => binding,
2067            None => {
2068                self.base.webgl_error(InvalidValue);
2069                return retval.set(NullValue());
2070            },
2071        };
2072
2073        match target {
2074            constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => {
2075                binding.buffer.get().safe_to_jsval(cx, retval)
2076            },
2077            constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
2078                retval.set(Int32Value(binding.start.get() as _))
2079            },
2080            constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
2081                retval.set(Int32Value(binding.size.get() as _))
2082            },
2083            _ => unreachable!(),
2084        }
2085    }
2086
2087    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2088    fn GetUniformLocation(
2089        &self,
2090        program: &WebGLProgram,
2091        name: DOMString,
2092    ) -> Option<DomRoot<WebGLUniformLocation>> {
2093        self.base.GetUniformLocation(program, name)
2094    }
2095
2096    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2097    fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) {
2098        self.base.GetVertexAttrib(cx, index, pname, retval)
2099    }
2100
2101    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2102    fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
2103        self.base.GetVertexAttribOffset(index, pname)
2104    }
2105
2106    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2107    fn Hint(&self, target: u32, mode: u32) {
2108        self.base.Hint(target, mode)
2109    }
2110
2111    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
2112    fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
2113        self.base.IsBuffer(buffer)
2114    }
2115
2116    // TODO: We could write this without IPC, recording the calls to `enable` and `disable`.
2117    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2118    fn IsEnabled(&self, cap: u32) -> bool {
2119        match cap {
2120            constants::RASTERIZER_DISCARD => self.enable_rasterizer_discard.get(),
2121            _ => self.base.IsEnabled(cap),
2122        }
2123    }
2124
2125    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
2126    fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
2127        self.base.IsFramebuffer(frame_buffer)
2128    }
2129
2130    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2131    fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
2132        self.base.IsProgram(program)
2133    }
2134
2135    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
2136    fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
2137        self.base.IsRenderbuffer(render_buffer)
2138    }
2139
2140    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2141    fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
2142        self.base.IsShader(shader)
2143    }
2144
2145    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
2146    fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
2147        self.base.IsTexture(texture)
2148    }
2149
2150    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
2151    fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
2152        self.base.is_vertex_array_webgl2(vertex_array)
2153    }
2154
2155    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2156    fn LineWidth(&self, width: f32) {
2157        self.base.LineWidth(width)
2158    }
2159
2160    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
2161    fn PixelStorei(&self, param_name: u32, param_value: i32) {
2162        if param_value < 0 {
2163            return self.base.webgl_error(InvalidValue);
2164        }
2165
2166        match param_name {
2167            constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
2168            constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
2169            constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
2170            _ => self.base.PixelStorei(param_name, param_value),
2171        }
2172    }
2173
2174    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2175    fn PolygonOffset(&self, factor: f32, units: f32) {
2176        self.base.PolygonOffset(factor, units)
2177    }
2178
2179    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.12>
2180    fn ReadPixels(
2181        &self,
2182        x: i32,
2183        y: i32,
2184        width: i32,
2185        height: i32,
2186        format: u32,
2187        pixel_type: u32,
2188        mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
2189    ) {
2190        let pixels =
2191            handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
2192
2193        self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
2194    }
2195
2196    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10>
2197    fn ReadPixels_(
2198        &self,
2199        x: i32,
2200        y: i32,
2201        width: i32,
2202        height: i32,
2203        format: u32,
2204        pixel_type: u32,
2205        dst_byte_offset: i64,
2206    ) {
2207        handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
2208
2209        let dst = match self.bound_pixel_pack_buffer.get() {
2210            Some(buffer) => buffer,
2211            None => return self.base.webgl_error(InvalidOperation),
2212        };
2213
2214        if dst_byte_offset < 0 {
2215            return self.base.webgl_error(InvalidValue);
2216        }
2217        let dst_byte_offset = dst_byte_offset as usize;
2218        if dst_byte_offset > dst.capacity() {
2219            return self.base.webgl_error(InvalidOperation);
2220        }
2221
2222        let ReadPixelsAllowedFormats {
2223            array_types: _,
2224            channels: bytes_per_pixel,
2225        } = match self.calc_read_pixel_formats(pixel_type, format) {
2226            Ok(result) => result,
2227            Err(error) => return self.base.webgl_error(error),
2228        };
2229        if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
2230            return self.base.webgl_error(InvalidOperation);
2231        }
2232
2233        let ReadPixelsSizes {
2234            row_stride: _,
2235            skipped_bytes,
2236            size,
2237        } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
2238            Ok(result) => result,
2239            Err(error) => return self.base.webgl_error(error),
2240        };
2241        let dst_end = dst_byte_offset + skipped_bytes + size;
2242        if dst.capacity() < dst_end {
2243            return self.base.webgl_error(InvalidOperation);
2244        }
2245
2246        {
2247            let (fb_width, fb_height) = handle_potential_webgl_error!(
2248                self.base,
2249                self.base
2250                    .get_current_framebuffer_size()
2251                    .ok_or(InvalidOperation),
2252                return
2253            );
2254            let src_origin = Point2D::new(x, y);
2255            let src_size = Size2D::new(width as u32, height as u32);
2256            let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
2257            if pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()).is_none() {
2258                return;
2259            }
2260        }
2261        let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
2262
2263        self.base.send_command(WebGLCommand::PixelStorei(
2264            constants::PACK_ALIGNMENT,
2265            self.base.get_texture_packing_alignment() as _,
2266        ));
2267        self.base.send_command(WebGLCommand::PixelStorei(
2268            constants::PACK_ROW_LENGTH,
2269            self.texture_pack_row_length.get() as _,
2270        ));
2271        self.base.send_command(WebGLCommand::PixelStorei(
2272            constants::PACK_SKIP_ROWS,
2273            self.texture_pack_skip_rows.get() as _,
2274        ));
2275        self.base.send_command(WebGLCommand::PixelStorei(
2276            constants::PACK_SKIP_PIXELS,
2277            self.texture_pack_skip_pixels.get() as _,
2278        ));
2279        self.base.send_command(WebGLCommand::ReadPixelsPP(
2280            src_rect,
2281            format,
2282            pixel_type,
2283            dst_byte_offset,
2284        ));
2285    }
2286
2287    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10>
2288    #[allow(unsafe_code)]
2289    fn ReadPixels__(
2290        &self,
2291        x: i32,
2292        y: i32,
2293        width: i32,
2294        height: i32,
2295        format: u32,
2296        pixel_type: u32,
2297        mut dst: CustomAutoRooterGuard<ArrayBufferView>,
2298        dst_elem_offset: u32,
2299    ) {
2300        self.read_pixels_into(
2301            x,
2302            y,
2303            width,
2304            height,
2305            format,
2306            pixel_type,
2307            &mut dst,
2308            dst_elem_offset,
2309        )
2310    }
2311
2312    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2313    fn SampleCoverage(&self, value: f32, invert: bool) {
2314        self.base.SampleCoverage(value, invert)
2315    }
2316
2317    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4>
2318    fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
2319        self.base.Scissor(x, y, width, height)
2320    }
2321
2322    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2323    fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
2324        self.base.StencilFunc(func, ref_, mask)
2325    }
2326
2327    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2328    fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
2329        self.base.StencilFuncSeparate(face, func, ref_, mask)
2330    }
2331
2332    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2333    fn StencilMask(&self, mask: u32) {
2334        self.base.StencilMask(mask)
2335    }
2336
2337    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2338    fn StencilMaskSeparate(&self, face: u32, mask: u32) {
2339        self.base.StencilMaskSeparate(face, mask)
2340    }
2341
2342    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2343    fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
2344        self.base.StencilOp(fail, zfail, zpass)
2345    }
2346
2347    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
2348    fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
2349        self.base.StencilOpSeparate(face, fail, zfail, zpass)
2350    }
2351
2352    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2353    fn LinkProgram(&self, program: &WebGLProgram) {
2354        self.base.LinkProgram(program)
2355    }
2356
2357    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2358    fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
2359        self.base.ShaderSource(shader, source)
2360    }
2361
2362    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2363    fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
2364        self.base.GetShaderSource(shader)
2365    }
2366
2367    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2368    fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
2369        self.base.Uniform1f(location, val)
2370    }
2371
2372    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2373    fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
2374        self.base.Uniform1i(location, val)
2375    }
2376
2377    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2378    fn Uniform1iv(
2379        &self,
2380        location: Option<&WebGLUniformLocation>,
2381        v: Int32ArrayOrLongSequence,
2382        src_offset: u32,
2383        src_length: u32,
2384    ) {
2385        self.base.uniform1iv(location, v, src_offset, src_length)
2386    }
2387
2388    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2389    fn Uniform1ui(&self, location: Option<&WebGLUniformLocation>, val: u32) {
2390        self.base.with_location(location, |location| {
2391            match location.type_() {
2392                constants::BOOL | constants::UNSIGNED_INT => (),
2393                _ => return Err(InvalidOperation),
2394            }
2395            self.base
2396                .send_command(WebGLCommand::Uniform1ui(location.id(), val));
2397            Ok(())
2398        });
2399    }
2400
2401    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2402    fn Uniform1uiv(
2403        &self,
2404        location: Option<&WebGLUniformLocation>,
2405        val: Uint32ArrayOrUnsignedLongSequence,
2406        src_offset: u32,
2407        src_length: u32,
2408    ) {
2409        self.base.with_location(location, |location| {
2410            match location.type_() {
2411                constants::BOOL |
2412                constants::UNSIGNED_INT |
2413                constants::SAMPLER_2D |
2414                constants::SAMPLER_2D_ARRAY |
2415                constants::SAMPLER_3D |
2416                constants::SAMPLER_CUBE => {},
2417                _ => return Err(InvalidOperation),
2418            }
2419
2420            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 1, location)?;
2421
2422            match location.type_() {
2423                constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
2424                    for &v in val
2425                        .iter()
2426                        .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
2427                    {
2428                        if v >= self.base.limits().max_combined_texture_image_units {
2429                            return Err(InvalidValue);
2430                        }
2431                    }
2432                },
2433                _ => {},
2434            }
2435            self.base
2436                .send_command(WebGLCommand::Uniform1uiv(location.id(), val));
2437            Ok(())
2438        });
2439    }
2440
2441    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2442    fn Uniform1fv(
2443        &self,
2444        location: Option<&WebGLUniformLocation>,
2445        v: Float32ArrayOrUnrestrictedFloatSequence,
2446        src_offset: u32,
2447        src_length: u32,
2448    ) {
2449        self.base.uniform1fv(location, v, src_offset, src_length);
2450    }
2451
2452    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2453    fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
2454        self.base.Uniform2f(location, x, y)
2455    }
2456
2457    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2458    fn Uniform2fv(
2459        &self,
2460        location: Option<&WebGLUniformLocation>,
2461        v: Float32ArrayOrUnrestrictedFloatSequence,
2462        src_offset: u32,
2463        src_length: u32,
2464    ) {
2465        self.base.uniform2fv(location, v, src_offset, src_length);
2466    }
2467
2468    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2469    fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
2470        self.base.Uniform2i(location, x, y)
2471    }
2472
2473    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2474    fn Uniform2iv(
2475        &self,
2476        location: Option<&WebGLUniformLocation>,
2477        v: Int32ArrayOrLongSequence,
2478        src_offset: u32,
2479        src_length: u32,
2480    ) {
2481        self.base.uniform2iv(location, v, src_offset, src_length)
2482    }
2483
2484    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2485    fn Uniform2ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32) {
2486        self.base.with_location(location, |location| {
2487            match location.type_() {
2488                constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2489                _ => return Err(InvalidOperation),
2490            }
2491            self.base
2492                .send_command(WebGLCommand::Uniform2ui(location.id(), x, y));
2493            Ok(())
2494        });
2495    }
2496
2497    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2498    fn Uniform2uiv(
2499        &self,
2500        location: Option<&WebGLUniformLocation>,
2501        val: Uint32ArrayOrUnsignedLongSequence,
2502        src_offset: u32,
2503        src_length: u32,
2504    ) {
2505        self.base.with_location(location, |location| {
2506            match location.type_() {
2507                constants::BOOL_VEC2 | constants::UNSIGNED_INT_VEC2 => {},
2508                _ => return Err(InvalidOperation),
2509            }
2510            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 2, location)?;
2511            self.base
2512                .send_command(WebGLCommand::Uniform2uiv(location.id(), val));
2513            Ok(())
2514        });
2515    }
2516
2517    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2518    fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
2519        self.base.Uniform3f(location, x, y, z)
2520    }
2521
2522    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2523    fn Uniform3fv(
2524        &self,
2525        location: Option<&WebGLUniformLocation>,
2526        v: Float32ArrayOrUnrestrictedFloatSequence,
2527        src_offset: u32,
2528        src_length: u32,
2529    ) {
2530        self.base.uniform3fv(location, v, src_offset, src_length);
2531    }
2532
2533    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2534    fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
2535        self.base.Uniform3i(location, x, y, z)
2536    }
2537
2538    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2539    fn Uniform3iv(
2540        &self,
2541        location: Option<&WebGLUniformLocation>,
2542        v: Int32ArrayOrLongSequence,
2543        src_offset: u32,
2544        src_length: u32,
2545    ) {
2546        self.base.uniform3iv(location, v, src_offset, src_length)
2547    }
2548
2549    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2550    fn Uniform3ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32) {
2551        self.base.with_location(location, |location| {
2552            match location.type_() {
2553                constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2554                _ => return Err(InvalidOperation),
2555            }
2556            self.base
2557                .send_command(WebGLCommand::Uniform3ui(location.id(), x, y, z));
2558            Ok(())
2559        });
2560    }
2561
2562    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2563    fn Uniform3uiv(
2564        &self,
2565        location: Option<&WebGLUniformLocation>,
2566        val: Uint32ArrayOrUnsignedLongSequence,
2567        src_offset: u32,
2568        src_length: u32,
2569    ) {
2570        self.base.with_location(location, |location| {
2571            match location.type_() {
2572                constants::BOOL_VEC3 | constants::UNSIGNED_INT_VEC3 => {},
2573                _ => return Err(InvalidOperation),
2574            }
2575            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 3, location)?;
2576            self.base
2577                .send_command(WebGLCommand::Uniform3uiv(location.id(), val));
2578            Ok(())
2579        });
2580    }
2581
2582    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2583    fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
2584        self.base.Uniform4i(location, x, y, z, w)
2585    }
2586
2587    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2588    fn Uniform4iv(
2589        &self,
2590        location: Option<&WebGLUniformLocation>,
2591        v: Int32ArrayOrLongSequence,
2592        src_offset: u32,
2593        src_length: u32,
2594    ) {
2595        self.base.uniform4iv(location, v, src_offset, src_length)
2596    }
2597
2598    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2599    fn Uniform4ui(&self, location: Option<&WebGLUniformLocation>, x: u32, y: u32, z: u32, w: u32) {
2600        self.base.with_location(location, |location| {
2601            match location.type_() {
2602                constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2603                _ => return Err(InvalidOperation),
2604            }
2605            self.base
2606                .send_command(WebGLCommand::Uniform4ui(location.id(), x, y, z, w));
2607            Ok(())
2608        });
2609    }
2610
2611    // https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8
2612    fn Uniform4uiv(
2613        &self,
2614        location: Option<&WebGLUniformLocation>,
2615        val: Uint32ArrayOrUnsignedLongSequence,
2616        src_offset: u32,
2617        src_length: u32,
2618    ) {
2619        self.base.with_location(location, |location| {
2620            match location.type_() {
2621                constants::BOOL_VEC4 | constants::UNSIGNED_INT_VEC4 => {},
2622                _ => return Err(InvalidOperation),
2623            }
2624            let val = self.uniform_vec_section_uint(val, src_offset, src_length, 4, location)?;
2625            self.base
2626                .send_command(WebGLCommand::Uniform4uiv(location.id(), val));
2627            Ok(())
2628        });
2629    }
2630
2631    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2632    fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
2633        self.base.Uniform4f(location, x, y, z, w)
2634    }
2635
2636    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2637    fn Uniform4fv(
2638        &self,
2639        location: Option<&WebGLUniformLocation>,
2640        v: Float32ArrayOrUnrestrictedFloatSequence,
2641        src_offset: u32,
2642        src_length: u32,
2643    ) {
2644        self.base.uniform4fv(location, v, src_offset, src_length);
2645    }
2646
2647    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2648    fn UniformMatrix2fv(
2649        &self,
2650        location: Option<&WebGLUniformLocation>,
2651        transpose: bool,
2652        v: Float32ArrayOrUnrestrictedFloatSequence,
2653        src_offset: u32,
2654        src_length: u32,
2655    ) {
2656        self.base
2657            .uniform_matrix_2fv(location, transpose, v, src_offset, src_length)
2658    }
2659
2660    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2661    fn UniformMatrix3fv(
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_3fv(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 UniformMatrix4fv(
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_4fv(location, transpose, v, src_offset, src_length)
2684    }
2685
2686    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2687    fn UniformMatrix3x2fv(
2688        &self,
2689        location: Option<&WebGLUniformLocation>,
2690        transpose: bool,
2691        val: Float32ArrayOrUnrestrictedFloatSequence,
2692        src_offset: u32,
2693        src_length: u32,
2694    ) {
2695        self.base.with_location(location, |location| {
2696            match location.type_() {
2697                constants::FLOAT_MAT3x2 => {},
2698                _ => return Err(InvalidOperation),
2699            }
2700            let val = self.base.uniform_matrix_section(
2701                val,
2702                src_offset,
2703                src_length,
2704                transpose,
2705                3 * 2,
2706                location,
2707            )?;
2708            self.base
2709                .send_command(WebGLCommand::UniformMatrix3x2fv(location.id(), val));
2710            Ok(())
2711        });
2712    }
2713
2714    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2715    fn UniformMatrix4x2fv(
2716        &self,
2717        location: Option<&WebGLUniformLocation>,
2718        transpose: bool,
2719        val: Float32ArrayOrUnrestrictedFloatSequence,
2720        src_offset: u32,
2721        src_length: u32,
2722    ) {
2723        self.base.with_location(location, |location| {
2724            match location.type_() {
2725                constants::FLOAT_MAT4x2 => {},
2726                _ => return Err(InvalidOperation),
2727            }
2728            let val = self.base.uniform_matrix_section(
2729                val,
2730                src_offset,
2731                src_length,
2732                transpose,
2733                4 * 2,
2734                location,
2735            )?;
2736            self.base
2737                .send_command(WebGLCommand::UniformMatrix4x2fv(location.id(), val));
2738            Ok(())
2739        });
2740    }
2741
2742    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2743    fn UniformMatrix2x3fv(
2744        &self,
2745        location: Option<&WebGLUniformLocation>,
2746        transpose: bool,
2747        val: Float32ArrayOrUnrestrictedFloatSequence,
2748        src_offset: u32,
2749        src_length: u32,
2750    ) {
2751        self.base.with_location(location, |location| {
2752            match location.type_() {
2753                constants::FLOAT_MAT2x3 => {},
2754                _ => return Err(InvalidOperation),
2755            }
2756            let val = self.base.uniform_matrix_section(
2757                val,
2758                src_offset,
2759                src_length,
2760                transpose,
2761                2 * 3,
2762                location,
2763            )?;
2764            self.base
2765                .send_command(WebGLCommand::UniformMatrix2x3fv(location.id(), val));
2766            Ok(())
2767        });
2768    }
2769
2770    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2771    fn UniformMatrix4x3fv(
2772        &self,
2773        location: Option<&WebGLUniformLocation>,
2774        transpose: bool,
2775        val: Float32ArrayOrUnrestrictedFloatSequence,
2776        src_offset: u32,
2777        src_length: u32,
2778    ) {
2779        self.base.with_location(location, |location| {
2780            match location.type_() {
2781                constants::FLOAT_MAT4x3 => {},
2782                _ => return Err(InvalidOperation),
2783            }
2784            let val = self.base.uniform_matrix_section(
2785                val,
2786                src_offset,
2787                src_length,
2788                transpose,
2789                4 * 3,
2790                location,
2791            )?;
2792            self.base
2793                .send_command(WebGLCommand::UniformMatrix4x3fv(location.id(), val));
2794            Ok(())
2795        });
2796    }
2797
2798    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2799    fn UniformMatrix2x4fv(
2800        &self,
2801        location: Option<&WebGLUniformLocation>,
2802        transpose: bool,
2803        val: Float32ArrayOrUnrestrictedFloatSequence,
2804        src_offset: u32,
2805        src_length: u32,
2806    ) {
2807        self.base.with_location(location, |location| {
2808            match location.type_() {
2809                constants::FLOAT_MAT2x4 => {},
2810                _ => return Err(InvalidOperation),
2811            }
2812            let val = self.base.uniform_matrix_section(
2813                val,
2814                src_offset,
2815                src_length,
2816                transpose,
2817                2 * 4,
2818                location,
2819            )?;
2820            self.base
2821                .send_command(WebGLCommand::UniformMatrix2x4fv(location.id(), val));
2822            Ok(())
2823        });
2824    }
2825
2826    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2827    fn UniformMatrix3x4fv(
2828        &self,
2829        location: Option<&WebGLUniformLocation>,
2830        transpose: bool,
2831        val: Float32ArrayOrUnrestrictedFloatSequence,
2832        src_offset: u32,
2833        src_length: u32,
2834    ) {
2835        self.base.with_location(location, |location| {
2836            match location.type_() {
2837                constants::FLOAT_MAT3x4 => {},
2838                _ => return Err(InvalidOperation),
2839            }
2840            let val = self.base.uniform_matrix_section(
2841                val,
2842                src_offset,
2843                src_length,
2844                transpose,
2845                3 * 4,
2846                location,
2847            )?;
2848            self.base
2849                .send_command(WebGLCommand::UniformMatrix3x4fv(location.id(), val));
2850            Ok(())
2851        });
2852    }
2853
2854    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2855    #[allow(unsafe_code)]
2856    fn GetUniform(
2857        &self,
2858        cx: JSContext,
2859        program: &WebGLProgram,
2860        location: &WebGLUniformLocation,
2861        mut retval: MutableHandleValue,
2862    ) {
2863        handle_potential_webgl_error!(
2864            self.base,
2865            self.base.uniform_check_program(program, location),
2866            return retval.set(NullValue())
2867        );
2868
2869        let triple = (&*self.base, program.id(), location.id());
2870
2871        match location.type_() {
2872            constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get(
2873                triple,
2874                WebGLCommand::GetUniformUint,
2875            ))),
2876            constants::UNSIGNED_INT_VEC2 => unsafe {
2877                uniform_typed::<Uint32>(
2878                    *cx,
2879                    &uniform_get(triple, WebGLCommand::GetUniformUint2),
2880                    retval,
2881                )
2882            },
2883            constants::UNSIGNED_INT_VEC3 => unsafe {
2884                uniform_typed::<Uint32>(
2885                    *cx,
2886                    &uniform_get(triple, WebGLCommand::GetUniformUint3),
2887                    retval,
2888                )
2889            },
2890            constants::UNSIGNED_INT_VEC4 => unsafe {
2891                uniform_typed::<Uint32>(
2892                    *cx,
2893                    &uniform_get(triple, WebGLCommand::GetUniformUint4),
2894                    retval,
2895                )
2896            },
2897            constants::FLOAT_MAT2x3 => unsafe {
2898                uniform_typed::<Float32>(
2899                    *cx,
2900                    &uniform_get(triple, WebGLCommand::GetUniformFloat2x3),
2901                    retval,
2902                )
2903            },
2904            constants::FLOAT_MAT2x4 => unsafe {
2905                uniform_typed::<Float32>(
2906                    *cx,
2907                    &uniform_get(triple, WebGLCommand::GetUniformFloat2x4),
2908                    retval,
2909                )
2910            },
2911            constants::FLOAT_MAT3x2 => unsafe {
2912                uniform_typed::<Float32>(
2913                    *cx,
2914                    &uniform_get(triple, WebGLCommand::GetUniformFloat3x2),
2915                    retval,
2916                )
2917            },
2918            constants::FLOAT_MAT3x4 => unsafe {
2919                uniform_typed::<Float32>(
2920                    *cx,
2921                    &uniform_get(triple, WebGLCommand::GetUniformFloat3x4),
2922                    retval,
2923                )
2924            },
2925            constants::FLOAT_MAT4x2 => unsafe {
2926                uniform_typed::<Float32>(
2927                    *cx,
2928                    &uniform_get(triple, WebGLCommand::GetUniformFloat4x2),
2929                    retval,
2930                )
2931            },
2932            constants::FLOAT_MAT4x3 => unsafe {
2933                uniform_typed::<Float32>(
2934                    *cx,
2935                    &uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
2936                    retval,
2937                )
2938            },
2939            constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
2940                retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
2941            },
2942            _ => self.base.GetUniform(cx, program, location, retval),
2943        }
2944    }
2945
2946    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2947    fn UseProgram(&self, program: Option<&WebGLProgram>) {
2948        self.base.UseProgram(program)
2949    }
2950
2951    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
2952    fn ValidateProgram(&self, program: &WebGLProgram) {
2953        self.base.ValidateProgram(program)
2954    }
2955
2956    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2957    fn VertexAttrib1f(&self, indx: u32, x: f32) {
2958        self.base.VertexAttrib1f(indx, x)
2959    }
2960
2961    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2962    fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2963        self.base.VertexAttrib1fv(indx, v)
2964    }
2965
2966    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2967    fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
2968        self.base.VertexAttrib2f(indx, x, y)
2969    }
2970
2971    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2972    fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2973        self.base.VertexAttrib2fv(indx, v)
2974    }
2975
2976    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2977    fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
2978        self.base.VertexAttrib3f(indx, x, y, z)
2979    }
2980
2981    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2982    fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2983        self.base.VertexAttrib3fv(indx, v)
2984    }
2985
2986    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2987    fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
2988        self.base.VertexAttrib4f(indx, x, y, z, w)
2989    }
2990
2991    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
2992    fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
2993        self.base.VertexAttrib4fv(indx, v)
2994    }
2995
2996    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
2997    fn VertexAttribI4i(&self, index: u32, x: i32, y: i32, z: i32, w: i32) {
2998        self.vertex_attrib_i(index, x, y, z, w)
2999    }
3000
3001    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3002    fn VertexAttribI4iv(&self, index: u32, v: Int32ArrayOrLongSequence) {
3003        let values = match v {
3004            Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
3005            Int32ArrayOrLongSequence::LongSequence(v) => v,
3006        };
3007        if values.len() < 4 {
3008            return self.base.webgl_error(InvalidValue);
3009        }
3010        self.vertex_attrib_i(index, values[0], values[1], values[2], values[3]);
3011    }
3012
3013    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3014    fn VertexAttribI4ui(&self, index: u32, x: u32, y: u32, z: u32, w: u32) {
3015        self.vertex_attrib_u(index, x, y, z, w)
3016    }
3017
3018    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3019    fn VertexAttribI4uiv(&self, index: u32, v: Uint32ArrayOrUnsignedLongSequence) {
3020        let values = match v {
3021            Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
3022            Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
3023        };
3024        if values.len() < 4 {
3025            return self.base.webgl_error(InvalidValue);
3026        }
3027        self.vertex_attrib_u(index, values[0], values[1], values[2], values[3]);
3028    }
3029
3030    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
3031    fn VertexAttribPointer(
3032        &self,
3033        attrib_id: u32,
3034        size: i32,
3035        data_type: u32,
3036        normalized: bool,
3037        stride: i32,
3038        offset: i64,
3039    ) {
3040        self.base
3041            .VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset)
3042    }
3043
3044    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.8>
3045    fn VertexAttribIPointer(&self, index: u32, size: i32, type_: u32, stride: i32, offset: i64) {
3046        match type_ {
3047            constants::BYTE |
3048            constants::UNSIGNED_BYTE |
3049            constants::SHORT |
3050            constants::UNSIGNED_SHORT |
3051            constants::INT |
3052            constants::UNSIGNED_INT => {},
3053            _ => return self.base.webgl_error(InvalidEnum),
3054        };
3055        self.base
3056            .VertexAttribPointer(index, size, type_, false, stride, offset)
3057    }
3058
3059    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4>
3060    fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
3061        self.base.Viewport(x, y, width, height)
3062    }
3063
3064    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3065    ///
3066    /// Allocates and initializes the specified mipmap level of a three-dimensional or
3067    /// two-dimensional array texture.
3068    #[allow(unsafe_code)]
3069    fn TexImage3D(
3070        &self,
3071        target: u32,
3072        level: i32,
3073        internal_format: i32,
3074        width: i32,
3075        height: i32,
3076        depth: i32,
3077        border: i32,
3078        format: u32,
3079        type_: u32,
3080        src_data: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3081    ) -> Fallible<()> {
3082        // If a WebGLBuffer is bound to the PIXEL_UNPACK_BUFFER target,
3083        // generates an INVALID_OPERATION error.
3084        if self.bound_pixel_unpack_buffer.get().is_some() {
3085            self.base.webgl_error(InvalidOperation);
3086            return Ok(());
3087        }
3088
3089        // If type is specified as FLOAT_32_UNSIGNED_INT_24_8_REV, srcData must be null;
3090        // otherwise, generates an INVALID_OPERATION error.
3091        if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV && src_data.is_some() {
3092            self.base.webgl_error(InvalidOperation);
3093            return Ok(());
3094        }
3095
3096        if border != 0 {
3097            self.base.webgl_error(InvalidValue);
3098            return Ok(());
3099        }
3100
3101        let Ok(TexImage3DValidatorResult {
3102            width,
3103            height,
3104            depth,
3105            level,
3106            border,
3107            texture,
3108            target,
3109            internal_format,
3110            format,
3111            data_type,
3112        }) = TexImage3DValidator::new(
3113            &self.base,
3114            target,
3115            level,
3116            internal_format as u32,
3117            width,
3118            height,
3119            depth,
3120            border,
3121            format,
3122            type_,
3123            &src_data,
3124        )
3125        .validate()
3126        else {
3127            return Ok(());
3128        };
3129
3130        // TODO: If pixel store parameter constraints are not met, generates an INVALID_OPERATION error.
3131
3132        // If srcData is null, a buffer of sufficient size initialized to 0 is passed.
3133        let unpacking_alignment = self.base.texture_unpacking_alignment();
3134        let buff = match *src_data {
3135            Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
3136            None => {
3137                let element_size = data_type.element_size();
3138                let components = format.components();
3139                let components_per_element = format.components();
3140                // FIXME: This is copied from tex_image_2d which is apparently incorrect
3141                // NOTE: width and height are positive or zero due to validate()
3142                let expected_byte_len = if height == 0 {
3143                    0
3144                } else {
3145                    // We need to be careful here to not count unpack
3146                    // alignment at the end of the image, otherwise (for
3147                    // example) passing a single byte for uploading a 1x1
3148                    // GL_ALPHA/GL_UNSIGNED_BYTE texture would throw an error.
3149                    let cpp = element_size * components / components_per_element;
3150                    let stride =
3151                        (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
3152                    stride * (height - 1) + width * cpp
3153                };
3154                IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_len as usize])
3155            },
3156        };
3157        let (alpha_treatment, y_axis_treatment) =
3158            self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3159        // If UNPACK_FLIP_Y_WEBGL or UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to true, texImage3D and texSubImage3D
3160        // generate an INVALID_OPERATION error if they upload data from a PIXEL_UNPACK_BUFFER or a non-null client
3161        // side ArrayBufferView.
3162        if let (Some(AlphaTreatment::Premultiply), YAxisTreatment::Flipped) =
3163            (alpha_treatment, y_axis_treatment)
3164        {
3165            if src_data.is_some() {
3166                self.base.webgl_error(InvalidOperation);
3167                return Ok(());
3168            }
3169        }
3170        let tex_source = TexPixels::from_array(
3171            buff,
3172            Size2D::new(width, height),
3173            alpha_treatment,
3174            y_axis_treatment,
3175        );
3176
3177        self.tex_image_3d(
3178            &texture,
3179            target,
3180            data_type,
3181            internal_format,
3182            format,
3183            level,
3184            width,
3185            height,
3186            depth,
3187            border,
3188            unpacking_alignment,
3189            tex_source,
3190        );
3191        Ok(())
3192    }
3193
3194    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3195    fn TexImage2D(
3196        &self,
3197        target: u32,
3198        level: i32,
3199        internal_format: i32,
3200        width: i32,
3201        height: i32,
3202        border: i32,
3203        format: u32,
3204        data_type: u32,
3205        pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3206    ) -> Fallible<()> {
3207        self.base.TexImage2D(
3208            target,
3209            level,
3210            internal_format,
3211            width,
3212            height,
3213            border,
3214            format,
3215            data_type,
3216            pixels,
3217        )
3218    }
3219
3220    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3221    fn TexImage2D_(
3222        &self,
3223        target: u32,
3224        level: i32,
3225        internal_format: i32,
3226        format: u32,
3227        data_type: u32,
3228        source: TexImageSource,
3229    ) -> ErrorResult {
3230        self.base
3231            .TexImage2D_(target, level, internal_format, format, data_type, source)
3232    }
3233
3234    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3235    fn TexImage2D__(
3236        &self,
3237        target: u32,
3238        level: i32,
3239        internalformat: i32,
3240        width: i32,
3241        height: i32,
3242        border: i32,
3243        format: u32,
3244        type_: u32,
3245        pbo_offset: i64,
3246    ) -> Fallible<()> {
3247        let pixel_unpack_buffer = match self.bound_pixel_unpack_buffer.get() {
3248            Some(pixel_unpack_buffer) => pixel_unpack_buffer,
3249            None => {
3250                self.base.webgl_error(InvalidOperation);
3251                return Ok(());
3252            },
3253        };
3254
3255        if let Some(tf_buffer) = self.bound_transform_feedback_buffer.get() {
3256            if pixel_unpack_buffer == tf_buffer {
3257                self.base.webgl_error(InvalidOperation);
3258                return Ok(());
3259            }
3260        }
3261
3262        if pbo_offset < 0 || pbo_offset as usize > pixel_unpack_buffer.capacity() {
3263            self.base.webgl_error(InvalidValue);
3264            return Ok(());
3265        }
3266
3267        let unpacking_alignment = self.base.texture_unpacking_alignment();
3268
3269        let validator = TexImage2DValidator::new(
3270            &self.base,
3271            target,
3272            level,
3273            internalformat as u32,
3274            width,
3275            height,
3276            border,
3277            format,
3278            type_,
3279        );
3280
3281        let TexImage2DValidatorResult {
3282            texture,
3283            target,
3284            width,
3285            height,
3286            level,
3287            border,
3288            internal_format,
3289            format,
3290            data_type,
3291        } = match validator.validate() {
3292            Ok(result) => result,
3293            Err(_) => return Ok(()),
3294        };
3295
3296        self.base.tex_image_2d(
3297            &texture,
3298            target,
3299            data_type,
3300            internal_format,
3301            format,
3302            level,
3303            border,
3304            unpacking_alignment,
3305            Size2D::new(width, height),
3306            TexSource::BufferOffset(pbo_offset),
3307        );
3308
3309        Ok(())
3310    }
3311
3312    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3313    fn TexImage2D___(
3314        &self,
3315        target: u32,
3316        level: i32,
3317        internalformat: i32,
3318        width: i32,
3319        height: i32,
3320        border: i32,
3321        format: u32,
3322        type_: u32,
3323        source: TexImageSource,
3324    ) -> Fallible<()> {
3325        if self.bound_pixel_unpack_buffer.get().is_some() {
3326            self.base.webgl_error(InvalidOperation);
3327            return Ok(());
3328        }
3329
3330        let validator = TexImage2DValidator::new(
3331            &self.base,
3332            target,
3333            level,
3334            internalformat as u32,
3335            width,
3336            height,
3337            border,
3338            format,
3339            type_,
3340        );
3341
3342        let TexImage2DValidatorResult {
3343            texture,
3344            target,
3345            width: _,
3346            height: _,
3347            level,
3348            border,
3349            internal_format,
3350            format,
3351            data_type,
3352        } = match validator.validate() {
3353            Ok(result) => result,
3354            Err(_) => return Ok(()),
3355        };
3356
3357        let unpacking_alignment = self.base.texture_unpacking_alignment();
3358
3359        let pixels = match self.base.get_image_pixels(source)? {
3360            Some(pixels) => pixels,
3361            None => return Ok(()),
3362        };
3363
3364        self.base.tex_image_2d(
3365            &texture,
3366            target,
3367            data_type,
3368            internal_format,
3369            format,
3370            level,
3371            border,
3372            unpacking_alignment,
3373            pixels.size(),
3374            TexSource::Pixels(pixels),
3375        );
3376
3377        Ok(())
3378    }
3379
3380    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
3381    #[allow(unsafe_code)]
3382    fn TexImage2D____(
3383        &self,
3384        target: u32,
3385        level: i32,
3386        internalformat: i32,
3387        width: i32,
3388        height: i32,
3389        border: i32,
3390        format: u32,
3391        type_: u32,
3392        src_data: CustomAutoRooterGuard<ArrayBufferView>,
3393        src_offset: u32,
3394    ) -> Fallible<()> {
3395        if self.bound_pixel_unpack_buffer.get().is_some() {
3396            self.base.webgl_error(InvalidOperation);
3397            return Ok(());
3398        }
3399
3400        if type_ == constants::FLOAT_32_UNSIGNED_INT_24_8_REV {
3401            self.base.webgl_error(InvalidOperation);
3402            return Ok(());
3403        }
3404
3405        let validator = TexImage2DValidator::new(
3406            &self.base,
3407            target,
3408            level,
3409            internalformat as u32,
3410            width,
3411            height,
3412            border,
3413            format,
3414            type_,
3415        );
3416
3417        let TexImage2DValidatorResult {
3418            texture,
3419            target,
3420            width,
3421            height,
3422            level,
3423            border,
3424            internal_format,
3425            format,
3426            data_type,
3427        } = match validator.validate() {
3428            Ok(result) => result,
3429            Err(_) => return Ok(()),
3430        };
3431
3432        let unpacking_alignment = self.base.texture_unpacking_alignment();
3433
3434        let src_elem_size = src_data.get_array_type().byte_size().unwrap();
3435        let src_byte_offset = src_offset as usize * src_elem_size;
3436
3437        if src_data.len() <= src_byte_offset {
3438            self.base.webgl_error(InvalidOperation);
3439            return Ok(());
3440        }
3441
3442        let buff = IpcSharedMemory::from_bytes(unsafe { &src_data.as_slice()[src_byte_offset..] });
3443
3444        let expected_byte_length = match self.base.validate_tex_image_2d_data(
3445            width,
3446            height,
3447            format,
3448            data_type,
3449            unpacking_alignment,
3450            Some(&*src_data),
3451        ) {
3452            Ok(byte_length) => byte_length,
3453            Err(()) => return Ok(()),
3454        };
3455
3456        if expected_byte_length as usize > buff.len() {
3457            self.base.webgl_error(InvalidOperation);
3458            return Ok(());
3459        }
3460
3461        let size = Size2D::new(width, height);
3462
3463        let (alpha_treatment, y_axis_treatment) =
3464            self.base.get_current_unpack_state(Alpha::NotPremultiplied);
3465
3466        self.base.tex_image_2d(
3467            &texture,
3468            target,
3469            data_type,
3470            internal_format,
3471            format,
3472            level,
3473            border,
3474            unpacking_alignment,
3475            size,
3476            TexSource::Pixels(TexPixels::from_array(
3477                buff,
3478                size,
3479                alpha_treatment,
3480                y_axis_treatment,
3481            )),
3482        );
3483
3484        Ok(())
3485    }
3486
3487    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3488    fn TexSubImage2D(
3489        &self,
3490        target: u32,
3491        level: i32,
3492        xoffset: i32,
3493        yoffset: i32,
3494        width: i32,
3495        height: i32,
3496        format: u32,
3497        data_type: u32,
3498        pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3499    ) -> Fallible<()> {
3500        self.base.TexSubImage2D(
3501            target, level, xoffset, yoffset, width, height, format, data_type, pixels,
3502        )
3503    }
3504
3505    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3506    fn TexSubImage2D_(
3507        &self,
3508        target: u32,
3509        level: i32,
3510        xoffset: i32,
3511        yoffset: i32,
3512        format: u32,
3513        data_type: u32,
3514        source: TexImageSource,
3515    ) -> ErrorResult {
3516        self.base
3517            .TexSubImage2D_(target, level, xoffset, yoffset, format, data_type, source)
3518    }
3519
3520    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3521    fn TexParameterf(&self, target: u32, name: u32, value: f32) {
3522        self.base.TexParameterf(target, name, value)
3523    }
3524
3525    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
3526    fn TexParameteri(&self, target: u32, name: u32, value: i32) {
3527        self.base.TexParameteri(target, name, value)
3528    }
3529
3530    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3531    fn CheckFramebufferStatus(&self, target: u32) -> u32 {
3532        let fb_slot = match target {
3533            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3534                self.base.get_draw_framebuffer_slot()
3535            },
3536            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3537            _ => {
3538                self.base.webgl_error(InvalidEnum);
3539                return 0;
3540            },
3541        };
3542        match fb_slot.get() {
3543            Some(fb) => fb.check_status(),
3544            None => constants::FRAMEBUFFER_COMPLETE,
3545        }
3546    }
3547
3548    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
3549    fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
3550        self.base
3551            .RenderbufferStorage(target, internal_format, width, height)
3552    }
3553
3554    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4S>
3555    fn BlitFramebuffer(
3556        &self,
3557        src_x0: i32,
3558        src_y0: i32,
3559        src_x1: i32,
3560        src_y1: i32,
3561        dst_x0: i32,
3562        dst_y0: i32,
3563        dst_x1: i32,
3564        dst_y1: i32,
3565        mask: u32,
3566        filter: u32,
3567    ) {
3568        bitflags! {
3569            struct BlitFrameBufferFlags: u32 {
3570                const DEPTH = constants::DEPTH_BUFFER_BIT;
3571                const COLOR = constants::COLOR_BUFFER_BIT;
3572                const STENCIL = constants::STENCIL_BUFFER_BIT;
3573                const DEPTH_STENCIL = constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT;
3574            }
3575        };
3576        let Some(bits) = BlitFrameBufferFlags::from_bits(mask) else {
3577            return self.base.webgl_error(InvalidValue);
3578        };
3579        let attributes = self.base.GetContextAttributes().unwrap();
3580
3581        if bits.intersects(BlitFrameBufferFlags::DEPTH_STENCIL) {
3582            match filter {
3583                constants::LINEAR => return self.base.webgl_error(InvalidOperation),
3584                constants::NEAREST => {},
3585                _ => return self.base.webgl_error(InvalidOperation),
3586            }
3587        }
3588
3589        let src_fb = self.base.get_read_framebuffer_slot().get();
3590        let dst_fb = self.base.get_draw_framebuffer_slot().get();
3591
3592        let get_default_formats = || -> WebGLResult<(Option<u32>, Option<u32>, Option<u32>)> {
3593            // All attempts to blit to an antialiased back buffer should fail.
3594            if attributes.antialias {
3595                return Err(InvalidOperation);
3596            };
3597            let color = if attributes.alpha {
3598                Some(constants::RGBA8)
3599            } else {
3600                Some(constants::RGB8)
3601            };
3602            let (depth, stencil) = match (attributes.depth, attributes.stencil) {
3603                (true, true) => (
3604                    Some(constants::DEPTH24_STENCIL8),
3605                    Some(constants::DEPTH24_STENCIL8),
3606                ),
3607                (true, false) => (Some(constants::DEPTH_COMPONENT16), None),
3608                (false, true) => (None, Some(constants::STENCIL_INDEX8)),
3609                _ => (None, None),
3610            };
3611            Ok((color, depth, stencil))
3612        };
3613
3614        let (src_color, src_depth, src_stencil) = match src_fb {
3615            Some(fb) => {
3616                handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3617            },
3618            None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3619        };
3620        let (dst_color, dst_depth, dst_stencil) = match dst_fb {
3621            Some(fb) => {
3622                handle_potential_webgl_error!(self.base, fb.get_attachment_formats(), return)
3623            },
3624            None => handle_potential_webgl_error!(self.base, get_default_formats(), return),
3625        };
3626
3627        if bits.intersects(BlitFrameBufferFlags::COLOR) && src_color != dst_color {
3628            return self.base.webgl_error(InvalidOperation);
3629        }
3630        if bits.intersects(BlitFrameBufferFlags::DEPTH) && src_depth != dst_depth {
3631            return self.base.webgl_error(InvalidOperation);
3632        }
3633        if bits.intersects(BlitFrameBufferFlags::STENCIL) && src_stencil != dst_stencil {
3634            return self.base.webgl_error(InvalidOperation);
3635        }
3636
3637        let src_width = src_x1.checked_sub(src_x0);
3638        let dst_width = dst_x1.checked_sub(dst_x0);
3639        let src_height = src_y1.checked_sub(src_y0);
3640        let dst_height = dst_y1.checked_sub(dst_y0);
3641
3642        if src_width.is_none() ||
3643            dst_width.is_none() ||
3644            src_height.is_none() ||
3645            dst_height.is_none()
3646        {
3647            return self.base.webgl_error(InvalidOperation);
3648        }
3649
3650        self.base.send_command(WebGLCommand::BlitFrameBuffer(
3651            src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
3652        ));
3653    }
3654
3655    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3656    fn FramebufferRenderbuffer(
3657        &self,
3658        target: u32,
3659        attachment: u32,
3660        renderbuffertarget: u32,
3661        rb: Option<&WebGLRenderbuffer>,
3662    ) {
3663        if let Some(rb) = rb {
3664            handle_potential_webgl_error!(self.base, self.base.validate_ownership(rb), return);
3665        }
3666
3667        let fb_slot = match target {
3668            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3669                self.base.get_draw_framebuffer_slot()
3670            },
3671            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3672            _ => return self.base.webgl_error(InvalidEnum),
3673        };
3674
3675        if renderbuffertarget != constants::RENDERBUFFER {
3676            return self.base.webgl_error(InvalidEnum);
3677        }
3678
3679        match fb_slot.get() {
3680            Some(fb) => match attachment {
3681                constants::DEPTH_STENCIL_ATTACHMENT => {
3682                    handle_potential_webgl_error!(
3683                        self.base,
3684                        fb.renderbuffer(constants::DEPTH_ATTACHMENT, rb)
3685                    );
3686                    handle_potential_webgl_error!(
3687                        self.base,
3688                        fb.renderbuffer(constants::STENCIL_ATTACHMENT, rb)
3689                    );
3690                },
3691                _ => handle_potential_webgl_error!(self.base, fb.renderbuffer(attachment, rb)),
3692            },
3693            None => self.base.webgl_error(InvalidOperation),
3694        };
3695    }
3696
3697    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6>
3698    fn FramebufferTexture2D(
3699        &self,
3700        target: u32,
3701        attachment: u32,
3702        textarget: u32,
3703        texture: Option<&WebGLTexture>,
3704        level: i32,
3705    ) {
3706        if let Some(texture) = texture {
3707            handle_potential_webgl_error!(self.base, self.base.validate_ownership(texture), return);
3708        }
3709
3710        let fb_slot = match target {
3711            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
3712                self.base.get_draw_framebuffer_slot()
3713            },
3714            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
3715            _ => return self.base.webgl_error(InvalidEnum),
3716        };
3717        match fb_slot.get() {
3718            Some(fb) => handle_potential_webgl_error!(
3719                self.base,
3720                fb.texture2d(attachment, textarget, texture, level)
3721            ),
3722            None => self.base.webgl_error(InvalidOperation),
3723        }
3724    }
3725
3726    /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
3727    fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
3728        self.base.GetAttachedShaders(program)
3729    }
3730
3731    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3732    fn DrawArraysInstanced(&self, mode: u32, first: i32, count: i32, primcount: i32) {
3733        self.validate_uniform_block_for_draw();
3734        self.validate_vertex_attribs_for_draw();
3735        handle_potential_webgl_error!(
3736            self.base,
3737            self.base
3738                .draw_arrays_instanced(mode, first, count, primcount)
3739        )
3740    }
3741
3742    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3743    fn DrawElementsInstanced(
3744        &self,
3745        mode: u32,
3746        count: i32,
3747        type_: u32,
3748        offset: i64,
3749        primcount: i32,
3750    ) {
3751        self.validate_uniform_block_for_draw();
3752        self.validate_vertex_attribs_for_draw();
3753        handle_potential_webgl_error!(
3754            self.base,
3755            self.base
3756                .draw_elements_instanced(mode, count, type_, offset, primcount)
3757        )
3758    }
3759
3760    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3761    fn DrawRangeElements(
3762        &self,
3763        mode: u32,
3764        start: u32,
3765        end: u32,
3766        count: i32,
3767        type_: u32,
3768        offset: i64,
3769    ) {
3770        if end < start {
3771            self.base.webgl_error(InvalidValue);
3772            return;
3773        }
3774        self.validate_uniform_block_for_draw();
3775        self.validate_vertex_attribs_for_draw();
3776        handle_potential_webgl_error!(
3777            self.base,
3778            self.base
3779                .draw_elements_instanced(mode, count, type_, offset, 1)
3780        )
3781    }
3782
3783    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9>
3784    fn VertexAttribDivisor(&self, index: u32, divisor: u32) {
3785        self.base.vertex_attrib_divisor(index, divisor);
3786    }
3787
3788    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3789    fn CreateQuery(&self) -> Option<DomRoot<WebGLQuery>> {
3790        Some(WebGLQuery::new(&self.base, CanGc::note()))
3791    }
3792
3793    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3794    #[rustfmt::skip]
3795    fn DeleteQuery(&self, query: Option<&WebGLQuery>) {
3796        if let Some(query) = query {
3797            handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3798
3799            if let Some(query_target) = query.target() {
3800                let slot = match query_target {
3801                    constants::ANY_SAMPLES_PASSED |
3802                    constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3803                        &self.occlusion_query
3804                    },
3805                    constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3806                        &self.primitives_query
3807                    },
3808                    _ => unreachable!(),
3809                };
3810                if let Some(stored_query) = slot.get() {
3811                    if stored_query.target() == query.target() {
3812                        slot.set(None);
3813                    }
3814                }
3815            }
3816
3817            query.delete(Operation::Infallible);
3818        }
3819    }
3820
3821    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3822    fn IsQuery(&self, query: Option<&WebGLQuery>) -> bool {
3823        match query {
3824            Some(query) => self.base.validate_ownership(query).is_ok() && query.is_valid(),
3825            None => false,
3826        }
3827    }
3828
3829    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3830    fn CreateSampler(&self) -> Option<DomRoot<WebGLSampler>> {
3831        Some(WebGLSampler::new(&self.base, CanGc::note()))
3832    }
3833
3834    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3835    fn DeleteSampler(&self, sampler: Option<&WebGLSampler>) {
3836        if let Some(sampler) = sampler {
3837            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
3838            for slot in self.samplers.iter() {
3839                if slot.get().is_some_and(|s| sampler == &*s) {
3840                    slot.set(None);
3841                }
3842            }
3843            sampler.delete(Operation::Infallible);
3844        }
3845    }
3846
3847    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
3848    fn IsSampler(&self, sampler: Option<&WebGLSampler>) -> bool {
3849        match sampler {
3850            Some(sampler) => self.base.validate_ownership(sampler).is_ok() && sampler.is_valid(),
3851            None => false,
3852        }
3853    }
3854
3855    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3856    #[rustfmt::skip]
3857    fn BeginQuery(&self, target: u32, query: &WebGLQuery) {
3858        handle_potential_webgl_error!(self.base, self.base.validate_ownership(query), return);
3859
3860        let active_query = match target {
3861            constants::ANY_SAMPLES_PASSED |
3862            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3863                &self.occlusion_query
3864            },
3865            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3866                &self.primitives_query
3867            },
3868            _ => {
3869                self.base.webgl_error(InvalidEnum);
3870                return;
3871            },
3872        };
3873        if active_query.get().is_some() {
3874            self.base.webgl_error(InvalidOperation);
3875            return;
3876        }
3877        let result = query.begin(&self.base, target);
3878        match result {
3879            Ok(_) => active_query.set(Some(query)),
3880            Err(error) => self.base.webgl_error(error),
3881        }
3882    }
3883
3884    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3885    #[rustfmt::skip]
3886    fn EndQuery(&self, target: u32) {
3887        let active_query = match target {
3888            constants::ANY_SAMPLES_PASSED |
3889            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3890                self.occlusion_query.take()
3891            },
3892            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3893                self.primitives_query.take()
3894            },
3895            _ => {
3896                self.base.webgl_error(InvalidEnum);
3897                return;
3898            },
3899        };
3900        match active_query {
3901            None => self.base.webgl_error(InvalidOperation),
3902            Some(query) => {
3903                let result = query.end(&self.base, target);
3904                if let Err(error) = result {
3905                    self.base.webgl_error(error);
3906                }
3907            },
3908        }
3909    }
3910
3911    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3912    #[rustfmt::skip]
3913    fn GetQuery(&self, target: u32, pname: u32) -> Option<DomRoot<WebGLQuery>> {
3914        if pname != constants::CURRENT_QUERY {
3915            self.base.webgl_error(InvalidEnum);
3916            return None;
3917        }
3918        let active_query = match target {
3919            constants::ANY_SAMPLES_PASSED |
3920            constants::ANY_SAMPLES_PASSED_CONSERVATIVE => {
3921                self.occlusion_query.get()
3922            },
3923            constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => {
3924                self.primitives_query.get()
3925            },
3926            _ => {
3927                self.base.webgl_error(InvalidEnum);
3928                None
3929            },
3930        };
3931        if let Some(query) = active_query.as_ref() {
3932            if query.target() != Some(target) {
3933                return None;
3934            }
3935        }
3936        active_query
3937    }
3938
3939    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
3940    #[rustfmt::skip]
3941    fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) {
3942        handle_potential_webgl_error!(
3943            self.base,
3944            self.base.validate_ownership(query),
3945            return retval.set(NullValue())
3946        );
3947        match query.get_parameter(&self.base, pname) {
3948            Ok(value) => match pname {
3949                constants::QUERY_RESULT => retval.set(UInt32Value(value)),
3950                constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)),
3951                _ => unreachable!(),
3952            },
3953            Err(error) => {
3954                self.base.webgl_error(error);
3955                retval.set(NullValue())
3956            },
3957        }
3958    }
3959
3960    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
3961    fn FenceSync(&self, condition: u32, flags: u32) -> Option<DomRoot<WebGLSync>> {
3962        if flags != 0 {
3963            self.base.webgl_error(InvalidValue);
3964            return None;
3965        }
3966        if condition != constants::SYNC_GPU_COMMANDS_COMPLETE {
3967            self.base.webgl_error(InvalidEnum);
3968            return None;
3969        }
3970
3971        Some(WebGLSync::new(&self.base, CanGc::note()))
3972    }
3973
3974    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
3975    fn IsSync(&self, sync: Option<&WebGLSync>) -> bool {
3976        match sync {
3977            Some(sync) => {
3978                if !sync.is_valid() {
3979                    return false;
3980                }
3981                handle_potential_webgl_error!(
3982                    self.base,
3983                    self.base.validate_ownership(sync),
3984                    return false
3985                );
3986                let (sender, receiver) = webgl_channel().unwrap();
3987                self.base
3988                    .send_command(WebGLCommand::IsSync(sync.id(), sender));
3989                receiver.recv().unwrap()
3990            },
3991            None => false,
3992        }
3993    }
3994
3995    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
3996    fn ClientWaitSync(&self, sync: &WebGLSync, flags: u32, timeout: u64) -> u32 {
3997        if !sync.is_valid() {
3998            self.base.webgl_error(InvalidOperation);
3999            return constants::WAIT_FAILED;
4000        }
4001        handle_potential_webgl_error!(
4002            self.base,
4003            self.base.validate_ownership(sync),
4004            return constants::WAIT_FAILED
4005        );
4006        if flags != 0 && flags != constants::SYNC_FLUSH_COMMANDS_BIT {
4007            self.base.webgl_error(InvalidValue);
4008            return constants::WAIT_FAILED;
4009        }
4010        if timeout > self.base.limits().max_client_wait_timeout_webgl.as_nanos() as u64 {
4011            self.base.webgl_error(InvalidOperation);
4012            return constants::WAIT_FAILED;
4013        }
4014
4015        match sync.client_wait_sync(&self.base, flags, timeout) {
4016            Some(status) => status,
4017            None => constants::WAIT_FAILED,
4018        }
4019    }
4020
4021    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4022    fn WaitSync(&self, sync: &WebGLSync, flags: u32, timeout: i64) {
4023        if !sync.is_valid() {
4024            self.base.webgl_error(InvalidOperation);
4025            return;
4026        }
4027        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4028        if flags != 0 {
4029            self.base.webgl_error(InvalidValue);
4030            return;
4031        }
4032        if timeout != constants::TIMEOUT_IGNORED {
4033            self.base.webgl_error(InvalidValue);
4034            return;
4035        }
4036
4037        self.base
4038            .send_command(WebGLCommand::WaitSync(sync.id(), flags, timeout));
4039    }
4040
4041    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4042    fn GetSyncParameter(
4043        &self,
4044        _cx: JSContext,
4045        sync: &WebGLSync,
4046        pname: u32,
4047        mut retval: MutableHandleValue,
4048    ) {
4049        if !sync.is_valid() {
4050            self.base.webgl_error(InvalidOperation);
4051            return retval.set(NullValue());
4052        }
4053        handle_potential_webgl_error!(
4054            self.base,
4055            self.base.validate_ownership(sync),
4056            return retval.set(NullValue())
4057        );
4058        match pname {
4059            constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
4060                let (sender, receiver) = webgl_channel().unwrap();
4061                self.base
4062                    .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
4063                retval.set(UInt32Value(receiver.recv().unwrap()))
4064            },
4065            constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
4066                Some(status) => retval.set(UInt32Value(status)),
4067                None => retval.set(UInt32Value(constants::UNSIGNALED)),
4068            },
4069            _ => {
4070                self.base.webgl_error(InvalidEnum);
4071                retval.set(NullValue())
4072            },
4073        }
4074    }
4075
4076    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
4077    fn DeleteSync(&self, sync: Option<&WebGLSync>) {
4078        if let Some(sync) = sync {
4079            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
4080            sync.delete(Operation::Infallible);
4081        }
4082    }
4083
4084    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4085    fn BindSampler(&self, unit: u32, sampler: Option<&WebGLSampler>) {
4086        if let Some(sampler) = sampler {
4087            handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4088
4089            if unit as usize >= self.samplers.len() {
4090                self.base.webgl_error(InvalidValue);
4091                return;
4092            }
4093
4094            let result = sampler.bind(&self.base, unit);
4095            match result {
4096                Ok(_) => self.samplers[unit as usize].set(Some(sampler)),
4097                Err(error) => self.base.webgl_error(error),
4098            }
4099        }
4100    }
4101
4102    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17>
4103    fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
4104        self.base.bind_vertex_array_webgl2(array);
4105    }
4106
4107    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4108    fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
4109        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4110        let param = WebGLSamplerValue::GLenum(param as u32);
4111        let result = sampler.set_parameter(&self.base, pname, param);
4112        if let Err(error) = result {
4113            self.base.webgl_error(error);
4114        }
4115    }
4116
4117    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4118    fn SamplerParameterf(&self, sampler: &WebGLSampler, pname: u32, param: f32) {
4119        handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
4120        let param = WebGLSamplerValue::Float(param);
4121        let result = sampler.set_parameter(&self.base, pname, param);
4122        if let Err(error) = result {
4123            self.base.webgl_error(error);
4124        }
4125    }
4126
4127    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
4128    fn GetSamplerParameter(
4129        &self,
4130        _cx: JSContext,
4131        sampler: &WebGLSampler,
4132        pname: u32,
4133        mut retval: MutableHandleValue,
4134    ) {
4135        handle_potential_webgl_error!(
4136            self.base,
4137            self.base.validate_ownership(sampler),
4138            return retval.set(NullValue())
4139        );
4140        match sampler.get_parameter(&self.base, pname) {
4141            Ok(value) => match value {
4142                WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)),
4143                WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)),
4144            },
4145            Err(error) => {
4146                self.base.webgl_error(error);
4147                retval.set(NullValue())
4148            },
4149        }
4150    }
4151
4152    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4153    fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
4154        Some(WebGLTransformFeedback::new(&self.base, CanGc::note()))
4155    }
4156
4157    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4158    fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
4159        if let Some(tf) = tf {
4160            handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
4161            if tf.is_active() {
4162                self.base.webgl_error(InvalidOperation);
4163                return;
4164            }
4165            tf.delete(Operation::Infallible);
4166            self.current_transform_feedback.set(None);
4167        }
4168    }
4169
4170    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4171    fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
4172        match tf {
4173            Some(tf) => {
4174                if !tf.is_valid() {
4175                    return false;
4176                }
4177                handle_potential_webgl_error!(
4178                    self.base,
4179                    self.base.validate_ownership(tf),
4180                    return false
4181                );
4182                let (sender, receiver) = webgl_channel().unwrap();
4183                self.base
4184                    .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
4185                receiver.recv().unwrap()
4186            },
4187            None => false,
4188        }
4189    }
4190
4191    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4192    fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
4193        if target != constants::TRANSFORM_FEEDBACK {
4194            self.base.webgl_error(InvalidEnum);
4195            return;
4196        }
4197        match tf {
4198            Some(transform_feedback) => {
4199                handle_potential_webgl_error!(
4200                    self.base,
4201                    self.base.validate_ownership(transform_feedback),
4202                    return
4203                );
4204                if !transform_feedback.is_valid() {
4205                    self.base.webgl_error(InvalidOperation);
4206                    return;
4207                }
4208                if let Some(current_tf) = self.current_transform_feedback.get() {
4209                    if current_tf.is_active() && !current_tf.is_paused() {
4210                        self.base.webgl_error(InvalidOperation);
4211                        return;
4212                    }
4213                }
4214                transform_feedback.bind(&self.base, target);
4215                self.current_transform_feedback
4216                    .set(Some(transform_feedback));
4217            },
4218            None => self
4219                .base
4220                .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
4221        }
4222    }
4223
4224    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4225    #[allow(non_snake_case)]
4226    fn BeginTransformFeedback(&self, primitiveMode: u32) {
4227        match primitiveMode {
4228            constants::POINTS | constants::LINES | constants::TRIANGLES => {},
4229            _ => {
4230                self.base.webgl_error(InvalidEnum);
4231                return;
4232            },
4233        };
4234        let current_tf = match self.current_transform_feedback.get() {
4235            Some(current_tf) => current_tf,
4236            None => {
4237                self.base.webgl_error(InvalidOperation);
4238                return;
4239            },
4240        };
4241        if current_tf.is_active() {
4242            self.base.webgl_error(InvalidOperation);
4243            return;
4244        };
4245        let program = match self.base.current_program() {
4246            Some(program) => program,
4247            None => {
4248                self.base.webgl_error(InvalidOperation);
4249                return;
4250            },
4251        };
4252        if !program.is_linked() || program.transform_feedback_varyings_length() == 0 {
4253            self.base.webgl_error(InvalidOperation);
4254            return;
4255        };
4256        current_tf.begin(&self.base, primitiveMode);
4257    }
4258
4259    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4260    fn EndTransformFeedback(&self) {
4261        if let Some(current_tf) = self.current_transform_feedback.get() {
4262            if !current_tf.is_active() {
4263                self.base.webgl_error(InvalidOperation);
4264                return;
4265            }
4266            current_tf.end(&self.base);
4267        }
4268    }
4269
4270    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4271    fn ResumeTransformFeedback(&self) {
4272        if let Some(current_tf) = self.current_transform_feedback.get() {
4273            if !current_tf.is_active() || !current_tf.is_paused() {
4274                self.base.webgl_error(InvalidOperation);
4275                return;
4276            }
4277            current_tf.resume(&self.base);
4278        }
4279    }
4280
4281    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4282    fn PauseTransformFeedback(&self) {
4283        if let Some(current_tf) = self.current_transform_feedback.get() {
4284            if !current_tf.is_active() || current_tf.is_paused() {
4285                self.base.webgl_error(InvalidOperation);
4286                return;
4287            }
4288            current_tf.pause(&self.base);
4289        }
4290    }
4291
4292    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4293    #[allow(non_snake_case)]
4294    fn TransformFeedbackVaryings(
4295        &self,
4296        program: &WebGLProgram,
4297        varyings: Vec<DOMString>,
4298        bufferMode: u32,
4299    ) {
4300        handle_potential_webgl_error!(self.base, program.validate(), return);
4301        let strs = varyings
4302            .iter()
4303            .map(|name| String::from(name.to_owned()))
4304            .collect::<Vec<String>>();
4305        match bufferMode {
4306            constants::INTERLEAVED_ATTRIBS => {
4307                self.base
4308                    .send_command(WebGLCommand::TransformFeedbackVaryings(
4309                        program.id(),
4310                        strs,
4311                        bufferMode,
4312                    ));
4313            },
4314            constants::SEPARATE_ATTRIBS => {
4315                let max_tf_sp_att =
4316                    self.base.limits().max_transform_feedback_separate_attribs as usize;
4317                if strs.len() >= max_tf_sp_att {
4318                    self.base.webgl_error(InvalidValue);
4319                    return;
4320                }
4321                self.base
4322                    .send_command(WebGLCommand::TransformFeedbackVaryings(
4323                        program.id(),
4324                        strs,
4325                        bufferMode,
4326                    ));
4327            },
4328            _ => self.base.webgl_error(InvalidEnum),
4329        }
4330    }
4331
4332    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15>
4333    fn GetTransformFeedbackVarying(
4334        &self,
4335        program: &WebGLProgram,
4336        index: u32,
4337    ) -> Option<DomRoot<WebGLActiveInfo>> {
4338        handle_potential_webgl_error!(self.base, program.validate(), return None);
4339        if index >= program.transform_feedback_varyings_length() as u32 {
4340            self.base.webgl_error(InvalidValue);
4341            return None;
4342        }
4343
4344        let (sender, receiver) = webgl_channel().unwrap();
4345        self.base
4346            .send_command(WebGLCommand::GetTransformFeedbackVarying(
4347                program.id(),
4348                index,
4349                sender,
4350            ));
4351        let (size, ty, name) = receiver.recv().unwrap();
4352        Some(WebGLActiveInfo::new(
4353            self.base.global().as_window(),
4354            size,
4355            ty,
4356            DOMString::from(name),
4357            CanGc::note(),
4358        ))
4359    }
4360
4361    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4362    fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
4363        let (generic_slot, indexed_bindings) = match target {
4364            constants::TRANSFORM_FEEDBACK_BUFFER => (
4365                &self.bound_transform_feedback_buffer,
4366                &self.indexed_transform_feedback_buffer_bindings,
4367            ),
4368            constants::UNIFORM_BUFFER => (
4369                &self.bound_uniform_buffer,
4370                &self.indexed_uniform_buffer_bindings,
4371            ),
4372            _ => return self.base.webgl_error(InvalidEnum),
4373        };
4374        let indexed_binding = match indexed_bindings.get(index as usize) {
4375            Some(slot) => slot,
4376            None => return self.base.webgl_error(InvalidValue),
4377        };
4378
4379        if let Some(buffer) = buffer {
4380            handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4381
4382            if buffer.is_marked_for_deletion() {
4383                return self.base.webgl_error(InvalidOperation);
4384            }
4385            handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4386
4387            // for both the generic and the indexed bindings
4388            buffer.increment_attached_counter();
4389            buffer.increment_attached_counter();
4390        }
4391
4392        self.base.send_command(WebGLCommand::BindBufferBase(
4393            target,
4394            index,
4395            buffer.map(|b| b.id()),
4396        ));
4397
4398        for slot in &[generic_slot, &indexed_binding.buffer] {
4399            if let Some(old) = slot.get() {
4400                old.decrement_attached_counter(Operation::Infallible);
4401            }
4402            slot.set(buffer);
4403        }
4404        indexed_binding.start.set(0);
4405        indexed_binding.size.set(0);
4406    }
4407
4408    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4409    fn BindBufferRange(
4410        &self,
4411        target: u32,
4412        index: u32,
4413        buffer: Option<&WebGLBuffer>,
4414        offset: i64,
4415        size: i64,
4416    ) {
4417        let (generic_slot, indexed_bindings) = match target {
4418            constants::TRANSFORM_FEEDBACK_BUFFER => (
4419                &self.bound_transform_feedback_buffer,
4420                &self.indexed_transform_feedback_buffer_bindings,
4421            ),
4422            constants::UNIFORM_BUFFER => (
4423                &self.bound_uniform_buffer,
4424                &self.indexed_uniform_buffer_bindings,
4425            ),
4426            _ => return self.base.webgl_error(InvalidEnum),
4427        };
4428        let indexed_binding = match indexed_bindings.get(index as usize) {
4429            Some(slot) => slot,
4430            None => return self.base.webgl_error(InvalidValue),
4431        };
4432
4433        if offset < 0 || size < 0 {
4434            return self.base.webgl_error(InvalidValue);
4435        }
4436        if buffer.is_some() && size == 0 {
4437            return self.base.webgl_error(InvalidValue);
4438        }
4439
4440        match target {
4441            constants::TRANSFORM_FEEDBACK_BUFFER => {
4442                if size % 4 != 0 && offset % 4 != 0 {
4443                    return self.base.webgl_error(InvalidValue);
4444                }
4445            },
4446            constants::UNIFORM_BUFFER => {
4447                let offset_alignment = self.base.limits().uniform_buffer_offset_alignment;
4448                if offset % offset_alignment as i64 != 0 {
4449                    return self.base.webgl_error(InvalidValue);
4450                }
4451            },
4452            _ => unreachable!(),
4453        }
4454
4455        if let Some(buffer) = buffer {
4456            handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
4457
4458            if buffer.is_marked_for_deletion() {
4459                return self.base.webgl_error(InvalidOperation);
4460            }
4461            handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
4462
4463            // for both the generic and the indexed bindings
4464            buffer.increment_attached_counter();
4465            buffer.increment_attached_counter();
4466        }
4467
4468        self.base.send_command(WebGLCommand::BindBufferRange(
4469            target,
4470            index,
4471            buffer.map(|b| b.id()),
4472            offset,
4473            size,
4474        ));
4475
4476        for slot in &[generic_slot, &indexed_binding.buffer] {
4477            if let Some(old) = slot.get() {
4478                old.decrement_attached_counter(Operation::Infallible);
4479            }
4480            slot.set(buffer);
4481        }
4482        indexed_binding.start.set(offset);
4483        indexed_binding.size.set(size);
4484    }
4485
4486    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4487    fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> {
4488        handle_potential_webgl_error!(
4489            self.base,
4490            self.base.validate_ownership(program),
4491            return None
4492        );
4493        let indices = handle_potential_webgl_error!(
4494            self.base,
4495            program.get_uniform_indices(names),
4496            return None
4497        );
4498        Some(indices)
4499    }
4500
4501    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4502    fn GetActiveUniforms(
4503        &self,
4504        cx: JSContext,
4505        program: &WebGLProgram,
4506        indices: Vec<u32>,
4507        pname: u32,
4508        mut rval: MutableHandleValue,
4509    ) {
4510        handle_potential_webgl_error!(
4511            self.base,
4512            self.base.validate_ownership(program),
4513            return rval.set(NullValue())
4514        );
4515        let values = handle_potential_webgl_error!(
4516            self.base,
4517            program.get_active_uniforms(indices, pname),
4518            return rval.set(NullValue())
4519        );
4520
4521        match pname {
4522            constants::UNIFORM_SIZE |
4523            constants::UNIFORM_TYPE |
4524            constants::UNIFORM_BLOCK_INDEX |
4525            constants::UNIFORM_OFFSET |
4526            constants::UNIFORM_ARRAY_STRIDE |
4527            constants::UNIFORM_MATRIX_STRIDE => {
4528                values.safe_to_jsval(cx, rval);
4529            },
4530            constants::UNIFORM_IS_ROW_MAJOR => {
4531                let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
4532                values.safe_to_jsval(cx, rval);
4533            },
4534            _ => unreachable!(),
4535        }
4536    }
4537
4538    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4539    fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 {
4540        handle_potential_webgl_error!(
4541            self.base,
4542            self.base.validate_ownership(program),
4543            return constants::INVALID_INDEX
4544        );
4545        handle_potential_webgl_error!(
4546            self.base,
4547            program.get_uniform_block_index(block_name),
4548            constants::INVALID_INDEX
4549        )
4550    }
4551
4552    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4553    #[allow(unsafe_code)]
4554    fn GetActiveUniformBlockParameter(
4555        &self,
4556        cx: JSContext,
4557        program: &WebGLProgram,
4558        block_index: u32,
4559        pname: u32,
4560        mut retval: MutableHandleValue,
4561    ) {
4562        handle_potential_webgl_error!(
4563            self.base,
4564            self.base.validate_ownership(program),
4565            return retval.set(NullValue())
4566        );
4567        let values = handle_potential_webgl_error!(
4568            self.base,
4569            program.get_active_uniform_block_parameter(block_index, pname),
4570            return retval.set(NullValue())
4571        );
4572        match pname {
4573            constants::UNIFORM_BLOCK_BINDING |
4574            constants::UNIFORM_BLOCK_DATA_SIZE |
4575            constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
4576                assert!(values.len() == 1);
4577                retval.set(UInt32Value(values[0] as u32))
4578            },
4579            constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
4580                let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
4581                rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
4582                Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap();
4583                retval.set(ObjectValue(result.get()))
4584            },
4585            constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
4586            constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
4587                assert!(values.len() == 1);
4588                retval.set(BooleanValue(values[0] != 0))
4589            },
4590            _ => unreachable!(),
4591        }
4592    }
4593
4594    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4595    fn GetActiveUniformBlockName(
4596        &self,
4597        program: &WebGLProgram,
4598        block_index: u32,
4599    ) -> Option<DOMString> {
4600        handle_potential_webgl_error!(
4601            self.base,
4602            self.base.validate_ownership(program),
4603            return None
4604        );
4605        let name = handle_potential_webgl_error!(
4606            self.base,
4607            program.get_active_uniform_block_name(block_index),
4608            return None
4609        );
4610        Some(DOMString::from(name))
4611    }
4612
4613    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
4614    fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) {
4615        handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return);
4616
4617        if block_binding >= self.base.limits().max_uniform_buffer_bindings {
4618            return self.base.webgl_error(InvalidValue);
4619        }
4620
4621        handle_potential_webgl_error!(
4622            self.base,
4623            program.bind_uniform_block(block_index, block_binding)
4624        )
4625    }
4626
4627    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4628    fn ClearBufferfv(
4629        &self,
4630        buffer: u32,
4631        draw_buffer: i32,
4632        values: Float32ArrayOrUnrestrictedFloatSequence,
4633        src_offset: u32,
4634    ) {
4635        let array = match values {
4636            Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4637            Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4638        };
4639        self.clear_buffer::<f32>(
4640            buffer,
4641            draw_buffer,
4642            &[constants::COLOR, constants::DEPTH],
4643            src_offset,
4644            array,
4645            WebGLCommand::ClearBufferfv,
4646        )
4647    }
4648
4649    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4650    fn ClearBufferiv(
4651        &self,
4652        buffer: u32,
4653        draw_buffer: i32,
4654        values: Int32ArrayOrLongSequence,
4655        src_offset: u32,
4656    ) {
4657        let array = match values {
4658            Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
4659            Int32ArrayOrLongSequence::LongSequence(v) => v,
4660        };
4661        self.clear_buffer::<i32>(
4662            buffer,
4663            draw_buffer,
4664            &[constants::COLOR, constants::STENCIL],
4665            src_offset,
4666            array,
4667            WebGLCommand::ClearBufferiv,
4668        )
4669    }
4670
4671    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4672    fn ClearBufferuiv(
4673        &self,
4674        buffer: u32,
4675        draw_buffer: i32,
4676        values: Uint32ArrayOrUnsignedLongSequence,
4677        src_offset: u32,
4678    ) {
4679        let array = match values {
4680            Uint32ArrayOrUnsignedLongSequence::Uint32Array(v) => v.to_vec(),
4681            Uint32ArrayOrUnsignedLongSequence::UnsignedLongSequence(v) => v,
4682        };
4683        self.clear_buffer::<u32>(
4684            buffer,
4685            draw_buffer,
4686            &[constants::COLOR],
4687            src_offset,
4688            array,
4689            WebGLCommand::ClearBufferuiv,
4690        )
4691    }
4692
4693    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4694    fn ClearBufferfi(&self, buffer: u32, draw_buffer: i32, depth: f32, stencil: i32) {
4695        if buffer != constants::DEPTH_STENCIL {
4696            return self.base.webgl_error(InvalidEnum);
4697        }
4698
4699        handle_potential_webgl_error!(
4700            self.base,
4701            self.clearbuffer_array_size(buffer, draw_buffer),
4702            return
4703        );
4704
4705        self.base.send_command(WebGLCommand::ClearBufferfi(
4706            buffer,
4707            draw_buffer,
4708            depth,
4709            stencil,
4710        ));
4711    }
4712
4713    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4714    fn InvalidateFramebuffer(&self, target: u32, attachments: Vec<u32>) {
4715        if !self.valid_fb_attachment_values(target, &attachments) {
4716            return;
4717        }
4718
4719        self.base
4720            .send_command(WebGLCommand::InvalidateFramebuffer(target, attachments))
4721    }
4722
4723    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4724    fn InvalidateSubFramebuffer(
4725        &self,
4726        target: u32,
4727        attachments: Vec<u32>,
4728        x: i32,
4729        y: i32,
4730        width: i32,
4731        height: i32,
4732    ) {
4733        if !self.valid_fb_attachment_values(target, &attachments) {
4734            return;
4735        }
4736
4737        if width < 0 || height < 0 {
4738            return self.base.webgl_error(InvalidValue);
4739        }
4740
4741        self.base
4742            .send_command(WebGLCommand::InvalidateSubFramebuffer(
4743                target,
4744                attachments,
4745                x,
4746                y,
4747                width,
4748                height,
4749            ))
4750    }
4751
4752    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4753    fn FramebufferTextureLayer(
4754        &self,
4755        target: u32,
4756        attachment: u32,
4757        texture: Option<&WebGLTexture>,
4758        level: i32,
4759        layer: i32,
4760    ) {
4761        if let Some(tex) = texture {
4762            handle_potential_webgl_error!(self.base, self.base.validate_ownership(tex), return);
4763        }
4764
4765        let fb_slot = match target {
4766            constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
4767                self.base.get_draw_framebuffer_slot()
4768            },
4769            constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
4770            _ => return self.base.webgl_error(InvalidEnum),
4771        };
4772
4773        match fb_slot.get() {
4774            Some(fb) => handle_potential_webgl_error!(
4775                self.base,
4776                fb.texture_layer(attachment, texture, level, layer)
4777            ),
4778            None => self.base.webgl_error(InvalidOperation),
4779        }
4780    }
4781
4782    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5>
4783    #[allow(unsafe_code)]
4784    fn GetInternalformatParameter(
4785        &self,
4786        cx: JSContext,
4787        target: u32,
4788        internal_format: u32,
4789        pname: u32,
4790        mut retval: MutableHandleValue,
4791    ) {
4792        if target != constants::RENDERBUFFER {
4793            self.base.webgl_error(InvalidEnum);
4794            return retval.set(NullValue());
4795        }
4796
4797        match handle_potential_webgl_error!(
4798            self.base,
4799            InternalFormatParameter::from_u32(pname),
4800            return retval.set(NullValue())
4801        ) {
4802            InternalFormatParameter::IntVec(param) => unsafe {
4803                let (sender, receiver) = webgl_channel().unwrap();
4804                self.base
4805                    .send_command(WebGLCommand::GetInternalFormatIntVec(
4806                        target,
4807                        internal_format,
4808                        param,
4809                        sender,
4810                    ));
4811
4812                rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
4813                Int32Array::create(
4814                    *cx,
4815                    CreateWith::Slice(&receiver.recv().unwrap()),
4816                    rval.handle_mut(),
4817                )
4818                .unwrap();
4819                retval.set(ObjectValue(rval.get()))
4820            },
4821        }
4822    }
4823
4824    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5>
4825    fn RenderbufferStorageMultisample(
4826        &self,
4827        target: u32,
4828        samples: i32,
4829        internal_format: u32,
4830        width: i32,
4831        height: i32,
4832    ) {
4833        self.base
4834            .renderbuffer_storage(target, samples, internal_format, width, height)
4835    }
4836
4837    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4>
4838    fn ReadBuffer(&self, src: u32) {
4839        match src {
4840            constants::BACK | constants::NONE => {},
4841            _ if self.base.valid_color_attachment_enum(src) => {},
4842            _ => return self.base.webgl_error(InvalidEnum),
4843        }
4844
4845        if let Some(fb) = self.base.get_read_framebuffer_slot().get() {
4846            handle_potential_webgl_error!(self.base, fb.set_read_buffer(src))
4847        } else {
4848            match src {
4849                constants::NONE | constants::BACK => {},
4850                _ => return self.base.webgl_error(InvalidOperation),
4851            }
4852
4853            self.default_fb_readbuffer.set(src);
4854            self.base.send_command(WebGLCommand::ReadBuffer(src));
4855        }
4856    }
4857
4858    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11>
4859    fn DrawBuffers(&self, buffers: Vec<u32>) {
4860        if let Some(fb) = self.base.get_draw_framebuffer_slot().get() {
4861            handle_potential_webgl_error!(self.base, fb.set_draw_buffers(buffers))
4862        } else {
4863            if buffers.len() != 1 {
4864                return self.base.webgl_error(InvalidOperation);
4865            }
4866
4867            match buffers[0] {
4868                constants::NONE | constants::BACK => {},
4869                _ => return self.base.webgl_error(InvalidOperation),
4870            }
4871
4872            self.default_fb_drawbuffer.set(buffers[0]);
4873            self.base.send_command(WebGLCommand::DrawBuffers(buffers));
4874        }
4875    }
4876
4877    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
4878    fn TexStorage2D(
4879        &self,
4880        target: u32,
4881        levels: i32,
4882        internal_format: u32,
4883        width: i32,
4884        height: i32,
4885    ) {
4886        self.tex_storage(2, target, levels, internal_format, width, height, 1)
4887    }
4888
4889    /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6>
4890    fn TexStorage3D(
4891        &self,
4892        target: u32,
4893        levels: i32,
4894        internal_format: u32,
4895        width: i32,
4896        height: i32,
4897        depth: i32,
4898    ) {
4899        self.tex_storage(3, target, levels, internal_format, width, height, depth)
4900    }
4901
4902    /// <https://immersive-web.github.io/webxr/#dom-webglrenderingcontextbase-makexrcompatible>
4903    #[cfg(feature = "webxr")]
4904    fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4905        // XXXManishearth Fill in with compatibility checks when rust-webxr supports this
4906        let p = Promise::new(&self.global(), can_gc);
4907        p.resolve_native(&(), can_gc);
4908        p
4909    }
4910}
4911
4912impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
4913    #[allow(unsafe_code)]
4914    fn canvas_data_source(self) -> Option<ImageKey> {
4915        let this = self.unsafe_get();
4916        unsafe { (*this.base.to_layout().unsafe_get()).layout_handle() }
4917    }
4918}
4919
4920impl WebGL2RenderingContextHelpers for WebGL2RenderingContext {
4921    fn is_webgl2_enabled(cx: JSContext, global: HandleObject) -> bool {
4922        Self::is_webgl2_enabled(cx, global)
4923    }
4924}