1use std::cell::Cell;
6use std::cmp;
7use std::ptr::{self, NonNull};
8#[cfg(feature = "webxr")]
9use std::rc::Rc;
10
11#[cfg(feature = "webgl_backtrace")]
12use backtrace::Backtrace;
13use bitflags::bitflags;
14use canvas_traits::webgl::WebGLError::*;
15use canvas_traits::webgl::{
16 AlphaTreatment, GLContextAttributes, GLLimits, GlType, Parameter, SizedDataType, TexDataType,
17 TexFormat, TexParameter, WebGLChan, WebGLCommand, WebGLCommandBacktrace, WebGLContextId,
18 WebGLError, WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLProgramId,
19 WebGLResult, WebGLSLVersion, WebGLSendResult, WebGLSender, WebGLVersion, YAxisTreatment,
20 webgl_channel,
21};
22use dom_struct::dom_struct;
23use euclid::default::{Point2D, Rect, Size2D};
24use ipc_channel::ipc::{self, IpcSharedMemory};
25use js::jsapi::{JSContext, JSObject, Type};
26use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
27use js::rust::{CustomAutoRooterGuard, MutableHandleValue};
28use js::typedarray::{
29 ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, TypedArray,
30 TypedArrayElementCreator, Uint32Array,
31};
32use pixels::{self, Alpha, PixelFormat, Snapshot, SnapshotPixelFormat};
33use script_bindings::conversions::SafeToJSValConvertible;
34use serde::{Deserialize, Serialize};
35use servo_config::pref;
36use webrender_api::ImageKey;
37
38use crate::canvas_context::{
39 CanvasContext, HTMLCanvasElementOrOffscreenCanvas, LayoutCanvasRenderingContextHelpers,
40};
41use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
42use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
43use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
44use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
45use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants;
46use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{
47 TexImageSource, WebGLContextAttributes, WebGLRenderingContextConstants as constants,
48 WebGLRenderingContextMethods,
49};
50use crate::dom::bindings::codegen::UnionTypes::{
51 ArrayBufferViewOrArrayBuffer, Float32ArrayOrUnrestrictedFloatSequence,
52 HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas,
53 Int32ArrayOrLongSequence,
54};
55use crate::dom::bindings::conversions::DerivedFrom;
56use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
57use crate::dom::bindings::inheritance::Castable;
58use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
59use crate::dom::bindings::root::{DomOnceCell, DomRoot, LayoutDom, MutNullableDom};
60use crate::dom::bindings::str::DOMString;
61use crate::dom::event::{Event, EventBubbles, EventCancelable};
62#[cfg(feature = "webgl_backtrace")]
63use crate::dom::globalscope::GlobalScope;
64use crate::dom::node::{Node, NodeDamage, NodeTraits};
65#[cfg(feature = "webxr")]
66use crate::dom::promise::Promise;
67use crate::dom::webgl::extensions::WebGLExtensions;
68use crate::dom::webgl::validations::WebGLValidator;
69use crate::dom::webgl::validations::tex_image_2d::{
70 CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
71 CommonTexImage2DValidatorResult, CompressedTexImage2DValidator,
72 CompressedTexSubImage2DValidator, TexImage2DValidator, TexImage2DValidatorResult,
73};
74use crate::dom::webgl::validations::types::TexImageTarget;
75use crate::dom::webgl::vertexarrayobject::VertexAttribData;
76use crate::dom::webgl::webglactiveinfo::WebGLActiveInfo;
77use crate::dom::webgl::webglbuffer::WebGLBuffer;
78use crate::dom::webgl::webglcontextevent::WebGLContextEvent;
79use crate::dom::webgl::webglframebuffer::{
80 CompleteForRendering, WebGLFramebuffer, WebGLFramebufferAttachmentRoot,
81};
82use crate::dom::webgl::webglobject::WebGLObject;
83use crate::dom::webgl::webglprogram::WebGLProgram;
84use crate::dom::webgl::webglrenderbuffer::WebGLRenderbuffer;
85use crate::dom::webgl::webglshader::WebGLShader;
86use crate::dom::webgl::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
87use crate::dom::webgl::webgltexture::{TexParameterValue, WebGLTexture};
88use crate::dom::webgl::webgluniformlocation::WebGLUniformLocation;
89use crate::dom::webgl::webglvertexarrayobject::WebGLVertexArrayObject;
90use crate::dom::webgl::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
91use crate::dom::window::Window;
92use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
93
94macro_rules! handle_object_deletion {
103 ($self_:expr, $binding:expr, $object:ident, $unbind_command:expr) => {
104 if let Some(bound_object) = $binding.get() {
105 if bound_object.id() == $object.id() {
106 $binding.set(None);
107 if let Some(command) = $unbind_command {
108 $self_.send_command(command);
109 }
110 }
111 }
112 };
113}
114
115fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool {
116 match (arg1, arg2) {
117 (constants::CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
118 (constants::ONE_MINUS_CONSTANT_COLOR, constants::ONE_MINUS_CONSTANT_ALPHA) => true,
119 (constants::ONE_MINUS_CONSTANT_COLOR, constants::CONSTANT_ALPHA) => true,
120 (constants::CONSTANT_COLOR, constants::ONE_MINUS_CONSTANT_ALPHA) => true,
121 (_, _) => false,
122 }
123}
124
125pub(crate) fn uniform_get<T, F>(triple: (&WebGLRenderingContext, WebGLProgramId, i32), f: F) -> T
126where
127 F: FnOnce(WebGLProgramId, i32, WebGLSender<T>) -> WebGLCommand,
128 T: for<'de> Deserialize<'de> + Serialize,
129{
130 let (sender, receiver) = webgl_channel().unwrap();
131 triple.0.send_command(f(triple.1, triple.2, sender));
132 receiver.recv().unwrap()
133}
134
135#[allow(unsafe_code)]
136pub(crate) unsafe fn uniform_typed<T>(
137 cx: *mut JSContext,
138 value: &[T::Element],
139 mut retval: MutableHandleValue,
140) where
141 T: TypedArrayElementCreator,
142{
143 rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
144 <TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(value), rval.handle_mut())
145 .unwrap();
146 retval.set(ObjectValue(rval.get()));
147}
148
149#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
151pub(crate) struct TextureUnpacking(u8);
152
153bitflags! {
154 impl TextureUnpacking: u8 {
155 const FLIP_Y_AXIS = 0x01;
156 const PREMULTIPLY_ALPHA = 0x02;
157 const CONVERT_COLORSPACE = 0x04;
158 }
159}
160
161#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)]
162pub(crate) enum VertexAttrib {
163 Float(f32, f32, f32, f32),
164 Int(i32, i32, i32, i32),
165 Uint(u32, u32, u32, u32),
166}
167
168#[derive(Clone, Copy, Debug)]
169pub(crate) enum Operation {
170 Fallible,
171 Infallible,
172}
173
174#[dom_struct]
175pub(crate) struct WebGLRenderingContext {
176 reflector_: Reflector,
177 #[ignore_malloc_size_of = "Channels are hard"]
178 webgl_sender: WebGLMessageSender,
179 #[ignore_malloc_size_of = "Defined in webrender"]
180 #[no_trace]
181 webrender_image: ImageKey,
182 #[no_trace]
183 webgl_version: WebGLVersion,
184 #[no_trace]
185 glsl_version: WebGLSLVersion,
186 #[ignore_malloc_size_of = "Defined in surfman"]
187 #[no_trace]
188 limits: GLLimits,
189 canvas: HTMLCanvasElementOrOffscreenCanvas,
190 #[ignore_malloc_size_of = "Defined in canvas_traits"]
191 #[no_trace]
192 last_error: Cell<Option<WebGLError>>,
193 texture_packing_alignment: Cell<u8>,
194 texture_unpacking_settings: Cell<TextureUnpacking>,
195 texture_unpacking_alignment: Cell<u32>,
197 bound_draw_framebuffer: MutNullableDom<WebGLFramebuffer>,
198 bound_read_framebuffer: MutNullableDom<WebGLFramebuffer>,
201 bound_renderbuffer: MutNullableDom<WebGLRenderbuffer>,
202 bound_buffer_array: MutNullableDom<WebGLBuffer>,
203 current_program: MutNullableDom<WebGLProgram>,
204 current_vertex_attribs: DomRefCell<Box<[VertexAttrib]>>,
205 #[ignore_malloc_size_of = "Because it's small"]
206 current_scissor: Cell<(i32, i32, u32, u32)>,
207 #[ignore_malloc_size_of = "Because it's small"]
208 current_clear_color: Cell<(f32, f32, f32, f32)>,
209 #[no_trace]
210 size: Cell<Size2D<u32>>,
211 extension_manager: WebGLExtensions,
212 capabilities: Capabilities,
213 default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
214 current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
215 default_vao_webgl2: DomOnceCell<WebGLVertexArrayObject>,
216 current_vao_webgl2: MutNullableDom<WebGLVertexArrayObject>,
217 textures: Textures,
218 #[no_trace]
219 api_type: GlType,
220}
221
222impl WebGLRenderingContext {
223 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
224 pub(crate) fn new_inherited(
225 window: &Window,
226 canvas: HTMLCanvasElementOrOffscreenCanvas,
227 webgl_version: WebGLVersion,
228 size: Size2D<u32>,
229 attrs: GLContextAttributes,
230 ) -> Result<WebGLRenderingContext, String> {
231 if pref!(webgl_testing_context_creation_error) {
232 return Err("WebGL context creation error forced by pref `webgl.testing.context_creation_error`".into());
233 }
234
235 let webgl_chan = match window.webgl_chan() {
236 Some(chan) => chan,
237 None => return Err("WebGL initialization failed early on".into()),
238 };
239
240 let (sender, receiver) = webgl_channel().unwrap();
241 webgl_chan
242 .send(WebGLMsg::CreateContext(webgl_version, size, attrs, sender))
243 .unwrap();
244 let result = receiver.recv().unwrap();
245
246 result.map(|ctx_data| {
247 let max_combined_texture_image_units = ctx_data.limits.max_combined_texture_image_units;
248 let max_vertex_attribs = ctx_data.limits.max_vertex_attribs as usize;
249 Self {
250 reflector_: Reflector::new(),
251 webgl_sender: WebGLMessageSender::new(ctx_data.sender),
252 webrender_image: ctx_data.image_key,
253 webgl_version,
254 glsl_version: ctx_data.glsl_version,
255 limits: ctx_data.limits,
256 canvas,
257 last_error: Cell::new(None),
258 texture_packing_alignment: Cell::new(4),
259 texture_unpacking_settings: Cell::new(TextureUnpacking::CONVERT_COLORSPACE),
260 texture_unpacking_alignment: Cell::new(4),
261 bound_draw_framebuffer: MutNullableDom::new(None),
262 bound_read_framebuffer: MutNullableDom::new(None),
263 bound_buffer_array: MutNullableDom::new(None),
264 bound_renderbuffer: MutNullableDom::new(None),
265 current_program: MutNullableDom::new(None),
266 current_vertex_attribs: DomRefCell::new(
267 vec![VertexAttrib::Float(0f32, 0f32, 0f32, 1f32); max_vertex_attribs].into(),
268 ),
269 current_scissor: Cell::new((0, 0, size.width, size.height)),
270 size: Cell::new(size),
273 current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)),
274 extension_manager: WebGLExtensions::new(
275 webgl_version,
276 ctx_data.api_type,
277 ctx_data.glsl_version,
278 ),
279 capabilities: Default::default(),
280 default_vao: Default::default(),
281 current_vao: Default::default(),
282 default_vao_webgl2: Default::default(),
283 current_vao_webgl2: Default::default(),
284 textures: Textures::new(max_combined_texture_image_units),
285 api_type: ctx_data.api_type,
286 }
287 })
288 }
289
290 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
291 pub(crate) fn new(
292 window: &Window,
293 canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
294 webgl_version: WebGLVersion,
295 size: Size2D<u32>,
296 attrs: GLContextAttributes,
297 can_gc: CanGc,
298 ) -> Option<DomRoot<WebGLRenderingContext>> {
299 match WebGLRenderingContext::new_inherited(
300 window,
301 HTMLCanvasElementOrOffscreenCanvas::from(canvas),
302 webgl_version,
303 size,
304 attrs,
305 ) {
306 Ok(ctx) => Some(reflect_dom_object(Box::new(ctx), window, can_gc)),
307 Err(msg) => {
308 error!("Couldn't create WebGLRenderingContext: {}", msg);
309 let event = WebGLContextEvent::new(
310 window,
311 atom!("webglcontextcreationerror"),
312 EventBubbles::DoesNotBubble,
313 EventCancelable::Cancelable,
314 DOMString::from(msg),
315 can_gc,
316 );
317 match canvas {
318 RootedHTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => {
319 event.upcast::<Event>().fire(canvas.upcast(), can_gc);
320 },
321 RootedHTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => {
322 event.upcast::<Event>().fire(canvas.upcast(), can_gc);
323 },
324 }
325 None
326 },
327 }
328 }
329
330 pub(crate) fn webgl_version(&self) -> WebGLVersion {
331 self.webgl_version
332 }
333
334 pub(crate) fn limits(&self) -> &GLLimits {
335 &self.limits
336 }
337
338 pub(crate) fn texture_unpacking_alignment(&self) -> u32 {
339 self.texture_unpacking_alignment.get()
340 }
341
342 pub(crate) fn bound_draw_framebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
343 self.bound_draw_framebuffer.get()
344 }
345
346 pub(crate) fn current_vao(&self) -> DomRoot<WebGLVertexArrayObjectOES> {
347 self.current_vao.or_init(|| {
348 DomRoot::from_ref(
349 self.default_vao
350 .init_once(|| WebGLVertexArrayObjectOES::new(self, None, CanGc::note())),
351 )
352 })
353 }
354
355 pub(crate) fn current_vao_webgl2(&self) -> DomRoot<WebGLVertexArrayObject> {
356 self.current_vao_webgl2.or_init(|| {
357 DomRoot::from_ref(
358 self.default_vao_webgl2
359 .init_once(|| WebGLVertexArrayObject::new(self, None, CanGc::note())),
360 )
361 })
362 }
363
364 pub(crate) fn current_vertex_attribs(&self) -> RefMut<'_, Box<[VertexAttrib]>> {
365 self.current_vertex_attribs.borrow_mut()
366 }
367
368 #[inline]
369 pub(crate) fn send_command(&self, command: WebGLCommand) {
370 self.webgl_sender
371 .send(command, capture_webgl_backtrace())
372 .unwrap();
373 }
374
375 pub(crate) fn send_command_ignored(&self, command: WebGLCommand) {
376 let _ = self.webgl_sender.send(command, capture_webgl_backtrace());
377 }
378
379 pub(crate) fn webgl_error(&self, err: WebGLError) {
380 warn!(
382 "WebGL error: {:?}, previous error was {:?}",
383 err,
384 self.last_error.get()
385 );
386
387 if self.last_error.get().is_none() {
390 self.last_error.set(Some(err));
391 }
392 }
393
394 pub(crate) fn validate_framebuffer(&self) -> WebGLResult<()> {
413 match self.bound_draw_framebuffer.get() {
414 Some(fb) => match fb.check_status_for_rendering() {
415 CompleteForRendering::Complete => Ok(()),
416 CompleteForRendering::Incomplete => Err(InvalidFramebufferOperation),
417 CompleteForRendering::MissingColorAttachment => Err(InvalidOperation),
418 },
419 None => Ok(()),
420 }
421 }
422
423 pub(crate) fn validate_ownership<T>(&self, object: &T) -> WebGLResult<()>
424 where
425 T: DerivedFrom<WebGLObject>,
426 {
427 if self != object.upcast().context() {
428 return Err(InvalidOperation);
429 }
430 Ok(())
431 }
432
433 pub(crate) fn with_location<F>(&self, location: Option<&WebGLUniformLocation>, f: F)
434 where
435 F: FnOnce(&WebGLUniformLocation) -> WebGLResult<()>,
436 {
437 let location = match location {
438 Some(loc) => loc,
439 None => return,
440 };
441 match self.current_program.get() {
442 Some(ref program)
443 if program.id() == location.program_id() &&
444 program.link_generation() == location.link_generation() => {},
445 _ => return self.webgl_error(InvalidOperation),
446 }
447 handle_potential_webgl_error!(self, f(location));
448 }
449
450 pub(crate) fn textures(&self) -> &Textures {
451 &self.textures
452 }
453
454 fn tex_parameter(&self, target: u32, param: u32, value: TexParameterValue) {
455 let texture_slot = handle_potential_webgl_error!(
456 self,
457 self.textures
458 .active_texture_slot(target, self.webgl_version()),
459 return
460 );
461 let texture =
462 handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
463
464 if !self
465 .extension_manager
466 .is_get_tex_parameter_name_enabled(param)
467 {
468 return self.webgl_error(InvalidEnum);
469 }
470
471 handle_potential_webgl_error!(self, texture.tex_parameter(param, value), return);
472
473 if target != constants::TEXTURE_2D {
475 return;
476 }
477
478 let target = TexImageTarget::Texture2D;
479 if let Some(info) = texture.image_info_for_target(&target, 0) {
480 self.validate_filterable_texture(
481 &texture,
482 target,
483 0,
484 info.internal_format(),
485 Size2D::new(info.width(), info.height()),
486 info.data_type().unwrap_or(TexDataType::UnsignedByte),
487 );
488 }
489 }
490
491 fn vertex_attrib(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
492 if indx >= self.limits.max_vertex_attribs {
493 return self.webgl_error(InvalidValue);
494 }
495
496 match self.webgl_version() {
497 WebGLVersion::WebGL1 => self
498 .current_vao()
499 .set_vertex_attrib_type(indx, constants::FLOAT),
500 WebGLVersion::WebGL2 => self
501 .current_vao_webgl2()
502 .set_vertex_attrib_type(indx, constants::FLOAT),
503 };
504 self.current_vertex_attribs.borrow_mut()[indx as usize] = VertexAttrib::Float(x, y, z, w);
505
506 self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w));
507 }
508
509 pub(crate) fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
510 match self.bound_draw_framebuffer.get() {
511 Some(fb) => fb.size(),
512
513 None => Some((self.DrawingBufferWidth(), self.DrawingBufferHeight())),
515 }
516 }
517
518 pub(crate) fn get_texture_packing_alignment(&self) -> u8 {
519 self.texture_packing_alignment.get()
520 }
521
522 pub(crate) fn get_current_unpack_state(
523 &self,
524 premultiplied: Alpha,
525 ) -> (Option<AlphaTreatment>, YAxisTreatment) {
526 let settings = self.texture_unpacking_settings.get();
527 let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
528
529 let alpha_treatment = match (premultiplied, dest_premultiplied) {
530 (Alpha::Premultiplied, false) => Some(AlphaTreatment::Unmultiply),
531 (Alpha::NotPremultiplied, true) => Some(AlphaTreatment::Premultiply),
532 _ => None,
533 };
534
535 let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) {
536 YAxisTreatment::Flipped
537 } else {
538 YAxisTreatment::AsIs
539 };
540
541 (alpha_treatment, y_axis_treatment)
542 }
543
544 fn validate_filterable_texture(
547 &self,
548 texture: &WebGLTexture,
549 target: TexImageTarget,
550 level: u32,
551 internal_format: TexFormat,
552 size: Size2D<u32>,
553 data_type: TexDataType,
554 ) -> bool {
555 if self
556 .extension_manager
557 .is_filterable(data_type.as_gl_constant()) ||
558 !texture.is_using_linear_filtering()
559 {
560 return true;
561 }
562
563 let data_type = TexDataType::UnsignedByte;
566 let expected_byte_length = size.area() * 4;
567 let mut pixels = vec![0u8; expected_byte_length as usize];
568 for rgba8 in pixels.chunks_mut(4) {
569 rgba8[3] = 255u8;
570 }
571
572 self.tex_image_2d(
576 texture,
577 target,
578 data_type,
579 internal_format,
580 internal_format.to_unsized(),
581 level,
582 0,
583 1,
584 size,
585 TexSource::Pixels(TexPixels::new(
586 IpcSharedMemory::from_bytes(&pixels),
587 size,
588 PixelFormat::RGBA8,
589 None,
590 YAxisTreatment::AsIs,
591 )),
592 );
593
594 false
595 }
596
597 fn validate_stencil_actions(&self, action: u32) -> bool {
598 matches!(
599 action,
600 0 | constants::KEEP |
601 constants::REPLACE |
602 constants::INCR |
603 constants::DECR |
604 constants::INVERT |
605 constants::INCR_WRAP |
606 constants::DECR_WRAP
607 )
608 }
609
610 pub(crate) fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> {
611 Ok(Some(match source {
612 TexImageSource::ImageBitmap(bitmap) => {
613 if !bitmap.origin_is_clean() {
614 return Err(Error::Security);
615 }
616
617 let Some(snapshot) = bitmap.bitmap_data().clone() else {
618 return Ok(None);
619 };
620
621 let snapshot = snapshot.as_ipc();
622 let size = snapshot.size().cast();
623 let format = match snapshot.format() {
624 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
625 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
626 };
627
628 TexPixels::new(
635 snapshot.to_ipc_shared_memory(),
636 size,
637 format,
638 None,
639 YAxisTreatment::AsIs,
640 )
641 },
642 TexImageSource::ImageData(image_data) => {
643 let (alpha_treatment, y_axis_treatment) =
644 self.get_current_unpack_state(Alpha::NotPremultiplied);
645
646 TexPixels::new(
647 image_data.to_shared_memory(),
648 image_data.get_size(),
649 PixelFormat::RGBA8,
650 alpha_treatment,
651 y_axis_treatment,
652 )
653 },
654 TexImageSource::HTMLImageElement(image) => {
655 let document = match self.canvas {
656 HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
657 canvas.owner_document()
658 },
659 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(ref _canvas) => {
660 return Ok(None);
662 },
663 };
664 if !image.same_origin(document.origin()) {
665 return Err(Error::Security);
666 }
667
668 let Some(snapshot) = image.get_raster_image_data() else {
672 return Ok(None);
673 };
674
675 let snapshot = snapshot.as_ipc();
676 let size = snapshot.size().cast();
677 let format: PixelFormat = match snapshot.format() {
678 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
679 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
680 };
681
682 let (alpha_treatment, y_axis_treatment) =
683 self.get_current_unpack_state(Alpha::NotPremultiplied);
684
685 TexPixels::new(
686 snapshot.to_ipc_shared_memory(),
687 size,
688 format,
689 alpha_treatment,
690 y_axis_treatment,
691 )
692 },
693 TexImageSource::HTMLCanvasElement(canvas) => {
697 if !canvas.origin_is_clean() {
698 return Err(Error::Security);
699 }
700
701 let Some(snapshot) = canvas.get_image_data() else {
702 return Ok(None);
703 };
704
705 let snapshot = snapshot.as_ipc();
706 let size = snapshot.size().cast();
707 let format = match snapshot.format() {
708 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
709 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
710 };
711
712 let (alpha_treatment, y_axis_treatment) =
713 self.get_current_unpack_state(snapshot.alpha_mode().alpha());
714
715 TexPixels::new(
716 snapshot.to_ipc_shared_memory(),
717 size,
718 format,
719 alpha_treatment,
720 y_axis_treatment,
721 )
722 },
723 TexImageSource::HTMLVideoElement(video) => {
724 if !video.origin_is_clean() {
725 return Err(Error::Security);
726 }
727
728 let Some(snapshot) = video.get_current_frame_data() else {
729 return Ok(None);
730 };
731
732 let snapshot = snapshot.as_ipc();
733 let size = snapshot.size().cast();
734 let format: PixelFormat = match snapshot.format() {
735 SnapshotPixelFormat::RGBA => PixelFormat::RGBA8,
736 SnapshotPixelFormat::BGRA => PixelFormat::BGRA8,
737 };
738
739 let (alpha_treatment, y_axis_treatment) =
740 self.get_current_unpack_state(snapshot.alpha_mode().alpha());
741
742 TexPixels::new(
743 snapshot.to_ipc_shared_memory(),
744 size,
745 format,
746 alpha_treatment,
747 y_axis_treatment,
748 )
749 },
750 }))
751 }
752
753 pub(crate) fn validate_tex_image_2d_data(
755 &self,
756 width: u32,
757 height: u32,
758 format: TexFormat,
759 data_type: TexDataType,
760 unpacking_alignment: u32,
761 data: Option<&ArrayBufferView>,
762 ) -> Result<u32, ()> {
763 let element_size = data_type.element_size();
764 let components_per_element = data_type.components_per_element();
765 let components = format.components();
766
767 let data_type_matches = data.as_ref().is_none_or(|buffer| {
775 Some(data_type.sized_data_type()) ==
776 array_buffer_type_to_sized_type(buffer.get_array_type()) &&
777 data_type.required_webgl_version() <= self.webgl_version()
778 });
779
780 if !data_type_matches {
781 self.webgl_error(InvalidOperation);
782 return Err(());
783 }
784
785 if height == 0 {
787 Ok(0)
788 } else {
789 let cpp = element_size * components / components_per_element;
794 let stride = (width * cpp + unpacking_alignment - 1) & !(unpacking_alignment - 1);
795 Ok(stride * (height - 1) + width * cpp)
796 }
797 }
798
799 #[allow(clippy::too_many_arguments)]
800 pub(crate) fn tex_image_2d(
801 &self,
802 texture: &WebGLTexture,
803 target: TexImageTarget,
804 data_type: TexDataType,
805 internal_format: TexFormat,
806 format: TexFormat,
807 level: u32,
808 _border: u32,
809 unpacking_alignment: u32,
810 size: Size2D<u32>,
811 source: TexSource,
812 ) {
813 handle_potential_webgl_error!(
815 self,
816 texture.initialize(
817 target,
818 size.width,
819 size.height,
820 1,
821 format,
822 level,
823 Some(data_type)
824 )
825 );
826
827 let internal_format = self
828 .extension_manager
829 .get_effective_tex_internal_format(internal_format, data_type.as_gl_constant());
830
831 let effective_data_type = self
832 .extension_manager
833 .effective_type(data_type.as_gl_constant());
834
835 match source {
836 TexSource::Pixels(pixels) => {
837 self.send_command(WebGLCommand::TexImage2D {
839 target: target.as_gl_constant(),
840 level,
841 internal_format,
842 size,
843 format,
844 data_type,
845 effective_data_type,
846 unpacking_alignment,
847 alpha_treatment: pixels.alpha_treatment,
848 y_axis_treatment: pixels.y_axis_treatment,
849 pixel_format: pixels.pixel_format,
850 data: pixels.data.into(),
851 });
852 },
853 TexSource::BufferOffset(offset) => {
854 self.send_command(WebGLCommand::TexImage2DPBO {
855 target: target.as_gl_constant(),
856 level,
857 internal_format,
858 size,
859 format,
860 effective_data_type,
861 unpacking_alignment,
862 offset,
863 });
864 },
865 }
866
867 if let Some(fb) = self.bound_draw_framebuffer.get() {
868 fb.invalidate_texture(texture);
869 }
870 }
871
872 #[allow(clippy::too_many_arguments)]
873 fn tex_sub_image_2d(
874 &self,
875 texture: DomRoot<WebGLTexture>,
876 target: TexImageTarget,
877 level: u32,
878 xoffset: i32,
879 yoffset: i32,
880 format: TexFormat,
881 data_type: TexDataType,
882 unpacking_alignment: u32,
883 pixels: TexPixels,
884 ) {
885 let image_info = match texture.image_info_for_target(&target, level) {
887 Some(info) => info,
888 None => return self.webgl_error(InvalidOperation),
889 };
890
891 if xoffset < 0 ||
896 (xoffset as u32 + pixels.size().width) > image_info.width() ||
897 yoffset < 0 ||
898 (yoffset as u32 + pixels.size().height) > image_info.height()
899 {
900 return self.webgl_error(InvalidValue);
901 }
902
903 debug_assert!(!format.is_sized());
905 if format != image_info.internal_format().to_unsized() {
906 return self.webgl_error(InvalidOperation);
907 }
908
909 if self.webgl_version() == WebGLVersion::WebGL1 &&
911 data_type != image_info.data_type().unwrap()
912 {
913 return self.webgl_error(InvalidOperation);
914 }
915
916 let effective_data_type = self
917 .extension_manager
918 .effective_type(data_type.as_gl_constant());
919
920 self.send_command(WebGLCommand::TexSubImage2D {
922 target: target.as_gl_constant(),
923 level,
924 xoffset,
925 yoffset,
926 size: pixels.size(),
927 format,
928 data_type,
929 effective_data_type,
930 unpacking_alignment,
931 alpha_treatment: pixels.alpha_treatment,
932 y_axis_treatment: pixels.y_axis_treatment,
933 pixel_format: pixels.pixel_format,
934 data: pixels.data.into(),
935 });
936 }
937
938 fn get_gl_extensions(&self) -> String {
939 let (sender, receiver) = webgl_channel().unwrap();
940 self.send_command(WebGLCommand::GetExtensions(sender));
941 receiver.recv().unwrap()
942 }
943
944 pub(crate) fn layout_handle(&self) -> Option<ImageKey> {
945 Some(self.webrender_image)
946 }
947
948 pub(crate) fn draw_arrays_instanced(
950 &self,
951 mode: u32,
952 first: i32,
953 count: i32,
954 primcount: i32,
955 ) -> WebGLResult<()> {
956 match mode {
957 constants::POINTS |
958 constants::LINE_STRIP |
959 constants::LINE_LOOP |
960 constants::LINES |
961 constants::TRIANGLE_STRIP |
962 constants::TRIANGLE_FAN |
963 constants::TRIANGLES => {},
964 _ => {
965 return Err(InvalidEnum);
966 },
967 }
968 if first < 0 || count < 0 || primcount < 0 {
969 return Err(InvalidValue);
970 }
971
972 let current_program = self.current_program.get().ok_or(InvalidOperation)?;
973
974 let required_len = if count > 0 {
975 first
976 .checked_add(count)
977 .map(|len| len as u32)
978 .ok_or(InvalidOperation)?
979 } else {
980 0
981 };
982
983 match self.webgl_version() {
984 WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
985 required_len,
986 primcount as u32,
987 ¤t_program.active_attribs(),
988 )?,
989 WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
990 required_len,
991 primcount as u32,
992 ¤t_program.active_attribs(),
993 )?,
994 };
995
996 self.validate_framebuffer()?;
997
998 if count == 0 || primcount == 0 {
999 return Ok(());
1000 }
1001
1002 self.send_command(if primcount == 1 {
1003 WebGLCommand::DrawArrays { mode, first, count }
1004 } else {
1005 WebGLCommand::DrawArraysInstanced {
1006 mode,
1007 first,
1008 count,
1009 primcount,
1010 }
1011 });
1012 self.mark_as_dirty();
1013 Ok(())
1014 }
1015
1016 pub(crate) fn draw_elements_instanced(
1018 &self,
1019 mode: u32,
1020 count: i32,
1021 type_: u32,
1022 offset: i64,
1023 primcount: i32,
1024 ) -> WebGLResult<()> {
1025 match mode {
1026 constants::POINTS |
1027 constants::LINE_STRIP |
1028 constants::LINE_LOOP |
1029 constants::LINES |
1030 constants::TRIANGLE_STRIP |
1031 constants::TRIANGLE_FAN |
1032 constants::TRIANGLES => {},
1033 _ => {
1034 return Err(InvalidEnum);
1035 },
1036 }
1037 if count < 0 || offset < 0 || primcount < 0 {
1038 return Err(InvalidValue);
1039 }
1040 let type_size = match type_ {
1041 constants::UNSIGNED_BYTE => 1,
1042 constants::UNSIGNED_SHORT => 2,
1043 constants::UNSIGNED_INT => match self.webgl_version() {
1044 WebGLVersion::WebGL1 if self.extension_manager.is_element_index_uint_enabled() => 4,
1045 WebGLVersion::WebGL2 => 4,
1046 _ => return Err(InvalidEnum),
1047 },
1048 _ => return Err(InvalidEnum),
1049 };
1050 if offset % type_size != 0 {
1051 return Err(InvalidOperation);
1052 }
1053
1054 let current_program = self.current_program.get().ok_or(InvalidOperation)?;
1055 let array_buffer = match self.webgl_version() {
1056 WebGLVersion::WebGL1 => self.current_vao().element_array_buffer().get(),
1057 WebGLVersion::WebGL2 => self.current_vao_webgl2().element_array_buffer().get(),
1058 }
1059 .ok_or(InvalidOperation)?;
1060
1061 if count > 0 && primcount > 0 {
1062 let val = offset as u64 + (count as u64 * type_size as u64);
1064 if val > array_buffer.capacity() as u64 {
1065 return Err(InvalidOperation);
1066 }
1067 }
1068
1069 match self.webgl_version() {
1071 WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
1072 0,
1073 primcount as u32,
1074 ¤t_program.active_attribs(),
1075 )?,
1076 WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
1077 0,
1078 primcount as u32,
1079 ¤t_program.active_attribs(),
1080 )?,
1081 };
1082
1083 self.validate_framebuffer()?;
1084
1085 if count == 0 || primcount == 0 {
1086 return Ok(());
1087 }
1088
1089 let offset = offset as u32;
1090 self.send_command(if primcount == 1 {
1091 WebGLCommand::DrawElements {
1092 mode,
1093 count,
1094 type_,
1095 offset,
1096 }
1097 } else {
1098 WebGLCommand::DrawElementsInstanced {
1099 mode,
1100 count,
1101 type_,
1102 offset,
1103 primcount,
1104 }
1105 });
1106 self.mark_as_dirty();
1107 Ok(())
1108 }
1109
1110 pub(crate) fn vertex_attrib_divisor(&self, index: u32, divisor: u32) {
1111 if index >= self.limits.max_vertex_attribs {
1112 return self.webgl_error(InvalidValue);
1113 }
1114
1115 match self.webgl_version() {
1116 WebGLVersion::WebGL1 => self.current_vao().vertex_attrib_divisor(index, divisor),
1117 WebGLVersion::WebGL2 => self
1118 .current_vao_webgl2()
1119 .vertex_attrib_divisor(index, divisor),
1120 };
1121 self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
1122 }
1123
1124 pub(crate) fn array_buffer(&self) -> Option<DomRoot<WebGLBuffer>> {
1125 self.bound_buffer_array.get()
1126 }
1127
1128 pub(crate) fn array_buffer_slot(&self) -> &MutNullableDom<WebGLBuffer> {
1129 &self.bound_buffer_array
1130 }
1131
1132 pub(crate) fn bound_buffer(&self, target: u32) -> WebGLResult<Option<DomRoot<WebGLBuffer>>> {
1133 match target {
1134 constants::ARRAY_BUFFER => Ok(self.bound_buffer_array.get()),
1135 constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
1136 _ => Err(WebGLError::InvalidEnum),
1137 }
1138 }
1139
1140 pub(crate) fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
1141 match usage {
1142 constants::STREAM_DRAW | constants::STATIC_DRAW | constants::DYNAMIC_DRAW => Ok(usage),
1143 _ => Err(WebGLError::InvalidEnum),
1144 }
1145 }
1146
1147 pub(crate) fn create_vertex_array(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> {
1148 let (sender, receiver) = webgl_channel().unwrap();
1149 self.send_command(WebGLCommand::CreateVertexArray(sender));
1150 receiver
1151 .recv()
1152 .unwrap()
1153 .map(|id| WebGLVertexArrayObjectOES::new(self, Some(id), CanGc::note()))
1154 }
1155
1156 pub(crate) fn create_vertex_array_webgl2(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
1157 let (sender, receiver) = webgl_channel().unwrap();
1158 self.send_command(WebGLCommand::CreateVertexArray(sender));
1159 receiver
1160 .recv()
1161 .unwrap()
1162 .map(|id| WebGLVertexArrayObject::new(self, Some(id), CanGc::note()))
1163 }
1164
1165 pub(crate) fn delete_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
1166 if let Some(vao) = vao {
1167 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1168 assert!(vao.id().is_some());
1170 if vao.is_deleted() {
1171 return;
1172 }
1173 if vao == &*self.current_vao() {
1174 self.current_vao.set(None);
1177 self.send_command(WebGLCommand::BindVertexArray(None));
1178 }
1179 vao.delete(Operation::Infallible);
1180 }
1181 }
1182
1183 pub(crate) fn delete_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
1184 if let Some(vao) = vao {
1185 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1186 assert!(vao.id().is_some());
1188 if vao.is_deleted() {
1189 return;
1190 }
1191 if vao == &*self.current_vao_webgl2() {
1192 self.current_vao_webgl2.set(None);
1195 self.send_command(WebGLCommand::BindVertexArray(None));
1196 }
1197 vao.delete(Operation::Infallible);
1198 }
1199 }
1200
1201 pub(crate) fn is_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
1202 vao.is_some_and(|vao| {
1203 assert!(vao.id().is_some());
1205 self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
1206 })
1207 }
1208
1209 pub(crate) fn is_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) -> bool {
1210 vao.is_some_and(|vao| {
1211 assert!(vao.id().is_some());
1213 self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
1214 })
1215 }
1216
1217 pub(crate) fn bind_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
1218 if let Some(vao) = vao {
1219 assert!(vao.id().is_some());
1221 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1222 if vao.is_deleted() {
1223 return self.webgl_error(InvalidOperation);
1224 }
1225 vao.set_ever_bound();
1226 }
1227 self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
1228 self.current_vao.set(vao);
1231 }
1232
1233 pub(crate) fn bind_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
1234 if let Some(vao) = vao {
1235 assert!(vao.id().is_some());
1237 handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
1238 if vao.is_deleted() {
1239 return self.webgl_error(InvalidOperation);
1240 }
1241 vao.set_ever_bound();
1242 }
1243 self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
1244 self.current_vao_webgl2.set(vao);
1247 }
1248
1249 fn validate_blend_mode(&self, mode: u32) -> WebGLResult<()> {
1250 match mode {
1251 constants::FUNC_ADD | constants::FUNC_SUBTRACT | constants::FUNC_REVERSE_SUBTRACT => {
1252 Ok(())
1253 },
1254 EXTBlendMinmaxConstants::MIN_EXT | EXTBlendMinmaxConstants::MAX_EXT
1255 if self.extension_manager.is_blend_minmax_enabled() =>
1256 {
1257 Ok(())
1258 },
1259 _ => Err(InvalidEnum),
1260 }
1261 }
1262
1263 pub(crate) fn initialize_framebuffer(&self, clear_bits: u32) {
1264 if clear_bits == 0 {
1265 return;
1266 }
1267 self.send_command(WebGLCommand::InitializeFramebuffer {
1268 color: clear_bits & constants::COLOR_BUFFER_BIT != 0,
1269 depth: clear_bits & constants::DEPTH_BUFFER_BIT != 0,
1270 stencil: clear_bits & constants::STENCIL_BUFFER_BIT != 0,
1271 });
1272 }
1273
1274 pub(crate) fn extension_manager(&self) -> &WebGLExtensions {
1275 &self.extension_manager
1276 }
1277
1278 #[allow(unsafe_code)]
1279 pub(crate) fn buffer_data(
1280 &self,
1281 target: u32,
1282 data: Option<ArrayBufferViewOrArrayBuffer>,
1283 usage: u32,
1284 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1285 ) {
1286 let data = handle_potential_webgl_error!(self, data.ok_or(InvalidValue), return);
1287 let bound_buffer =
1288 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1289
1290 let data = unsafe {
1291 match data {
1293 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
1294 ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
1295 }
1296 };
1297 handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
1298 }
1299
1300 pub(crate) fn buffer_data_(
1301 &self,
1302 target: u32,
1303 size: i64,
1304 usage: u32,
1305 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1306 ) {
1307 let bound_buffer =
1308 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1309
1310 if size < 0 {
1311 return self.webgl_error(InvalidValue);
1312 }
1313
1314 let data = vec![0u8; size as usize];
1317 handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data, usage));
1318 }
1319
1320 #[allow(unsafe_code)]
1321 pub(crate) fn buffer_sub_data(
1322 &self,
1323 target: u32,
1324 offset: i64,
1325 data: ArrayBufferViewOrArrayBuffer,
1326 bound_buffer: Option<DomRoot<WebGLBuffer>>,
1327 ) {
1328 let bound_buffer =
1329 handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
1330
1331 if offset < 0 {
1332 return self.webgl_error(InvalidValue);
1333 }
1334
1335 let data = unsafe {
1336 match data {
1338 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
1339 ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
1340 }
1341 };
1342 if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 {
1343 return self.webgl_error(InvalidValue);
1344 }
1345 let (sender, receiver) = ipc::bytes_channel().unwrap();
1346 self.send_command(WebGLCommand::BufferSubData(
1347 target,
1348 offset as isize,
1349 receiver,
1350 ));
1351 sender.send(data).unwrap();
1352 }
1353
1354 pub(crate) fn bind_buffer_maybe(
1355 &self,
1356 slot: &MutNullableDom<WebGLBuffer>,
1357 target: u32,
1358 buffer: Option<&WebGLBuffer>,
1359 ) {
1360 if let Some(buffer) = buffer {
1361 handle_potential_webgl_error!(self, self.validate_ownership(buffer), return);
1362
1363 if buffer.is_marked_for_deletion() {
1364 return self.webgl_error(InvalidOperation);
1365 }
1366 handle_potential_webgl_error!(self, buffer.set_target_maybe(target), return);
1367 buffer.increment_attached_counter();
1368 }
1369
1370 self.send_command(WebGLCommand::BindBuffer(target, buffer.map(|b| b.id())));
1371 if let Some(old) = slot.get() {
1372 old.decrement_attached_counter(Operation::Infallible);
1373 }
1374
1375 slot.set(buffer);
1376 }
1377
1378 pub(crate) fn current_program(&self) -> Option<DomRoot<WebGLProgram>> {
1379 self.current_program.get()
1380 }
1381
1382 pub(crate) fn uniform_check_program(
1383 &self,
1384 program: &WebGLProgram,
1385 location: &WebGLUniformLocation,
1386 ) -> WebGLResult<()> {
1387 self.validate_ownership(program)?;
1388
1389 if program.is_deleted() ||
1390 !program.is_linked() ||
1391 self.context_id() != location.context_id() ||
1392 program.id() != location.program_id() ||
1393 program.link_generation() != location.link_generation()
1394 {
1395 return Err(InvalidOperation);
1396 }
1397
1398 Ok(())
1399 }
1400
1401 fn uniform_vec_section_int(
1402 &self,
1403 vec: Int32ArrayOrLongSequence,
1404 offset: u32,
1405 length: u32,
1406 uniform_size: usize,
1407 uniform_location: &WebGLUniformLocation,
1408 ) -> WebGLResult<Vec<i32>> {
1409 let vec = match vec {
1410 Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
1411 Int32ArrayOrLongSequence::LongSequence(v) => v,
1412 };
1413 self.uniform_vec_section::<i32>(vec, offset, length, uniform_size, uniform_location)
1414 }
1415
1416 fn uniform_vec_section_float(
1417 &self,
1418 vec: Float32ArrayOrUnrestrictedFloatSequence,
1419 offset: u32,
1420 length: u32,
1421 uniform_size: usize,
1422 uniform_location: &WebGLUniformLocation,
1423 ) -> WebGLResult<Vec<f32>> {
1424 let vec = match vec {
1425 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
1426 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
1427 };
1428 self.uniform_vec_section::<f32>(vec, offset, length, uniform_size, uniform_location)
1429 }
1430
1431 pub(crate) fn uniform_vec_section<T: Clone>(
1432 &self,
1433 vec: Vec<T>,
1434 offset: u32,
1435 length: u32,
1436 uniform_size: usize,
1437 uniform_location: &WebGLUniformLocation,
1438 ) -> WebGLResult<Vec<T>> {
1439 let offset = offset as usize;
1440 if offset > vec.len() {
1441 return Err(InvalidValue);
1442 }
1443
1444 let length = if length > 0 {
1445 length as usize
1446 } else {
1447 vec.len() - offset
1448 };
1449 if offset + length > vec.len() {
1450 return Err(InvalidValue);
1451 }
1452
1453 let vec = if offset == 0 && length == vec.len() {
1454 vec
1455 } else {
1456 vec[offset..offset + length].to_vec()
1457 };
1458
1459 if vec.len() < uniform_size || vec.len() % uniform_size != 0 {
1460 return Err(InvalidValue);
1461 }
1462 if uniform_location.size().is_none() && vec.len() != uniform_size {
1463 return Err(InvalidOperation);
1464 }
1465
1466 Ok(vec)
1467 }
1468
1469 pub(crate) fn uniform_matrix_section(
1470 &self,
1471 vec: Float32ArrayOrUnrestrictedFloatSequence,
1472 offset: u32,
1473 length: u32,
1474 transpose: bool,
1475 uniform_size: usize,
1476 uniform_location: &WebGLUniformLocation,
1477 ) -> WebGLResult<Vec<f32>> {
1478 let vec = match vec {
1479 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
1480 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
1481 };
1482 if transpose {
1483 return Err(InvalidValue);
1484 }
1485 self.uniform_vec_section::<f32>(vec, offset, length, uniform_size, uniform_location)
1486 }
1487
1488 pub(crate) fn get_draw_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> {
1489 &self.bound_draw_framebuffer
1490 }
1491
1492 pub(crate) fn get_read_framebuffer_slot(&self) -> &MutNullableDom<WebGLFramebuffer> {
1493 &self.bound_read_framebuffer
1494 }
1495
1496 pub(crate) fn validate_new_framebuffer_binding(
1497 &self,
1498 framebuffer: Option<&WebGLFramebuffer>,
1499 ) -> WebGLResult<()> {
1500 if let Some(fb) = framebuffer {
1501 self.validate_ownership(fb)?;
1502 if fb.is_deleted() {
1503 return Err(InvalidOperation);
1509 }
1510 }
1511 Ok(())
1512 }
1513
1514 pub(crate) fn bind_framebuffer_to(
1515 &self,
1516 target: u32,
1517 framebuffer: Option<&WebGLFramebuffer>,
1518 slot: &MutNullableDom<WebGLFramebuffer>,
1519 ) {
1520 match framebuffer {
1521 Some(framebuffer) => framebuffer.bind(target),
1522 None => {
1523 let cmd =
1525 WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Default);
1526 self.send_command(cmd);
1527 },
1528 }
1529 slot.set(framebuffer);
1530 }
1531
1532 pub(crate) fn renderbuffer_storage(
1533 &self,
1534 target: u32,
1535 samples: i32,
1536 internal_format: u32,
1537 width: i32,
1538 height: i32,
1539 ) {
1540 if target != constants::RENDERBUFFER {
1541 return self.webgl_error(InvalidEnum);
1542 }
1543
1544 let max = self.limits.max_renderbuffer_size;
1545
1546 if samples < 0 || width < 0 || width as u32 > max || height < 0 || height as u32 > max {
1547 return self.webgl_error(InvalidValue);
1548 }
1549
1550 let rb = handle_potential_webgl_error!(
1551 self,
1552 self.bound_renderbuffer.get().ok_or(InvalidOperation),
1553 return
1554 );
1555 handle_potential_webgl_error!(
1556 self,
1557 rb.storage(self.api_type, samples, internal_format, width, height)
1558 );
1559 if let Some(fb) = self.bound_draw_framebuffer.get() {
1560 fb.invalidate_renderbuffer(&rb);
1561 }
1562
1563 }
1565
1566 pub(crate) fn valid_color_attachment_enum(&self, attachment: u32) -> bool {
1567 let last_slot = constants::COLOR_ATTACHMENT0 + self.limits().max_color_attachments - 1;
1568 constants::COLOR_ATTACHMENT0 <= attachment && attachment <= last_slot
1569 }
1570
1571 #[allow(clippy::too_many_arguments)]
1572 pub(crate) fn compressed_tex_image_2d(
1573 &self,
1574 target: u32,
1575 level: i32,
1576 internal_format: u32,
1577 width: i32,
1578 height: i32,
1579 border: i32,
1580 data: &[u8],
1581 ) {
1582 let validator = CompressedTexImage2DValidator::new(
1583 self,
1584 target,
1585 level,
1586 width,
1587 height,
1588 border,
1589 internal_format,
1590 data.len(),
1591 );
1592 let CommonCompressedTexImage2DValidatorResult {
1593 texture,
1594 target,
1595 level,
1596 width,
1597 height,
1598 compression,
1599 } = match validator.validate() {
1600 Ok(result) => result,
1601 Err(_) => return,
1602 };
1603
1604 if texture.is_immutable() {
1605 return self.webgl_error(InvalidOperation);
1606 }
1607
1608 let size = Size2D::new(width, height);
1609 let data = IpcSharedMemory::from_bytes(data);
1610
1611 handle_potential_webgl_error!(
1612 self,
1613 texture.initialize(
1614 target,
1615 size.width,
1616 size.height,
1617 1,
1618 compression.format,
1619 level,
1620 Some(TexDataType::UnsignedByte)
1621 )
1622 );
1623
1624 self.send_command(WebGLCommand::CompressedTexImage2D {
1625 target: target.as_gl_constant(),
1626 level,
1627 internal_format,
1628 size: Size2D::new(width, height),
1629 data: data.into(),
1630 });
1631
1632 if let Some(fb) = self.bound_draw_framebuffer.get() {
1633 fb.invalidate_texture(&texture);
1634 }
1635 }
1636
1637 #[allow(clippy::too_many_arguments)]
1638 pub(crate) fn compressed_tex_sub_image_2d(
1639 &self,
1640 target: u32,
1641 level: i32,
1642 xoffset: i32,
1643 yoffset: i32,
1644 width: i32,
1645 height: i32,
1646 format: u32,
1647 data: &[u8],
1648 ) {
1649 let validator = CompressedTexSubImage2DValidator::new(
1650 self,
1651 target,
1652 level,
1653 xoffset,
1654 yoffset,
1655 width,
1656 height,
1657 format,
1658 data.len(),
1659 );
1660 let CommonCompressedTexImage2DValidatorResult {
1661 texture: _,
1662 target,
1663 level,
1664 width,
1665 height,
1666 ..
1667 } = match validator.validate() {
1668 Ok(result) => result,
1669 Err(_) => return,
1670 };
1671
1672 let data = IpcSharedMemory::from_bytes(data);
1673
1674 self.send_command(WebGLCommand::CompressedTexSubImage2D {
1675 target: target.as_gl_constant(),
1676 level: level as i32,
1677 xoffset,
1678 yoffset,
1679 size: Size2D::new(width, height),
1680 format,
1681 data: data.into(),
1682 });
1683 }
1684
1685 pub(crate) fn uniform1iv(
1686 &self,
1687 location: Option<&WebGLUniformLocation>,
1688 val: Int32ArrayOrLongSequence,
1689 src_offset: u32,
1690 src_length: u32,
1691 ) {
1692 self.with_location(location, |location| {
1693 match location.type_() {
1694 constants::BOOL |
1695 constants::INT |
1696 constants::SAMPLER_2D |
1697 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
1698 WebGL2RenderingContextConstants::SAMPLER_3D |
1699 constants::SAMPLER_CUBE => {},
1700 _ => return Err(InvalidOperation),
1701 }
1702
1703 let val = self.uniform_vec_section_int(val, src_offset, src_length, 1, location)?;
1704
1705 match location.type_() {
1706 constants::SAMPLER_2D |
1707 constants::SAMPLER_CUBE |
1708 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
1709 WebGL2RenderingContextConstants::SAMPLER_3D => {
1710 for &v in val
1711 .iter()
1712 .take(cmp::min(location.size().unwrap_or(1) as usize, val.len()))
1713 {
1714 if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units {
1715 return Err(InvalidValue);
1716 }
1717 }
1718 },
1719 _ => {},
1720 }
1721 self.send_command(WebGLCommand::Uniform1iv(location.id(), val));
1722 Ok(())
1723 });
1724 }
1725
1726 pub(crate) fn uniform1fv(
1727 &self,
1728 location: Option<&WebGLUniformLocation>,
1729 val: Float32ArrayOrUnrestrictedFloatSequence,
1730 src_offset: u32,
1731 src_length: u32,
1732 ) {
1733 self.with_location(location, |location| {
1734 match location.type_() {
1735 constants::BOOL | constants::FLOAT => {},
1736 _ => return Err(InvalidOperation),
1737 }
1738 let val = self.uniform_vec_section_float(val, src_offset, src_length, 1, location)?;
1739 self.send_command(WebGLCommand::Uniform1fv(location.id(), val));
1740 Ok(())
1741 });
1742 }
1743
1744 pub(crate) fn uniform2fv(
1745 &self,
1746 location: Option<&WebGLUniformLocation>,
1747 val: Float32ArrayOrUnrestrictedFloatSequence,
1748 src_offset: u32,
1749 src_length: u32,
1750 ) {
1751 self.with_location(location, |location| {
1752 match location.type_() {
1753 constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
1754 _ => return Err(InvalidOperation),
1755 }
1756 let val = self.uniform_vec_section_float(val, src_offset, src_length, 2, location)?;
1757 self.send_command(WebGLCommand::Uniform2fv(location.id(), val));
1758 Ok(())
1759 });
1760 }
1761
1762 pub(crate) fn uniform2iv(
1763 &self,
1764 location: Option<&WebGLUniformLocation>,
1765 val: Int32ArrayOrLongSequence,
1766 src_offset: u32,
1767 src_length: u32,
1768 ) {
1769 self.with_location(location, |location| {
1770 match location.type_() {
1771 constants::BOOL_VEC2 | constants::INT_VEC2 => {},
1772 _ => return Err(InvalidOperation),
1773 }
1774 let val = self.uniform_vec_section_int(val, src_offset, src_length, 2, location)?;
1775 self.send_command(WebGLCommand::Uniform2iv(location.id(), val));
1776 Ok(())
1777 });
1778 }
1779
1780 pub(crate) fn uniform3fv(
1781 &self,
1782 location: Option<&WebGLUniformLocation>,
1783 val: Float32ArrayOrUnrestrictedFloatSequence,
1784 src_offset: u32,
1785 src_length: u32,
1786 ) {
1787 self.with_location(location, |location| {
1788 match location.type_() {
1789 constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
1790 _ => return Err(InvalidOperation),
1791 }
1792 let val = self.uniform_vec_section_float(val, src_offset, src_length, 3, location)?;
1793 self.send_command(WebGLCommand::Uniform3fv(location.id(), val));
1794 Ok(())
1795 });
1796 }
1797
1798 pub(crate) fn uniform3iv(
1799 &self,
1800 location: Option<&WebGLUniformLocation>,
1801 val: Int32ArrayOrLongSequence,
1802 src_offset: u32,
1803 src_length: u32,
1804 ) {
1805 self.with_location(location, |location| {
1806 match location.type_() {
1807 constants::BOOL_VEC3 | constants::INT_VEC3 => {},
1808 _ => return Err(InvalidOperation),
1809 }
1810 let val = self.uniform_vec_section_int(val, src_offset, src_length, 3, location)?;
1811 self.send_command(WebGLCommand::Uniform3iv(location.id(), val));
1812 Ok(())
1813 });
1814 }
1815
1816 pub(crate) fn uniform4iv(
1817 &self,
1818 location: Option<&WebGLUniformLocation>,
1819 val: Int32ArrayOrLongSequence,
1820 src_offset: u32,
1821 src_length: u32,
1822 ) {
1823 self.with_location(location, |location| {
1824 match location.type_() {
1825 constants::BOOL_VEC4 | constants::INT_VEC4 => {},
1826 _ => return Err(InvalidOperation),
1827 }
1828 let val = self.uniform_vec_section_int(val, src_offset, src_length, 4, location)?;
1829 self.send_command(WebGLCommand::Uniform4iv(location.id(), val));
1830 Ok(())
1831 });
1832 }
1833
1834 pub(crate) fn uniform4fv(
1835 &self,
1836 location: Option<&WebGLUniformLocation>,
1837 val: Float32ArrayOrUnrestrictedFloatSequence,
1838 src_offset: u32,
1839 src_length: u32,
1840 ) {
1841 self.with_location(location, |location| {
1842 match location.type_() {
1843 constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
1844 _ => return Err(InvalidOperation),
1845 }
1846 let val = self.uniform_vec_section_float(val, src_offset, src_length, 4, location)?;
1847 self.send_command(WebGLCommand::Uniform4fv(location.id(), val));
1848 Ok(())
1849 });
1850 }
1851
1852 pub(crate) fn uniform_matrix_2fv(
1853 &self,
1854 location: Option<&WebGLUniformLocation>,
1855 transpose: bool,
1856 val: Float32ArrayOrUnrestrictedFloatSequence,
1857 src_offset: u32,
1858 src_length: u32,
1859 ) {
1860 self.with_location(location, |location| {
1861 match location.type_() {
1862 constants::FLOAT_MAT2 => {},
1863 _ => return Err(InvalidOperation),
1864 }
1865 let val =
1866 self.uniform_matrix_section(val, src_offset, src_length, transpose, 4, location)?;
1867 self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val));
1868 Ok(())
1869 });
1870 }
1871
1872 pub(crate) fn uniform_matrix_3fv(
1873 &self,
1874 location: Option<&WebGLUniformLocation>,
1875 transpose: bool,
1876 val: Float32ArrayOrUnrestrictedFloatSequence,
1877 src_offset: u32,
1878 src_length: u32,
1879 ) {
1880 self.with_location(location, |location| {
1881 match location.type_() {
1882 constants::FLOAT_MAT3 => {},
1883 _ => return Err(InvalidOperation),
1884 }
1885 let val =
1886 self.uniform_matrix_section(val, src_offset, src_length, transpose, 9, location)?;
1887 self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val));
1888 Ok(())
1889 });
1890 }
1891
1892 pub(crate) fn uniform_matrix_4fv(
1893 &self,
1894 location: Option<&WebGLUniformLocation>,
1895 transpose: bool,
1896 val: Float32ArrayOrUnrestrictedFloatSequence,
1897 src_offset: u32,
1898 src_length: u32,
1899 ) {
1900 self.with_location(location, |location| {
1901 match location.type_() {
1902 constants::FLOAT_MAT4 => {},
1903 _ => return Err(InvalidOperation),
1904 }
1905 let val =
1906 self.uniform_matrix_section(val, src_offset, src_length, transpose, 16, location)?;
1907 self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val));
1908 Ok(())
1909 });
1910 }
1911
1912 pub(crate) fn get_buffer_param(
1913 &self,
1914 buffer: Option<DomRoot<WebGLBuffer>>,
1915 parameter: u32,
1916 mut retval: MutableHandleValue,
1917 ) {
1918 let buffer = handle_potential_webgl_error!(
1919 self,
1920 buffer.ok_or(InvalidOperation),
1921 return retval.set(NullValue())
1922 );
1923
1924 retval.set(match parameter {
1925 constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32),
1926 constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32),
1927 _ => {
1928 self.webgl_error(InvalidEnum);
1929 NullValue()
1930 },
1931 })
1932 }
1933}
1934
1935impl CanvasContext for WebGLRenderingContext {
1936 type ID = WebGLContextId;
1937
1938 fn context_id(&self) -> Self::ID {
1939 self.webgl_sender.context_id()
1940 }
1941
1942 fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
1943 Some(RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas))
1944 }
1945
1946 fn resize(&self) {
1947 let size = self.size().cast();
1948 let (sender, receiver) = webgl_channel().unwrap();
1949 self.webgl_sender.send_resize(size, sender).unwrap();
1950 self.size.set(size);
1953
1954 if let Err(msg) = receiver.recv().unwrap() {
1955 error!("Error resizing WebGLContext: {}", msg);
1956 return;
1957 };
1958
1959 let color = self.current_clear_color.get();
1962 self.send_command(WebGLCommand::ClearColor(color.0, color.1, color.2, color.3));
1963
1964 let rect = self.current_scissor.get();
1969 self.send_command(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3));
1970
1971 if let Some(texture) = self
1976 .textures
1977 .active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
1978 .unwrap()
1979 .get()
1980 {
1981 self.send_command(WebGLCommand::BindTexture(
1982 constants::TEXTURE_2D,
1983 Some(texture.id()),
1984 ));
1985 }
1986
1987 if let Some(fbo) = self.bound_draw_framebuffer.get() {
1991 let id = WebGLFramebufferBindingRequest::Explicit(fbo.id());
1992 self.send_command(WebGLCommand::BindFramebuffer(constants::FRAMEBUFFER, id));
1993 }
1994 }
1995
1996 fn reset_bitmap(&self) {
1997 warn!("The WebGLRenderingContext 'reset_bitmap' is not implemented yet");
1998 }
1999
2000 fn get_image_data(&self) -> Option<Snapshot> {
2007 handle_potential_webgl_error!(self, self.validate_framebuffer(), return None);
2008 let mut size = self.size().cast();
2009
2010 let (fb_width, fb_height) = handle_potential_webgl_error!(
2011 self,
2012 self.get_current_framebuffer_size().ok_or(InvalidOperation),
2013 return None
2014 );
2015 size.width = cmp::min(size.width, fb_width as u32);
2016 size.height = cmp::min(size.height, fb_height as u32);
2017
2018 let (sender, receiver) = ipc::channel().unwrap();
2019 self.send_command(WebGLCommand::ReadPixels(
2020 Rect::from_size(size),
2021 constants::RGBA,
2022 constants::UNSIGNED_BYTE,
2023 sender,
2024 ));
2025 let (data, alpha_mode) = receiver.recv().unwrap();
2026 Some(Snapshot::from_vec(
2027 size.cast(),
2028 SnapshotPixelFormat::RGBA,
2029 alpha_mode,
2030 data.to_vec(),
2031 ))
2032 }
2033
2034 fn mark_as_dirty(&self) {
2035 if self.bound_draw_framebuffer.get().is_some() {
2037 return;
2038 }
2039
2040 if self.global().as_window().in_immersive_xr_session() {
2043 return;
2044 }
2045
2046 match self.canvas {
2047 HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
2048 canvas.upcast::<Node>().dirty(NodeDamage::Other);
2049 canvas.owner_document().add_dirty_webgl_canvas(self);
2050 },
2051 HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(_) => {},
2052 }
2053 }
2054
2055 fn image_key(&self) -> Option<ImageKey> {
2056 Some(self.webrender_image)
2057 }
2058}
2059
2060#[cfg(not(feature = "webgl_backtrace"))]
2061#[inline]
2062pub(crate) fn capture_webgl_backtrace() -> WebGLCommandBacktrace {
2063 WebGLCommandBacktrace {}
2064}
2065
2066#[cfg(feature = "webgl_backtrace")]
2067#[cfg_attr(feature = "webgl_backtrace", allow(unsafe_code))]
2068pub(crate) fn capture_webgl_backtrace() -> WebGLCommandBacktrace {
2069 let bt = Backtrace::new();
2070 unsafe {
2071 capture_stack!(in(*GlobalScope::get_cx()) let stack);
2072 WebGLCommandBacktrace {
2073 backtrace: format!("{:?}", bt),
2074 js_backtrace: stack.and_then(|s| s.as_string(None, js::jsapi::StackFormat::Default)),
2075 }
2076 }
2077}
2078
2079impl Drop for WebGLRenderingContext {
2080 fn drop(&mut self) {
2081 let _ = self.webgl_sender.send_remove();
2082 }
2083}
2084
2085impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContext {
2086 fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
2088 RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas)
2089 }
2090
2091 fn Flush(&self) {
2093 self.send_command(WebGLCommand::Flush);
2094 }
2095
2096 fn Finish(&self) {
2098 let (sender, receiver) = webgl_channel().unwrap();
2099 self.send_command(WebGLCommand::Finish(sender));
2100 receiver.recv().unwrap()
2101 }
2102
2103 fn DrawingBufferWidth(&self) -> i32 {
2105 let (sender, receiver) = webgl_channel().unwrap();
2106 self.send_command(WebGLCommand::DrawingBufferWidth(sender));
2107 receiver.recv().unwrap()
2108 }
2109
2110 fn DrawingBufferHeight(&self) -> i32 {
2112 let (sender, receiver) = webgl_channel().unwrap();
2113 self.send_command(WebGLCommand::DrawingBufferHeight(sender));
2114 receiver.recv().unwrap()
2115 }
2116
2117 fn GetBufferParameter(
2119 &self,
2120 _cx: SafeJSContext,
2121 target: u32,
2122 parameter: u32,
2123 mut retval: MutableHandleValue,
2124 ) {
2125 let buffer = handle_potential_webgl_error!(
2126 self,
2127 self.bound_buffer(target),
2128 return retval.set(NullValue())
2129 );
2130 self.get_buffer_param(buffer, parameter, retval)
2131 }
2132
2133 #[allow(unsafe_code)]
2134 fn GetParameter(&self, cx: SafeJSContext, parameter: u32, mut retval: MutableHandleValue) {
2136 if !self
2137 .extension_manager
2138 .is_get_parameter_name_enabled(parameter)
2139 {
2140 self.webgl_error(WebGLError::InvalidEnum);
2141 return retval.set(NullValue());
2142 }
2143
2144 match parameter {
2145 constants::ARRAY_BUFFER_BINDING => {
2146 self.bound_buffer_array.get().safe_to_jsval(cx, retval);
2147 return;
2148 },
2149 constants::CURRENT_PROGRAM => {
2150 self.current_program.get().safe_to_jsval(cx, retval);
2151 return;
2152 },
2153 constants::ELEMENT_ARRAY_BUFFER_BINDING => {
2154 let buffer = self.current_vao().element_array_buffer().get();
2155 buffer.safe_to_jsval(cx, retval);
2156 return;
2157 },
2158 constants::FRAMEBUFFER_BINDING => {
2159 self.bound_draw_framebuffer.get().safe_to_jsval(cx, retval);
2160 return;
2161 },
2162 constants::RENDERBUFFER_BINDING => {
2163 self.bound_renderbuffer.get().safe_to_jsval(cx, retval);
2164 return;
2165 },
2166 constants::TEXTURE_BINDING_2D => {
2167 let texture = self
2168 .textures
2169 .active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
2170 .unwrap()
2171 .get();
2172 texture.safe_to_jsval(cx, retval);
2173 return;
2174 },
2175 WebGL2RenderingContextConstants::TEXTURE_BINDING_2D_ARRAY => {
2176 let texture = self
2177 .textures
2178 .active_texture_slot(
2179 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
2180 self.webgl_version(),
2181 )
2182 .unwrap()
2183 .get();
2184 texture.safe_to_jsval(cx, retval);
2185 return;
2186 },
2187 WebGL2RenderingContextConstants::TEXTURE_BINDING_3D => {
2188 let texture = self
2189 .textures
2190 .active_texture_slot(
2191 WebGL2RenderingContextConstants::TEXTURE_3D,
2192 self.webgl_version(),
2193 )
2194 .unwrap()
2195 .get();
2196 texture.safe_to_jsval(cx, retval);
2197 return;
2198 },
2199 constants::TEXTURE_BINDING_CUBE_MAP => {
2200 let texture = self
2201 .textures
2202 .active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version())
2203 .unwrap()
2204 .get();
2205 texture.safe_to_jsval(cx, retval);
2206 return;
2207 },
2208 OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => {
2209 let vao = self.current_vao.get().filter(|vao| vao.id().is_some());
2210 vao.safe_to_jsval(cx, retval);
2211 return;
2212 },
2213 constants::IMPLEMENTATION_COLOR_READ_FORMAT => {
2219 if self.validate_framebuffer().is_err() {
2220 self.webgl_error(InvalidOperation);
2221 return retval.set(NullValue());
2222 }
2223 return retval.set(Int32Value(constants::RGBA as i32));
2224 },
2225 constants::IMPLEMENTATION_COLOR_READ_TYPE => {
2226 if self.validate_framebuffer().is_err() {
2227 self.webgl_error(InvalidOperation);
2228 return retval.set(NullValue());
2229 }
2230 return retval.set(Int32Value(constants::UNSIGNED_BYTE as i32));
2231 },
2232 constants::COMPRESSED_TEXTURE_FORMATS => unsafe {
2233 let format_ids = self.extension_manager.get_tex_compression_ids();
2234
2235 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2236 Uint32Array::create(*cx, CreateWith::Slice(&format_ids), rval.handle_mut())
2237 .unwrap();
2238 return retval.set(ObjectValue(rval.get()));
2239 },
2240 constants::VERSION => {
2241 "WebGL 1.0".safe_to_jsval(cx, retval);
2242 return;
2243 },
2244 constants::RENDERER | constants::VENDOR => {
2245 "Mozilla/Servo".safe_to_jsval(cx, retval);
2246 return;
2247 },
2248 constants::SHADING_LANGUAGE_VERSION => {
2249 "WebGL GLSL ES 1.0".safe_to_jsval(cx, retval);
2250 return;
2251 },
2252 constants::UNPACK_FLIP_Y_WEBGL => {
2253 let unpack = self.texture_unpacking_settings.get();
2254 retval.set(BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS)));
2255 return;
2256 },
2257 constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => {
2258 let unpack = self.texture_unpacking_settings.get();
2259 retval.set(BooleanValue(
2260 unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA),
2261 ));
2262 return;
2263 },
2264 constants::PACK_ALIGNMENT => {
2265 retval.set(UInt32Value(self.texture_packing_alignment.get() as u32));
2266 return;
2267 },
2268 constants::UNPACK_ALIGNMENT => {
2269 retval.set(UInt32Value(self.texture_unpacking_alignment.get()));
2270 return;
2271 },
2272 constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
2273 let unpack = self.texture_unpacking_settings.get();
2274 retval.set(UInt32Value(
2275 if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) {
2276 constants::BROWSER_DEFAULT_WEBGL
2277 } else {
2278 constants::NONE
2279 },
2280 ));
2281 return;
2282 },
2283 _ => {},
2284 }
2285
2286 let limit = match parameter {
2289 constants::MAX_VERTEX_ATTRIBS => Some(self.limits.max_vertex_attribs),
2290 constants::MAX_TEXTURE_SIZE => Some(self.limits.max_tex_size),
2291 constants::MAX_CUBE_MAP_TEXTURE_SIZE => Some(self.limits.max_cube_map_tex_size),
2292 constants::MAX_COMBINED_TEXTURE_IMAGE_UNITS => {
2293 Some(self.limits.max_combined_texture_image_units)
2294 },
2295 constants::MAX_FRAGMENT_UNIFORM_VECTORS => {
2296 Some(self.limits.max_fragment_uniform_vectors)
2297 },
2298 constants::MAX_RENDERBUFFER_SIZE => Some(self.limits.max_renderbuffer_size),
2299 constants::MAX_TEXTURE_IMAGE_UNITS => Some(self.limits.max_texture_image_units),
2300 constants::MAX_VARYING_VECTORS => Some(self.limits.max_varying_vectors),
2301 constants::MAX_VERTEX_TEXTURE_IMAGE_UNITS => {
2302 Some(self.limits.max_vertex_texture_image_units)
2303 },
2304 constants::MAX_VERTEX_UNIFORM_VECTORS => Some(self.limits.max_vertex_uniform_vectors),
2305 _ => None,
2306 };
2307 if let Some(limit) = limit {
2308 retval.set(UInt32Value(limit));
2309 return;
2310 }
2311
2312 if let Ok(value) = self.capabilities.is_enabled(parameter) {
2313 retval.set(BooleanValue(value));
2314 return;
2315 }
2316
2317 match handle_potential_webgl_error!(
2318 self,
2319 Parameter::from_u32(parameter),
2320 return retval.set(NullValue())
2321 ) {
2322 Parameter::Bool(param) => {
2323 let (sender, receiver) = webgl_channel().unwrap();
2324 self.send_command(WebGLCommand::GetParameterBool(param, sender));
2325 retval.set(BooleanValue(receiver.recv().unwrap()))
2326 },
2327 Parameter::Bool4(param) => {
2328 let (sender, receiver) = webgl_channel().unwrap();
2329 self.send_command(WebGLCommand::GetParameterBool4(param, sender));
2330 receiver.recv().unwrap().safe_to_jsval(cx, retval);
2331 },
2332 Parameter::Int(param) => {
2333 let (sender, receiver) = webgl_channel().unwrap();
2334 self.send_command(WebGLCommand::GetParameterInt(param, sender));
2335 retval.set(Int32Value(receiver.recv().unwrap()))
2336 },
2337 Parameter::Int2(param) => unsafe {
2338 let (sender, receiver) = webgl_channel().unwrap();
2339 self.send_command(WebGLCommand::GetParameterInt2(param, sender));
2340 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2341 Int32Array::create(
2342 *cx,
2343 CreateWith::Slice(&receiver.recv().unwrap()),
2344 rval.handle_mut(),
2345 )
2346 .unwrap();
2347 retval.set(ObjectValue(rval.get()))
2348 },
2349 Parameter::Int4(param) => unsafe {
2350 let (sender, receiver) = webgl_channel().unwrap();
2351 self.send_command(WebGLCommand::GetParameterInt4(param, sender));
2352 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2353 Int32Array::create(
2354 *cx,
2355 CreateWith::Slice(&receiver.recv().unwrap()),
2356 rval.handle_mut(),
2357 )
2358 .unwrap();
2359 retval.set(ObjectValue(rval.get()))
2360 },
2361 Parameter::Float(param) => {
2362 let (sender, receiver) = webgl_channel().unwrap();
2363 self.send_command(WebGLCommand::GetParameterFloat(param, sender));
2364 retval.set(DoubleValue(receiver.recv().unwrap() as f64))
2365 },
2366 Parameter::Float2(param) => unsafe {
2367 let (sender, receiver) = webgl_channel().unwrap();
2368 self.send_command(WebGLCommand::GetParameterFloat2(param, sender));
2369 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2370 Float32Array::create(
2371 *cx,
2372 CreateWith::Slice(&receiver.recv().unwrap()),
2373 rval.handle_mut(),
2374 )
2375 .unwrap();
2376 retval.set(ObjectValue(rval.get()))
2377 },
2378 Parameter::Float4(param) => unsafe {
2379 let (sender, receiver) = webgl_channel().unwrap();
2380 self.send_command(WebGLCommand::GetParameterFloat4(param, sender));
2381 rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
2382 Float32Array::create(
2383 *cx,
2384 CreateWith::Slice(&receiver.recv().unwrap()),
2385 rval.handle_mut(),
2386 )
2387 .unwrap();
2388 retval.set(ObjectValue(rval.get()))
2389 },
2390 }
2391 }
2392
2393 fn GetTexParameter(
2395 &self,
2396 _cx: SafeJSContext,
2397 target: u32,
2398 pname: u32,
2399 mut retval: MutableHandleValue,
2400 ) {
2401 let texture_slot = handle_potential_webgl_error!(
2402 self,
2403 self.textures
2404 .active_texture_slot(target, self.webgl_version()),
2405 return retval.set(NullValue())
2406 );
2407 let texture = handle_potential_webgl_error!(
2408 self,
2409 texture_slot.get().ok_or(InvalidOperation),
2410 return retval.set(NullValue())
2411 );
2412
2413 if !self
2414 .extension_manager
2415 .is_get_tex_parameter_name_enabled(pname)
2416 {
2417 self.webgl_error(InvalidEnum);
2418 return retval.set(NullValue());
2419 }
2420
2421 match pname {
2422 constants::TEXTURE_MAG_FILTER => return retval.set(UInt32Value(texture.mag_filter())),
2423 constants::TEXTURE_MIN_FILTER => return retval.set(UInt32Value(texture.min_filter())),
2424 _ => {},
2425 }
2426
2427 let texparam = handle_potential_webgl_error!(
2428 self,
2429 TexParameter::from_u32(pname),
2430 return retval.set(NullValue())
2431 );
2432 if self.webgl_version() < texparam.required_webgl_version() {
2433 self.webgl_error(InvalidEnum);
2434 return retval.set(NullValue());
2435 }
2436
2437 if let Some(value) = texture.maybe_get_tex_parameter(texparam) {
2438 match value {
2439 TexParameterValue::Float(v) => retval.set(DoubleValue(v as f64)),
2440 TexParameterValue::Int(v) => retval.set(Int32Value(v)),
2441 TexParameterValue::Bool(v) => retval.set(BooleanValue(v)),
2442 }
2443 return;
2444 }
2445
2446 match texparam {
2447 TexParameter::Float(param) => {
2448 let (sender, receiver) = webgl_channel().unwrap();
2449 self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender));
2450 retval.set(DoubleValue(receiver.recv().unwrap() as f64))
2451 },
2452 TexParameter::Int(param) => {
2453 let (sender, receiver) = webgl_channel().unwrap();
2454 self.send_command(WebGLCommand::GetTexParameterInt(target, param, sender));
2455 retval.set(Int32Value(receiver.recv().unwrap()))
2456 },
2457 TexParameter::Bool(param) => {
2458 let (sender, receiver) = webgl_channel().unwrap();
2459 self.send_command(WebGLCommand::GetTexParameterBool(target, param, sender));
2460 retval.set(BooleanValue(receiver.recv().unwrap()))
2461 },
2462 }
2463 }
2464
2465 fn GetError(&self) -> u32 {
2467 let error_code = if let Some(error) = self.last_error.get() {
2468 match error {
2469 WebGLError::InvalidEnum => constants::INVALID_ENUM,
2470 WebGLError::InvalidFramebufferOperation => constants::INVALID_FRAMEBUFFER_OPERATION,
2471 WebGLError::InvalidValue => constants::INVALID_VALUE,
2472 WebGLError::InvalidOperation => constants::INVALID_OPERATION,
2473 WebGLError::OutOfMemory => constants::OUT_OF_MEMORY,
2474 WebGLError::ContextLost => constants::CONTEXT_LOST_WEBGL,
2475 }
2476 } else {
2477 constants::NO_ERROR
2478 };
2479 self.last_error.set(None);
2480 error_code
2481 }
2482
2483 fn GetContextAttributes(&self) -> Option<WebGLContextAttributes> {
2485 let (sender, receiver) = webgl_channel().unwrap();
2486
2487 let backtrace = capture_webgl_backtrace();
2489 if self
2490 .webgl_sender
2491 .send(WebGLCommand::GetContextAttributes(sender), backtrace)
2492 .is_err()
2493 {
2494 return None;
2495 }
2496
2497 let attrs = receiver.recv().unwrap();
2498
2499 Some(WebGLContextAttributes {
2500 alpha: attrs.alpha,
2501 antialias: attrs.antialias,
2502 depth: attrs.depth,
2503 failIfMajorPerformanceCaveat: false,
2504 preferLowPowerToHighPerformance: false,
2505 premultipliedAlpha: attrs.premultiplied_alpha,
2506 preserveDrawingBuffer: attrs.preserve_drawing_buffer,
2507 stencil: attrs.stencil,
2508 })
2509 }
2510
2511 fn IsContextLost(&self) -> bool {
2513 false
2514 }
2515
2516 fn GetSupportedExtensions(&self) -> Option<Vec<DOMString>> {
2518 self.extension_manager
2519 .init_once(|| self.get_gl_extensions());
2520 let extensions = self.extension_manager.get_supported_extensions();
2521 Some(
2522 extensions
2523 .iter()
2524 .map(|name| DOMString::from(*name))
2525 .collect(),
2526 )
2527 }
2528
2529 fn GetExtension(&self, _cx: SafeJSContext, name: DOMString) -> Option<NonNull<JSObject>> {
2531 self.extension_manager
2532 .init_once(|| self.get_gl_extensions());
2533 self.extension_manager.get_or_init_extension(&name, self)
2534 }
2535
2536 fn ActiveTexture(&self, texture: u32) {
2538 handle_potential_webgl_error!(self, self.textures.set_active_unit_enum(texture), return);
2539 self.send_command(WebGLCommand::ActiveTexture(texture));
2540 }
2541
2542 fn BlendColor(&self, r: f32, g: f32, b: f32, a: f32) {
2544 self.send_command(WebGLCommand::BlendColor(r, g, b, a));
2545 }
2546
2547 fn BlendEquation(&self, mode: u32) {
2549 handle_potential_webgl_error!(self, self.validate_blend_mode(mode), return);
2550 self.send_command(WebGLCommand::BlendEquation(mode))
2551 }
2552
2553 fn BlendEquationSeparate(&self, mode_rgb: u32, mode_alpha: u32) {
2555 handle_potential_webgl_error!(self, self.validate_blend_mode(mode_rgb), return);
2556 handle_potential_webgl_error!(self, self.validate_blend_mode(mode_alpha), return);
2557 self.send_command(WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha));
2558 }
2559
2560 fn BlendFunc(&self, src_factor: u32, dest_factor: u32) {
2562 if has_invalid_blend_constants(src_factor, dest_factor) {
2568 return self.webgl_error(InvalidOperation);
2569 }
2570 if has_invalid_blend_constants(dest_factor, src_factor) {
2571 return self.webgl_error(InvalidOperation);
2572 }
2573
2574 self.send_command(WebGLCommand::BlendFunc(src_factor, dest_factor));
2575 }
2576
2577 fn BlendFuncSeparate(&self, src_rgb: u32, dest_rgb: u32, src_alpha: u32, dest_alpha: u32) {
2579 if has_invalid_blend_constants(src_rgb, dest_rgb) {
2585 return self.webgl_error(InvalidOperation);
2586 }
2587 if has_invalid_blend_constants(dest_rgb, src_rgb) {
2588 return self.webgl_error(InvalidOperation);
2589 }
2590
2591 self.send_command(WebGLCommand::BlendFuncSeparate(
2592 src_rgb, dest_rgb, src_alpha, dest_alpha,
2593 ));
2594 }
2595
2596 fn AttachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
2598 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2599 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
2600 handle_potential_webgl_error!(self, program.attach_shader(shader));
2601 }
2602
2603 fn DetachShader(&self, program: &WebGLProgram, shader: &WebGLShader) {
2605 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2606 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
2607 handle_potential_webgl_error!(self, program.detach_shader(shader));
2608 }
2609
2610 fn BindAttribLocation(&self, program: &WebGLProgram, index: u32, name: DOMString) {
2612 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
2613 handle_potential_webgl_error!(self, program.bind_attrib_location(index, name));
2614 }
2615
2616 fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
2618 let current_vao;
2619 let slot = match target {
2620 constants::ARRAY_BUFFER => &self.bound_buffer_array,
2621 constants::ELEMENT_ARRAY_BUFFER => {
2622 current_vao = self.current_vao();
2623 current_vao.element_array_buffer()
2624 },
2625 _ => return self.webgl_error(InvalidEnum),
2626 };
2627 self.bind_buffer_maybe(slot, target, buffer);
2628 }
2629
2630 fn BindFramebuffer(&self, target: u32, framebuffer: Option<&WebGLFramebuffer>) {
2632 handle_potential_webgl_error!(
2633 self,
2634 self.validate_new_framebuffer_binding(framebuffer),
2635 return
2636 );
2637
2638 if target != constants::FRAMEBUFFER {
2639 return self.webgl_error(InvalidEnum);
2640 }
2641
2642 self.bind_framebuffer_to(target, framebuffer, &self.bound_draw_framebuffer)
2643 }
2644
2645 fn BindRenderbuffer(&self, target: u32, renderbuffer: Option<&WebGLRenderbuffer>) {
2647 if let Some(rb) = renderbuffer {
2648 handle_potential_webgl_error!(self, self.validate_ownership(rb), return);
2649 }
2650
2651 if target != constants::RENDERBUFFER {
2652 return self.webgl_error(InvalidEnum);
2653 }
2654
2655 match renderbuffer {
2656 Some(renderbuffer) if !renderbuffer.is_deleted() => {
2660 self.bound_renderbuffer.set(Some(renderbuffer));
2661 renderbuffer.bind(target);
2662 },
2663 _ => {
2664 if renderbuffer.is_some() {
2665 self.webgl_error(InvalidOperation);
2666 }
2667
2668 self.bound_renderbuffer.set(None);
2669 self.send_command(WebGLCommand::BindRenderbuffer(target, None));
2671 },
2672 }
2673 }
2674
2675 fn BindTexture(&self, target: u32, texture: Option<&WebGLTexture>) {
2677 if let Some(texture) = texture {
2678 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
2679 }
2680
2681 let texture_slot = handle_potential_webgl_error!(
2682 self,
2683 self.textures
2684 .active_texture_slot(target, self.webgl_version()),
2685 return
2686 );
2687
2688 if let Some(texture) = texture {
2689 handle_potential_webgl_error!(self, texture.bind(target), return);
2690 } else {
2691 self.send_command(WebGLCommand::BindTexture(target, None));
2692 }
2693 texture_slot.set(texture);
2694 }
2695
2696 fn GenerateMipmap(&self, target: u32) {
2698 let texture_slot = handle_potential_webgl_error!(
2699 self,
2700 self.textures
2701 .active_texture_slot(target, self.webgl_version()),
2702 return
2703 );
2704 let texture =
2705 handle_potential_webgl_error!(self, texture_slot.get().ok_or(InvalidOperation), return);
2706 handle_potential_webgl_error!(self, texture.generate_mipmap());
2707 }
2708
2709 fn BufferData_(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
2711 let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
2712 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2713 self.buffer_data(target, data, usage, bound_buffer)
2714 }
2715
2716 fn BufferData(&self, target: u32, size: i64, usage: u32) {
2718 let usage = handle_potential_webgl_error!(self, self.buffer_usage(usage), return);
2719 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2720 self.buffer_data_(target, size, usage, bound_buffer)
2721 }
2722
2723 #[allow(unsafe_code)]
2725 fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
2726 let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
2727 self.buffer_sub_data(target, offset, data, bound_buffer)
2728 }
2729
2730 #[allow(unsafe_code)]
2732 fn CompressedTexImage2D(
2733 &self,
2734 target: u32,
2735 level: i32,
2736 internal_format: u32,
2737 width: i32,
2738 height: i32,
2739 border: i32,
2740 data: CustomAutoRooterGuard<ArrayBufferView>,
2741 ) {
2742 let data = unsafe { data.as_slice() };
2743 self.compressed_tex_image_2d(target, level, internal_format, width, height, border, data)
2744 }
2745
2746 #[allow(unsafe_code)]
2748 fn CompressedTexSubImage2D(
2749 &self,
2750 target: u32,
2751 level: i32,
2752 xoffset: i32,
2753 yoffset: i32,
2754 width: i32,
2755 height: i32,
2756 format: u32,
2757 data: CustomAutoRooterGuard<ArrayBufferView>,
2758 ) {
2759 let data = unsafe { data.as_slice() };
2760 self.compressed_tex_sub_image_2d(
2761 target, level, xoffset, yoffset, width, height, format, data,
2762 )
2763 }
2764
2765 fn CopyTexImage2D(
2767 &self,
2768 target: u32,
2769 level: i32,
2770 internal_format: u32,
2771 x: i32,
2772 y: i32,
2773 width: i32,
2774 height: i32,
2775 border: i32,
2776 ) {
2777 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2778
2779 let validator = CommonTexImage2DValidator::new(
2780 self,
2781 target,
2782 level,
2783 internal_format,
2784 width,
2785 height,
2786 border,
2787 );
2788 let CommonTexImage2DValidatorResult {
2789 texture,
2790 target,
2791 level,
2792 internal_format,
2793 width,
2794 height,
2795 border,
2796 } = match validator.validate() {
2797 Ok(result) => result,
2798 Err(_) => return,
2799 };
2800
2801 if texture.is_immutable() {
2802 return self.webgl_error(InvalidOperation);
2803 }
2804
2805 let framebuffer_format = match self.bound_draw_framebuffer.get() {
2806 Some(fb) => match fb.attachment(constants::COLOR_ATTACHMENT0) {
2807 Some(WebGLFramebufferAttachmentRoot::Renderbuffer(rb)) => {
2808 TexFormat::from_gl_constant(rb.internal_format())
2809 },
2810 Some(WebGLFramebufferAttachmentRoot::Texture(texture)) => texture
2811 .image_info_for_target(&target, 0)
2812 .map(|info| info.internal_format()),
2813 None => None,
2814 },
2815 None => {
2816 let attrs = self.GetContextAttributes().unwrap();
2817 Some(if attrs.alpha {
2818 TexFormat::RGBA
2819 } else {
2820 TexFormat::RGB
2821 })
2822 },
2823 };
2824
2825 let framebuffer_format = match framebuffer_format {
2826 Some(f) => f,
2827 None => {
2828 self.webgl_error(InvalidOperation);
2829 return;
2830 },
2831 };
2832
2833 match (framebuffer_format, internal_format) {
2834 (a, b) if a == b => (),
2835 (TexFormat::RGBA, TexFormat::RGB) => (),
2836 (TexFormat::RGBA, TexFormat::Alpha) => (),
2837 (TexFormat::RGBA, TexFormat::Luminance) => (),
2838 (TexFormat::RGBA, TexFormat::LuminanceAlpha) => (),
2839 (TexFormat::RGB, TexFormat::Luminance) => (),
2840 _ => {
2841 self.webgl_error(InvalidOperation);
2842 return;
2843 },
2844 }
2845
2846 handle_potential_webgl_error!(
2848 self,
2849 texture.initialize(target, width, height, 1, internal_format, level, None)
2850 );
2851
2852 let msg = WebGLCommand::CopyTexImage2D(
2853 target.as_gl_constant(),
2854 level as i32,
2855 internal_format.as_gl_constant(),
2856 x,
2857 y,
2858 width as i32,
2859 height as i32,
2860 border as i32,
2861 );
2862
2863 self.send_command(msg);
2864 }
2865
2866 fn CopyTexSubImage2D(
2868 &self,
2869 target: u32,
2870 level: i32,
2871 xoffset: i32,
2872 yoffset: i32,
2873 x: i32,
2874 y: i32,
2875 width: i32,
2876 height: i32,
2877 ) {
2878 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2879
2880 let validator = CommonTexImage2DValidator::new(
2883 self,
2884 target,
2885 level,
2886 TexFormat::RGBA.as_gl_constant(),
2887 width,
2888 height,
2889 0,
2890 );
2891 let CommonTexImage2DValidatorResult {
2892 texture,
2893 target,
2894 level,
2895 width,
2896 height,
2897 ..
2898 } = match validator.validate() {
2899 Ok(result) => result,
2900 Err(_) => return,
2901 };
2902
2903 let image_info = match texture.image_info_for_target(&target, level) {
2904 Some(info) => info,
2905 None => return self.webgl_error(InvalidOperation),
2906 };
2907
2908 if xoffset < 0 ||
2913 (xoffset as u32 + width) > image_info.width() ||
2914 yoffset < 0 ||
2915 (yoffset as u32 + height) > image_info.height()
2916 {
2917 self.webgl_error(InvalidValue);
2918 return;
2919 }
2920
2921 let msg = WebGLCommand::CopyTexSubImage2D(
2922 target.as_gl_constant(),
2923 level as i32,
2924 xoffset,
2925 yoffset,
2926 x,
2927 y,
2928 width as i32,
2929 height as i32,
2930 );
2931
2932 self.send_command(msg);
2933 }
2934
2935 fn Clear(&self, mask: u32) {
2937 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
2938 if mask &
2939 !(constants::DEPTH_BUFFER_BIT |
2940 constants::STENCIL_BUFFER_BIT |
2941 constants::COLOR_BUFFER_BIT) !=
2942 0
2943 {
2944 return self.webgl_error(InvalidValue);
2945 }
2946
2947 self.send_command(WebGLCommand::Clear(mask));
2948 self.mark_as_dirty();
2949 }
2950
2951 fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
2953 self.current_clear_color.set((red, green, blue, alpha));
2954 self.send_command(WebGLCommand::ClearColor(red, green, blue, alpha));
2955 }
2956
2957 fn ClearDepth(&self, depth: f32) {
2959 self.send_command(WebGLCommand::ClearDepth(depth))
2960 }
2961
2962 fn ClearStencil(&self, stencil: i32) {
2964 self.send_command(WebGLCommand::ClearStencil(stencil))
2965 }
2966
2967 fn ColorMask(&self, r: bool, g: bool, b: bool, a: bool) {
2969 self.send_command(WebGLCommand::ColorMask(r, g, b, a))
2970 }
2971
2972 fn CullFace(&self, mode: u32) {
2974 match mode {
2975 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => {
2976 self.send_command(WebGLCommand::CullFace(mode))
2977 },
2978 _ => self.webgl_error(InvalidEnum),
2979 }
2980 }
2981
2982 fn FrontFace(&self, mode: u32) {
2984 match mode {
2985 constants::CW | constants::CCW => self.send_command(WebGLCommand::FrontFace(mode)),
2986 _ => self.webgl_error(InvalidEnum),
2987 }
2988 }
2989 fn DepthFunc(&self, func: u32) {
2991 match func {
2992 constants::NEVER |
2993 constants::LESS |
2994 constants::EQUAL |
2995 constants::LEQUAL |
2996 constants::GREATER |
2997 constants::NOTEQUAL |
2998 constants::GEQUAL |
2999 constants::ALWAYS => self.send_command(WebGLCommand::DepthFunc(func)),
3000 _ => self.webgl_error(InvalidEnum),
3001 }
3002 }
3003
3004 fn DepthMask(&self, flag: bool) {
3006 self.send_command(WebGLCommand::DepthMask(flag))
3007 }
3008
3009 fn DepthRange(&self, near: f32, far: f32) {
3011 if near > far {
3013 return self.webgl_error(InvalidOperation);
3014 }
3015 self.send_command(WebGLCommand::DepthRange(near, far))
3016 }
3017
3018 fn Enable(&self, cap: u32) {
3020 if handle_potential_webgl_error!(self, self.capabilities.set(cap, true), return) {
3021 self.send_command(WebGLCommand::Enable(cap));
3022 }
3023 }
3024
3025 fn Disable(&self, cap: u32) {
3027 if handle_potential_webgl_error!(self, self.capabilities.set(cap, false), return) {
3028 self.send_command(WebGLCommand::Disable(cap));
3029 }
3030 }
3031
3032 fn CompileShader(&self, shader: &WebGLShader) {
3034 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
3035 handle_potential_webgl_error!(
3036 self,
3037 shader.compile(
3038 self.api_type,
3039 self.webgl_version,
3040 self.glsl_version,
3041 &self.limits,
3042 &self.extension_manager,
3043 )
3044 )
3045 }
3046
3047 fn CreateBuffer(&self) -> Option<DomRoot<WebGLBuffer>> {
3049 WebGLBuffer::maybe_new(self, CanGc::note())
3050 }
3051
3052 fn CreateFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
3054 WebGLFramebuffer::maybe_new(self, CanGc::note())
3055 }
3056
3057 fn CreateRenderbuffer(&self) -> Option<DomRoot<WebGLRenderbuffer>> {
3059 WebGLRenderbuffer::maybe_new(self)
3060 }
3061
3062 fn CreateTexture(&self) -> Option<DomRoot<WebGLTexture>> {
3064 WebGLTexture::maybe_new(self)
3065 }
3066
3067 fn CreateProgram(&self) -> Option<DomRoot<WebGLProgram>> {
3069 WebGLProgram::maybe_new(self, CanGc::note())
3070 }
3071
3072 fn CreateShader(&self, shader_type: u32) -> Option<DomRoot<WebGLShader>> {
3074 match shader_type {
3075 constants::VERTEX_SHADER | constants::FRAGMENT_SHADER => {},
3076 _ => {
3077 self.webgl_error(InvalidEnum);
3078 return None;
3079 },
3080 }
3081 WebGLShader::maybe_new(self, shader_type)
3082 }
3083
3084 fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
3086 let buffer = match buffer {
3087 Some(buffer) => buffer,
3088 None => return,
3089 };
3090 handle_potential_webgl_error!(self, self.validate_ownership(buffer), return);
3091 if buffer.is_marked_for_deletion() {
3092 return;
3093 }
3094 self.current_vao().unbind_buffer(buffer);
3095 if self.bound_buffer_array.get().is_some_and(|b| buffer == &*b) {
3096 self.bound_buffer_array.set(None);
3097 buffer.decrement_attached_counter(Operation::Infallible);
3098 }
3099 buffer.mark_for_deletion(Operation::Infallible);
3100 }
3101
3102 fn DeleteFramebuffer(&self, framebuffer: Option<&WebGLFramebuffer>) {
3104 if let Some(framebuffer) = framebuffer {
3105 handle_potential_webgl_error!(self, framebuffer.validate_transparent(), return);
3109 handle_potential_webgl_error!(self, self.validate_ownership(framebuffer), return);
3110 handle_object_deletion!(
3111 self,
3112 self.bound_draw_framebuffer,
3113 framebuffer,
3114 Some(WebGLCommand::BindFramebuffer(
3115 framebuffer.target().unwrap(),
3116 WebGLFramebufferBindingRequest::Default
3117 ))
3118 );
3119 framebuffer.delete(Operation::Infallible)
3120 }
3121 }
3122
3123 fn DeleteRenderbuffer(&self, renderbuffer: Option<&WebGLRenderbuffer>) {
3125 if let Some(renderbuffer) = renderbuffer {
3126 handle_potential_webgl_error!(self, self.validate_ownership(renderbuffer), return);
3127 handle_object_deletion!(
3128 self,
3129 self.bound_renderbuffer,
3130 renderbuffer,
3131 Some(WebGLCommand::BindRenderbuffer(
3132 constants::RENDERBUFFER,
3133 None
3134 ))
3135 );
3136 renderbuffer.delete(Operation::Infallible)
3137 }
3138 }
3139
3140 fn DeleteTexture(&self, texture: Option<&WebGLTexture>) {
3142 if let Some(texture) = texture {
3143 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
3144
3145 let mut active_unit_enum = self.textures.active_unit_enum();
3154 for (unit_enum, slot) in self.textures.iter() {
3155 if let Some(target) = slot.unbind(texture) {
3156 if unit_enum != active_unit_enum {
3157 self.send_command(WebGLCommand::ActiveTexture(unit_enum));
3158 active_unit_enum = unit_enum;
3159 }
3160 self.send_command(WebGLCommand::BindTexture(target, None));
3161 }
3162 }
3163
3164 if active_unit_enum != self.textures.active_unit_enum() {
3166 self.send_command(WebGLCommand::ActiveTexture(
3167 self.textures.active_unit_enum(),
3168 ));
3169 }
3170
3171 texture.delete(Operation::Infallible)
3172 }
3173 }
3174
3175 fn DeleteProgram(&self, program: Option<&WebGLProgram>) {
3177 if let Some(program) = program {
3178 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
3179 program.mark_for_deletion(Operation::Infallible)
3180 }
3181 }
3182
3183 fn DeleteShader(&self, shader: Option<&WebGLShader>) {
3185 if let Some(shader) = shader {
3186 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
3187 shader.mark_for_deletion(Operation::Infallible)
3188 }
3189 }
3190
3191 fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
3193 handle_potential_webgl_error!(self, self.draw_arrays_instanced(mode, first, count, 1));
3194 }
3195
3196 fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
3198 handle_potential_webgl_error!(
3199 self,
3200 self.draw_elements_instanced(mode, count, type_, offset, 1)
3201 );
3202 }
3203
3204 fn EnableVertexAttribArray(&self, attrib_id: u32) {
3206 if attrib_id >= self.limits.max_vertex_attribs {
3207 return self.webgl_error(InvalidValue);
3208 }
3209 match self.webgl_version() {
3210 WebGLVersion::WebGL1 => self
3211 .current_vao()
3212 .enabled_vertex_attrib_array(attrib_id, true),
3213 WebGLVersion::WebGL2 => self
3214 .current_vao_webgl2()
3215 .enabled_vertex_attrib_array(attrib_id, true),
3216 };
3217 self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
3218 }
3219
3220 fn DisableVertexAttribArray(&self, attrib_id: u32) {
3222 if attrib_id >= self.limits.max_vertex_attribs {
3223 return self.webgl_error(InvalidValue);
3224 }
3225 match self.webgl_version() {
3226 WebGLVersion::WebGL1 => self
3227 .current_vao()
3228 .enabled_vertex_attrib_array(attrib_id, false),
3229 WebGLVersion::WebGL2 => self
3230 .current_vao_webgl2()
3231 .enabled_vertex_attrib_array(attrib_id, false),
3232 };
3233 self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
3234 }
3235
3236 fn GetActiveUniform(
3238 &self,
3239 program: &WebGLProgram,
3240 index: u32,
3241 ) -> Option<DomRoot<WebGLActiveInfo>> {
3242 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3243 match program.get_active_uniform(index, CanGc::note()) {
3244 Ok(ret) => Some(ret),
3245 Err(e) => {
3246 self.webgl_error(e);
3247 None
3248 },
3249 }
3250 }
3251
3252 fn GetActiveAttrib(
3254 &self,
3255 program: &WebGLProgram,
3256 index: u32,
3257 ) -> Option<DomRoot<WebGLActiveInfo>> {
3258 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3259 handle_potential_webgl_error!(
3260 self,
3261 program.get_active_attrib(index, CanGc::note()).map(Some),
3262 None
3263 )
3264 }
3265
3266 fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
3268 handle_potential_webgl_error!(self, self.validate_ownership(program), return -1);
3269 handle_potential_webgl_error!(self, program.get_attrib_location(name), -1)
3270 }
3271
3272 fn GetFramebufferAttachmentParameter(
3274 &self,
3275 cx: SafeJSContext,
3276 target: u32,
3277 attachment: u32,
3278 pname: u32,
3279 mut retval: MutableHandleValue,
3280 ) {
3281 if let Some(fb) = self.bound_draw_framebuffer.get() {
3283 handle_potential_webgl_error!(
3286 self,
3287 fb.validate_transparent(),
3288 return retval.set(NullValue())
3289 );
3290 } else {
3291 self.webgl_error(InvalidOperation);
3292 return retval.set(NullValue());
3293 }
3294
3295 let target_matches = match target {
3297 constants::FRAMEBUFFER => true,
3300 _ => false,
3301 };
3302 let attachment_matches = match attachment {
3303 constants::COLOR_ATTACHMENT0 |
3306 constants::DEPTH_STENCIL_ATTACHMENT |
3307 constants::DEPTH_ATTACHMENT |
3308 constants::STENCIL_ATTACHMENT => true,
3309 _ => false,
3310 };
3311 let pname_matches = match pname {
3312 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME |
3322 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3323 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE |
3324 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL => true,
3325 _ => false,
3326 };
3327
3328 let bound_attachment_matches = match self
3329 .bound_draw_framebuffer
3330 .get()
3331 .unwrap()
3332 .attachment(attachment)
3333 {
3334 Some(attachment_root) => match attachment_root {
3335 WebGLFramebufferAttachmentRoot::Renderbuffer(_) => matches!(
3336 pname,
3337 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3338 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
3339 ),
3340 WebGLFramebufferAttachmentRoot::Texture(_) => matches!(
3341 pname,
3342 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE |
3343 constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME |
3344 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL |
3345 constants::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
3346 ),
3347 },
3348 _ => matches!(pname, constants::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE),
3349 };
3350
3351 if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches {
3352 self.webgl_error(InvalidEnum);
3353 return retval.set(NullValue());
3354 }
3355
3356 if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
3363 let fb = self.bound_draw_framebuffer.get().unwrap();
3366 if let Some(webgl_attachment) = fb.attachment(attachment) {
3367 match webgl_attachment {
3368 WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => {
3369 rb.safe_to_jsval(cx, retval);
3370 return;
3371 },
3372 WebGLFramebufferAttachmentRoot::Texture(texture) => {
3373 texture.safe_to_jsval(cx, retval);
3374 return;
3375 },
3376 }
3377 }
3378 self.webgl_error(InvalidEnum);
3379 return retval.set(NullValue());
3380 }
3381
3382 let (sender, receiver) = webgl_channel().unwrap();
3383 self.send_command(WebGLCommand::GetFramebufferAttachmentParameter(
3384 target, attachment, pname, sender,
3385 ));
3386
3387 retval.set(Int32Value(receiver.recv().unwrap()))
3388 }
3389
3390 fn GetRenderbufferParameter(
3392 &self,
3393 _cx: SafeJSContext,
3394 target: u32,
3395 pname: u32,
3396 mut retval: MutableHandleValue,
3397 ) {
3398 let target_matches = target == constants::RENDERBUFFER;
3401
3402 let pname_matches = matches!(
3403 pname,
3404 constants::RENDERBUFFER_WIDTH |
3405 constants::RENDERBUFFER_HEIGHT |
3406 constants::RENDERBUFFER_INTERNAL_FORMAT |
3407 constants::RENDERBUFFER_RED_SIZE |
3408 constants::RENDERBUFFER_GREEN_SIZE |
3409 constants::RENDERBUFFER_BLUE_SIZE |
3410 constants::RENDERBUFFER_ALPHA_SIZE |
3411 constants::RENDERBUFFER_DEPTH_SIZE |
3412 constants::RENDERBUFFER_STENCIL_SIZE
3413 );
3414
3415 if !target_matches || !pname_matches {
3416 self.webgl_error(InvalidEnum);
3417 return retval.set(NullValue());
3418 }
3419
3420 if self.bound_renderbuffer.get().is_none() {
3421 self.webgl_error(InvalidOperation);
3422 return retval.set(NullValue());
3423 }
3424
3425 let result = if pname == constants::RENDERBUFFER_INTERNAL_FORMAT {
3426 let rb = self.bound_renderbuffer.get().unwrap();
3427 rb.internal_format() as i32
3428 } else {
3429 let (sender, receiver) = webgl_channel().unwrap();
3430 self.send_command(WebGLCommand::GetRenderbufferParameter(
3431 target, pname, sender,
3432 ));
3433 receiver.recv().unwrap()
3434 };
3435
3436 retval.set(Int32Value(result))
3437 }
3438
3439 fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
3441 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3442 match program.get_info_log() {
3443 Ok(value) => Some(DOMString::from(value)),
3444 Err(e) => {
3445 self.webgl_error(e);
3446 None
3447 },
3448 }
3449 }
3450
3451 fn GetProgramParameter(
3453 &self,
3454 _: SafeJSContext,
3455 program: &WebGLProgram,
3456 param: u32,
3457 mut retval: MutableHandleValue,
3458 ) {
3459 handle_potential_webgl_error!(
3460 self,
3461 self.validate_ownership(program),
3462 return retval.set(NullValue())
3463 );
3464 if program.is_deleted() {
3465 self.webgl_error(InvalidOperation);
3466 return retval.set(NullValue());
3467 }
3468 retval.set(match param {
3469 constants::DELETE_STATUS => BooleanValue(program.is_marked_for_deletion()),
3470 constants::LINK_STATUS => BooleanValue(program.is_linked()),
3471 constants::VALIDATE_STATUS => {
3472 let (sender, receiver) = webgl_channel().unwrap();
3475 self.send_command(WebGLCommand::GetProgramValidateStatus(program.id(), sender));
3476 BooleanValue(receiver.recv().unwrap())
3477 },
3478 constants::ATTACHED_SHADERS => {
3479 Int32Value(
3481 program
3482 .attached_shaders()
3483 .map(|shaders| shaders.len() as i32)
3484 .unwrap_or(0),
3485 )
3486 },
3487 constants::ACTIVE_ATTRIBUTES => Int32Value(program.active_attribs().len() as i32),
3488 constants::ACTIVE_UNIFORMS => Int32Value(program.active_uniforms().len() as i32),
3489 _ => {
3490 self.webgl_error(InvalidEnum);
3491 NullValue()
3492 },
3493 })
3494 }
3495
3496 fn GetShaderInfoLog(&self, shader: &WebGLShader) -> Option<DOMString> {
3498 handle_potential_webgl_error!(self, self.validate_ownership(shader), return None);
3499 Some(shader.info_log())
3500 }
3501
3502 fn GetShaderParameter(
3504 &self,
3505 _: SafeJSContext,
3506 shader: &WebGLShader,
3507 param: u32,
3508 mut retval: MutableHandleValue,
3509 ) {
3510 handle_potential_webgl_error!(
3511 self,
3512 self.validate_ownership(shader),
3513 return retval.set(NullValue())
3514 );
3515 if shader.is_deleted() {
3516 self.webgl_error(InvalidValue);
3517 return retval.set(NullValue());
3518 }
3519 retval.set(match param {
3520 constants::DELETE_STATUS => BooleanValue(shader.is_marked_for_deletion()),
3521 constants::COMPILE_STATUS => BooleanValue(shader.successfully_compiled()),
3522 constants::SHADER_TYPE => UInt32Value(shader.gl_type()),
3523 _ => {
3524 self.webgl_error(InvalidEnum);
3525 NullValue()
3526 },
3527 })
3528 }
3529
3530 fn GetShaderPrecisionFormat(
3532 &self,
3533 shader_type: u32,
3534 precision_type: u32,
3535 ) -> Option<DomRoot<WebGLShaderPrecisionFormat>> {
3536 match shader_type {
3537 constants::FRAGMENT_SHADER | constants::VERTEX_SHADER => (),
3538 _ => {
3539 self.webgl_error(InvalidEnum);
3540 return None;
3541 },
3542 }
3543
3544 match precision_type {
3545 constants::LOW_FLOAT |
3546 constants::MEDIUM_FLOAT |
3547 constants::HIGH_FLOAT |
3548 constants::LOW_INT |
3549 constants::MEDIUM_INT |
3550 constants::HIGH_INT => (),
3551 _ => {
3552 self.webgl_error(InvalidEnum);
3553 return None;
3554 },
3555 }
3556
3557 let (sender, receiver) = webgl_channel().unwrap();
3558 self.send_command(WebGLCommand::GetShaderPrecisionFormat(
3559 shader_type,
3560 precision_type,
3561 sender,
3562 ));
3563
3564 let (range_min, range_max, precision) = receiver.recv().unwrap();
3565 Some(WebGLShaderPrecisionFormat::new(
3566 self.global().as_window(),
3567 range_min,
3568 range_max,
3569 precision,
3570 CanGc::note(),
3571 ))
3572 }
3573
3574 fn GetUniformLocation(
3576 &self,
3577 program: &WebGLProgram,
3578 name: DOMString,
3579 ) -> Option<DomRoot<WebGLUniformLocation>> {
3580 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
3581 handle_potential_webgl_error!(
3582 self,
3583 program.get_uniform_location(name, CanGc::note()),
3584 None
3585 )
3586 }
3587
3588 #[allow(unsafe_code)]
3589 fn GetVertexAttrib(
3591 &self,
3592 cx: SafeJSContext,
3593 index: u32,
3594 param: u32,
3595 mut retval: MutableHandleValue,
3596 ) {
3597 let mut get_attrib = |data: Ref<'_, VertexAttribData>| {
3598 if param == constants::CURRENT_VERTEX_ATTRIB {
3599 let attrib = self.current_vertex_attribs.borrow()[index as usize];
3600 match attrib {
3601 VertexAttrib::Float(x, y, z, w) => {
3602 let value = [x, y, z, w];
3603 unsafe {
3604 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3605 Float32Array::create(
3606 *cx,
3607 CreateWith::Slice(&value),
3608 result.handle_mut(),
3609 )
3610 .unwrap();
3611 return retval.set(ObjectValue(result.get()));
3612 }
3613 },
3614 VertexAttrib::Int(x, y, z, w) => {
3615 let value = [x, y, z, w];
3616 unsafe {
3617 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3618 Int32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
3619 .unwrap();
3620 return retval.set(ObjectValue(result.get()));
3621 }
3622 },
3623 VertexAttrib::Uint(x, y, z, w) => {
3624 let value = [x, y, z, w];
3625 unsafe {
3626 rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
3627 Uint32Array::create(
3628 *cx,
3629 CreateWith::Slice(&value),
3630 result.handle_mut(),
3631 )
3632 .unwrap();
3633 return retval.set(ObjectValue(result.get()));
3634 }
3635 },
3636 };
3637 }
3638 if !self
3639 .extension_manager
3640 .is_get_vertex_attrib_name_enabled(param)
3641 {
3642 self.webgl_error(WebGLError::InvalidEnum);
3643 return retval.set(NullValue());
3644 }
3645
3646 match param {
3647 constants::VERTEX_ATTRIB_ARRAY_ENABLED => {
3648 retval.set(BooleanValue(data.enabled_as_array))
3649 },
3650 constants::VERTEX_ATTRIB_ARRAY_SIZE => retval.set(Int32Value(data.size as i32)),
3651 constants::VERTEX_ATTRIB_ARRAY_TYPE => retval.set(Int32Value(data.type_ as i32)),
3652 constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => {
3653 retval.set(BooleanValue(data.normalized))
3654 },
3655 constants::VERTEX_ATTRIB_ARRAY_STRIDE => retval.set(Int32Value(data.stride as i32)),
3656 constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => {
3657 if let Some(buffer) = data.buffer() {
3658 buffer.safe_to_jsval(cx, retval.reborrow());
3659 } else {
3660 retval.set(NullValue());
3661 }
3662 },
3663 ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
3664 retval.set(UInt32Value(data.divisor))
3665 },
3666 _ => {
3667 self.webgl_error(InvalidEnum);
3668 retval.set(NullValue())
3669 },
3670 }
3671 };
3672
3673 match self.webgl_version() {
3674 WebGLVersion::WebGL1 => {
3675 let current_vao = self.current_vao();
3676 let data = handle_potential_webgl_error!(
3677 self,
3678 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3679 return retval.set(NullValue())
3680 );
3681 get_attrib(data)
3682 },
3683 WebGLVersion::WebGL2 => {
3684 let current_vao = self.current_vao_webgl2();
3685 let data = handle_potential_webgl_error!(
3686 self,
3687 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3688 return retval.set(NullValue())
3689 );
3690 get_attrib(data)
3691 },
3692 }
3693 }
3694
3695 fn GetVertexAttribOffset(&self, index: u32, pname: u32) -> i64 {
3697 if pname != constants::VERTEX_ATTRIB_ARRAY_POINTER {
3698 self.webgl_error(InvalidEnum);
3699 return 0;
3700 }
3701 match self.webgl_version() {
3702 WebGLVersion::WebGL1 => {
3703 let current_vao = self.current_vao();
3704 let data = handle_potential_webgl_error!(
3705 self,
3706 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3707 return 0
3708 );
3709 data.offset as i64
3710 },
3711 WebGLVersion::WebGL2 => {
3712 let current_vao = self.current_vao_webgl2();
3713 let data = handle_potential_webgl_error!(
3714 self,
3715 current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
3716 return 0
3717 );
3718 data.offset as i64
3719 },
3720 }
3721 }
3722
3723 fn Hint(&self, target: u32, mode: u32) {
3725 if target != constants::GENERATE_MIPMAP_HINT &&
3726 !self.extension_manager.is_hint_target_enabled(target)
3727 {
3728 return self.webgl_error(InvalidEnum);
3729 }
3730
3731 match mode {
3732 constants::FASTEST | constants::NICEST | constants::DONT_CARE => (),
3733
3734 _ => return self.webgl_error(InvalidEnum),
3735 }
3736
3737 self.send_command(WebGLCommand::Hint(target, mode));
3738 }
3739
3740 fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
3742 buffer.is_some_and(|buf| {
3743 self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_deleted()
3744 })
3745 }
3746
3747 fn IsEnabled(&self, cap: u32) -> bool {
3749 handle_potential_webgl_error!(self, self.capabilities.is_enabled(cap), false)
3750 }
3751
3752 fn IsFramebuffer(&self, frame_buffer: Option<&WebGLFramebuffer>) -> bool {
3754 frame_buffer.is_some_and(|buf| {
3755 self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_deleted()
3756 })
3757 }
3758
3759 fn IsProgram(&self, program: Option<&WebGLProgram>) -> bool {
3761 program.is_some_and(|p| self.validate_ownership(p).is_ok() && !p.is_deleted())
3762 }
3763
3764 fn IsRenderbuffer(&self, render_buffer: Option<&WebGLRenderbuffer>) -> bool {
3766 render_buffer.is_some_and(|buf| {
3767 self.validate_ownership(buf).is_ok() && buf.ever_bound() && !buf.is_deleted()
3768 })
3769 }
3770
3771 fn IsShader(&self, shader: Option<&WebGLShader>) -> bool {
3773 shader.is_some_and(|s| self.validate_ownership(s).is_ok() && !s.is_deleted())
3774 }
3775
3776 fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
3778 texture.is_some_and(|tex| {
3779 self.validate_ownership(tex).is_ok() && tex.target().is_some() && !tex.is_invalid()
3780 })
3781 }
3782
3783 fn LineWidth(&self, width: f32) {
3785 if width.is_nan() || width <= 0f32 {
3786 return self.webgl_error(InvalidValue);
3787 }
3788
3789 self.send_command(WebGLCommand::LineWidth(width))
3790 }
3791
3792 fn PixelStorei(&self, param_name: u32, param_value: i32) {
3796 let mut texture_settings = self.texture_unpacking_settings.get();
3797 match param_name {
3798 constants::UNPACK_FLIP_Y_WEBGL => {
3799 texture_settings.set(TextureUnpacking::FLIP_Y_AXIS, param_value != 0);
3800 },
3801 constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => {
3802 texture_settings.set(TextureUnpacking::PREMULTIPLY_ALPHA, param_value != 0);
3803 },
3804 constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
3805 let convert = match param_value as u32 {
3806 constants::BROWSER_DEFAULT_WEBGL => true,
3807 constants::NONE => false,
3808 _ => return self.webgl_error(InvalidEnum),
3809 };
3810 texture_settings.set(TextureUnpacking::CONVERT_COLORSPACE, convert);
3811 },
3812 constants::UNPACK_ALIGNMENT => {
3813 match param_value {
3814 1 | 2 | 4 | 8 => (),
3815 _ => return self.webgl_error(InvalidValue),
3816 }
3817 self.texture_unpacking_alignment.set(param_value as u32);
3818 return;
3819 },
3820 constants::PACK_ALIGNMENT => {
3821 match param_value {
3822 1 | 2 | 4 | 8 => (),
3823 _ => return self.webgl_error(InvalidValue),
3824 }
3825 self.texture_packing_alignment.set(param_value as u8);
3829 return;
3830 },
3831 _ => return self.webgl_error(InvalidEnum),
3832 }
3833 self.texture_unpacking_settings.set(texture_settings);
3834 }
3835
3836 fn PolygonOffset(&self, factor: f32, units: f32) {
3838 self.send_command(WebGLCommand::PolygonOffset(factor, units))
3839 }
3840
3841 #[allow(unsafe_code)]
3843 fn ReadPixels(
3844 &self,
3845 x: i32,
3846 y: i32,
3847 width: i32,
3848 height: i32,
3849 format: u32,
3850 pixel_type: u32,
3851 mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
3852 ) {
3853 handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
3854
3855 let pixels =
3856 handle_potential_webgl_error!(self, pixels.as_mut().ok_or(InvalidValue), return);
3857
3858 if width < 0 || height < 0 {
3859 return self.webgl_error(InvalidValue);
3860 }
3861
3862 if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
3863 return self.webgl_error(InvalidOperation);
3864 }
3865
3866 if pixels.get_array_type() != Type::Uint8 {
3867 return self.webgl_error(InvalidOperation);
3868 }
3869
3870 let (fb_width, fb_height) = handle_potential_webgl_error!(
3871 self,
3872 self.get_current_framebuffer_size().ok_or(InvalidOperation),
3873 return
3874 );
3875
3876 if width == 0 || height == 0 {
3877 return;
3878 }
3879
3880 let bytes_per_pixel = 4;
3881
3882 let row_len = handle_potential_webgl_error!(
3883 self,
3884 width.checked_mul(bytes_per_pixel).ok_or(InvalidOperation),
3885 return
3886 );
3887
3888 let pack_alignment = self.texture_packing_alignment.get() as i32;
3889 let dest_padding = match row_len % pack_alignment {
3890 0 => 0,
3891 remainder => pack_alignment - remainder,
3892 };
3893 let dest_stride = row_len + dest_padding;
3894
3895 let full_rows_len = handle_potential_webgl_error!(
3896 self,
3897 dest_stride.checked_mul(height - 1).ok_or(InvalidOperation),
3898 return
3899 );
3900 let required_dest_len = handle_potential_webgl_error!(
3901 self,
3902 full_rows_len.checked_add(row_len).ok_or(InvalidOperation),
3903 return
3904 );
3905
3906 let dest = unsafe { pixels.as_mut_slice() };
3907 if dest.len() < required_dest_len as usize {
3908 return self.webgl_error(InvalidOperation);
3909 }
3910
3911 let src_origin = Point2D::new(x, y);
3912 let src_size = Size2D::new(width as u32, height as u32);
3913 let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
3914 let src_rect = match pixels::clip(src_origin, src_size.to_u32(), fb_size.to_u32()) {
3915 Some(rect) => rect,
3916 None => return,
3917 };
3918
3919 let src_rect = src_rect.to_u32();
3923
3924 let mut dest_offset = 0;
3925 if x < 0 {
3926 dest_offset += -x * bytes_per_pixel;
3927 }
3928 if y < 0 {
3929 dest_offset += -y * row_len;
3930 }
3931
3932 let (sender, receiver) = ipc::channel().unwrap();
3933 self.send_command(WebGLCommand::ReadPixels(
3934 src_rect, format, pixel_type, sender,
3935 ));
3936 let (src, _) = receiver.recv().unwrap();
3937
3938 let src_row_len = src_rect.size.width as usize * bytes_per_pixel as usize;
3939 for i in 0..src_rect.size.height {
3940 let dest_start = dest_offset as usize + i as usize * dest_stride as usize;
3941 let dest_end = dest_start + src_row_len;
3942 let src_start = i as usize * src_row_len;
3943 let src_end = src_start + src_row_len;
3944 dest[dest_start..dest_end].copy_from_slice(&src[src_start..src_end]);
3945 }
3946 }
3947
3948 fn SampleCoverage(&self, value: f32, invert: bool) {
3950 self.send_command(WebGLCommand::SampleCoverage(value, invert));
3951 }
3952
3953 fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) {
3955 if width < 0 || height < 0 {
3956 return self.webgl_error(InvalidValue);
3957 }
3958
3959 let width = width as u32;
3960 let height = height as u32;
3961
3962 self.current_scissor.set((x, y, width, height));
3963 self.send_command(WebGLCommand::Scissor(x, y, width, height));
3964 }
3965
3966 fn StencilFunc(&self, func: u32, ref_: i32, mask: u32) {
3968 match func {
3969 constants::NEVER |
3970 constants::LESS |
3971 constants::EQUAL |
3972 constants::LEQUAL |
3973 constants::GREATER |
3974 constants::NOTEQUAL |
3975 constants::GEQUAL |
3976 constants::ALWAYS => self.send_command(WebGLCommand::StencilFunc(func, ref_, mask)),
3977 _ => self.webgl_error(InvalidEnum),
3978 }
3979 }
3980
3981 fn StencilFuncSeparate(&self, face: u32, func: u32, ref_: i32, mask: u32) {
3983 match face {
3984 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
3985 _ => return self.webgl_error(InvalidEnum),
3986 }
3987
3988 match func {
3989 constants::NEVER |
3990 constants::LESS |
3991 constants::EQUAL |
3992 constants::LEQUAL |
3993 constants::GREATER |
3994 constants::NOTEQUAL |
3995 constants::GEQUAL |
3996 constants::ALWAYS => {
3997 self.send_command(WebGLCommand::StencilFuncSeparate(face, func, ref_, mask))
3998 },
3999 _ => self.webgl_error(InvalidEnum),
4000 }
4001 }
4002
4003 fn StencilMask(&self, mask: u32) {
4005 self.send_command(WebGLCommand::StencilMask(mask))
4006 }
4007
4008 fn StencilMaskSeparate(&self, face: u32, mask: u32) {
4010 match face {
4011 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => {
4012 self.send_command(WebGLCommand::StencilMaskSeparate(face, mask))
4013 },
4014 _ => self.webgl_error(InvalidEnum),
4015 };
4016 }
4017
4018 fn StencilOp(&self, fail: u32, zfail: u32, zpass: u32) {
4020 if self.validate_stencil_actions(fail) &&
4021 self.validate_stencil_actions(zfail) &&
4022 self.validate_stencil_actions(zpass)
4023 {
4024 self.send_command(WebGLCommand::StencilOp(fail, zfail, zpass));
4025 } else {
4026 self.webgl_error(InvalidEnum)
4027 }
4028 }
4029
4030 fn StencilOpSeparate(&self, face: u32, fail: u32, zfail: u32, zpass: u32) {
4032 match face {
4033 constants::FRONT | constants::BACK | constants::FRONT_AND_BACK => (),
4034 _ => return self.webgl_error(InvalidEnum),
4035 }
4036
4037 if self.validate_stencil_actions(fail) &&
4038 self.validate_stencil_actions(zfail) &&
4039 self.validate_stencil_actions(zpass)
4040 {
4041 self.send_command(WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass))
4042 } else {
4043 self.webgl_error(InvalidEnum)
4044 }
4045 }
4046
4047 fn LinkProgram(&self, program: &WebGLProgram) {
4049 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4050 if program.is_deleted() {
4051 return self.webgl_error(InvalidValue);
4052 }
4053 handle_potential_webgl_error!(self, program.link());
4054 }
4055
4056 fn ShaderSource(&self, shader: &WebGLShader, source: DOMString) {
4058 handle_potential_webgl_error!(self, self.validate_ownership(shader), return);
4059 shader.set_source(source)
4060 }
4061
4062 fn GetShaderSource(&self, shader: &WebGLShader) -> Option<DOMString> {
4064 handle_potential_webgl_error!(self, self.validate_ownership(shader), return None);
4065 Some(shader.source())
4066 }
4067
4068 fn Uniform1f(&self, location: Option<&WebGLUniformLocation>, val: f32) {
4070 self.with_location(location, |location| {
4071 match location.type_() {
4072 constants::BOOL | constants::FLOAT => {},
4073 _ => return Err(InvalidOperation),
4074 }
4075 self.send_command(WebGLCommand::Uniform1f(location.id(), val));
4076 Ok(())
4077 });
4078 }
4079
4080 fn Uniform1i(&self, location: Option<&WebGLUniformLocation>, val: i32) {
4082 self.with_location(location, |location| {
4083 match location.type_() {
4084 constants::BOOL | constants::INT => {},
4085 constants::SAMPLER_2D |
4086 WebGL2RenderingContextConstants::SAMPLER_3D |
4087 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
4088 constants::SAMPLER_CUBE => {
4089 if val < 0 || val as u32 >= self.limits.max_combined_texture_image_units {
4090 return Err(InvalidValue);
4091 }
4092 },
4093 _ => return Err(InvalidOperation),
4094 }
4095 self.send_command(WebGLCommand::Uniform1i(location.id(), val));
4096 Ok(())
4097 });
4098 }
4099
4100 fn Uniform1iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4102 self.uniform1iv(location, val, 0, 0)
4103 }
4104
4105 fn Uniform1fv(
4107 &self,
4108 location: Option<&WebGLUniformLocation>,
4109 val: Float32ArrayOrUnrestrictedFloatSequence,
4110 ) {
4111 self.uniform1fv(location, val, 0, 0)
4112 }
4113
4114 fn Uniform2f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32) {
4116 self.with_location(location, |location| {
4117 match location.type_() {
4118 constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {},
4119 _ => return Err(InvalidOperation),
4120 }
4121 self.send_command(WebGLCommand::Uniform2f(location.id(), x, y));
4122 Ok(())
4123 });
4124 }
4125
4126 fn Uniform2fv(
4128 &self,
4129 location: Option<&WebGLUniformLocation>,
4130 val: Float32ArrayOrUnrestrictedFloatSequence,
4131 ) {
4132 self.uniform2fv(location, val, 0, 0)
4133 }
4134
4135 fn Uniform2i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32) {
4137 self.with_location(location, |location| {
4138 match location.type_() {
4139 constants::BOOL_VEC2 | constants::INT_VEC2 => {},
4140 _ => return Err(InvalidOperation),
4141 }
4142 self.send_command(WebGLCommand::Uniform2i(location.id(), x, y));
4143 Ok(())
4144 });
4145 }
4146
4147 fn Uniform2iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4149 self.uniform2iv(location, val, 0, 0)
4150 }
4151
4152 fn Uniform3f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32) {
4154 self.with_location(location, |location| {
4155 match location.type_() {
4156 constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {},
4157 _ => return Err(InvalidOperation),
4158 }
4159 self.send_command(WebGLCommand::Uniform3f(location.id(), x, y, z));
4160 Ok(())
4161 });
4162 }
4163
4164 fn Uniform3fv(
4166 &self,
4167 location: Option<&WebGLUniformLocation>,
4168 val: Float32ArrayOrUnrestrictedFloatSequence,
4169 ) {
4170 self.uniform3fv(location, val, 0, 0)
4171 }
4172
4173 fn Uniform3i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32) {
4175 self.with_location(location, |location| {
4176 match location.type_() {
4177 constants::BOOL_VEC3 | constants::INT_VEC3 => {},
4178 _ => return Err(InvalidOperation),
4179 }
4180 self.send_command(WebGLCommand::Uniform3i(location.id(), x, y, z));
4181 Ok(())
4182 });
4183 }
4184
4185 fn Uniform3iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4187 self.uniform3iv(location, val, 0, 0)
4188 }
4189
4190 fn Uniform4i(&self, location: Option<&WebGLUniformLocation>, x: i32, y: i32, z: i32, w: i32) {
4192 self.with_location(location, |location| {
4193 match location.type_() {
4194 constants::BOOL_VEC4 | constants::INT_VEC4 => {},
4195 _ => return Err(InvalidOperation),
4196 }
4197 self.send_command(WebGLCommand::Uniform4i(location.id(), x, y, z, w));
4198 Ok(())
4199 });
4200 }
4201
4202 fn Uniform4iv(&self, location: Option<&WebGLUniformLocation>, val: Int32ArrayOrLongSequence) {
4204 self.uniform4iv(location, val, 0, 0)
4205 }
4206
4207 fn Uniform4f(&self, location: Option<&WebGLUniformLocation>, x: f32, y: f32, z: f32, w: f32) {
4209 self.with_location(location, |location| {
4210 match location.type_() {
4211 constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {},
4212 _ => return Err(InvalidOperation),
4213 }
4214 self.send_command(WebGLCommand::Uniform4f(location.id(), x, y, z, w));
4215 Ok(())
4216 });
4217 }
4218
4219 fn Uniform4fv(
4221 &self,
4222 location: Option<&WebGLUniformLocation>,
4223 val: Float32ArrayOrUnrestrictedFloatSequence,
4224 ) {
4225 self.uniform4fv(location, val, 0, 0)
4226 }
4227
4228 fn UniformMatrix2fv(
4230 &self,
4231 location: Option<&WebGLUniformLocation>,
4232 transpose: bool,
4233 val: Float32ArrayOrUnrestrictedFloatSequence,
4234 ) {
4235 self.uniform_matrix_2fv(location, transpose, val, 0, 0)
4236 }
4237
4238 fn UniformMatrix3fv(
4240 &self,
4241 location: Option<&WebGLUniformLocation>,
4242 transpose: bool,
4243 val: Float32ArrayOrUnrestrictedFloatSequence,
4244 ) {
4245 self.uniform_matrix_3fv(location, transpose, val, 0, 0)
4246 }
4247
4248 fn UniformMatrix4fv(
4250 &self,
4251 location: Option<&WebGLUniformLocation>,
4252 transpose: bool,
4253 val: Float32ArrayOrUnrestrictedFloatSequence,
4254 ) {
4255 self.uniform_matrix_4fv(location, transpose, val, 0, 0)
4256 }
4257
4258 #[allow(unsafe_code)]
4260 fn GetUniform(
4261 &self,
4262 cx: SafeJSContext,
4263 program: &WebGLProgram,
4264 location: &WebGLUniformLocation,
4265 mut rval: MutableHandleValue,
4266 ) {
4267 handle_potential_webgl_error!(
4268 self,
4269 self.uniform_check_program(program, location),
4270 return rval.set(NullValue())
4271 );
4272
4273 let triple = (self, program.id(), location.id());
4274
4275 match location.type_() {
4276 constants::BOOL => rval.set(BooleanValue(uniform_get(
4277 triple,
4278 WebGLCommand::GetUniformBool,
4279 ))),
4280 constants::BOOL_VEC2 => {
4281 uniform_get(triple, WebGLCommand::GetUniformBool2).safe_to_jsval(cx, rval)
4282 },
4283 constants::BOOL_VEC3 => {
4284 uniform_get(triple, WebGLCommand::GetUniformBool3).safe_to_jsval(cx, rval)
4285 },
4286 constants::BOOL_VEC4 => {
4287 uniform_get(triple, WebGLCommand::GetUniformBool4).safe_to_jsval(cx, rval)
4288 },
4289 constants::INT |
4290 constants::SAMPLER_2D |
4291 constants::SAMPLER_CUBE |
4292 WebGL2RenderingContextConstants::SAMPLER_2D_ARRAY |
4293 WebGL2RenderingContextConstants::SAMPLER_3D => {
4294 rval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
4295 },
4296 constants::INT_VEC2 => unsafe {
4297 uniform_typed::<Int32>(
4298 *cx,
4299 &uniform_get(triple, WebGLCommand::GetUniformInt2),
4300 rval,
4301 )
4302 },
4303 constants::INT_VEC3 => unsafe {
4304 uniform_typed::<Int32>(
4305 *cx,
4306 &uniform_get(triple, WebGLCommand::GetUniformInt3),
4307 rval,
4308 )
4309 },
4310 constants::INT_VEC4 => unsafe {
4311 uniform_typed::<Int32>(
4312 *cx,
4313 &uniform_get(triple, WebGLCommand::GetUniformInt4),
4314 rval,
4315 )
4316 },
4317 constants::FLOAT => rval
4318 .set(DoubleValue(
4319 uniform_get(triple, WebGLCommand::GetUniformFloat) as f64,
4320 )),
4321 constants::FLOAT_VEC2 => unsafe {
4322 uniform_typed::<Float32>(
4323 *cx,
4324 &uniform_get(triple, WebGLCommand::GetUniformFloat2),
4325 rval,
4326 )
4327 },
4328 constants::FLOAT_VEC3 => unsafe {
4329 uniform_typed::<Float32>(
4330 *cx,
4331 &uniform_get(triple, WebGLCommand::GetUniformFloat3),
4332 rval,
4333 )
4334 },
4335 constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe {
4336 uniform_typed::<Float32>(
4337 *cx,
4338 &uniform_get(triple, WebGLCommand::GetUniformFloat4),
4339 rval,
4340 )
4341 },
4342 constants::FLOAT_MAT3 => unsafe {
4343 uniform_typed::<Float32>(
4344 *cx,
4345 &uniform_get(triple, WebGLCommand::GetUniformFloat9),
4346 rval,
4347 )
4348 },
4349 constants::FLOAT_MAT4 => unsafe {
4350 uniform_typed::<Float32>(
4351 *cx,
4352 &uniform_get(triple, WebGLCommand::GetUniformFloat16),
4353 rval,
4354 )
4355 },
4356 _ => panic!("wrong uniform type"),
4357 }
4358 }
4359
4360 fn UseProgram(&self, program: Option<&WebGLProgram>) {
4362 if let Some(program) = program {
4363 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4364 if program.is_deleted() || !program.is_linked() {
4365 return self.webgl_error(InvalidOperation);
4366 }
4367 if program.is_in_use() {
4368 return;
4369 }
4370 program.in_use(true);
4371 }
4372 match self.current_program.get() {
4373 Some(ref current) if program != Some(&**current) => current.in_use(false),
4374 _ => {},
4375 }
4376 self.send_command(WebGLCommand::UseProgram(program.map(|p| p.id())));
4377 self.current_program.set(program);
4378 }
4379
4380 fn ValidateProgram(&self, program: &WebGLProgram) {
4382 handle_potential_webgl_error!(self, self.validate_ownership(program), return);
4383 if let Err(e) = program.validate() {
4384 self.webgl_error(e);
4385 }
4386 }
4387
4388 fn VertexAttrib1f(&self, indx: u32, x: f32) {
4390 self.vertex_attrib(indx, x, 0f32, 0f32, 1f32)
4391 }
4392
4393 fn VertexAttrib1fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4395 let values = match v {
4396 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4397 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4398 };
4399 if values.is_empty() {
4400 return self.webgl_error(InvalidValue);
4402 }
4403 self.vertex_attrib(indx, values[0], 0f32, 0f32, 1f32);
4404 }
4405
4406 fn VertexAttrib2f(&self, indx: u32, x: f32, y: f32) {
4408 self.vertex_attrib(indx, x, y, 0f32, 1f32)
4409 }
4410
4411 fn VertexAttrib2fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4413 let values = match v {
4414 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4415 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4416 };
4417 if values.len() < 2 {
4418 return self.webgl_error(InvalidValue);
4420 }
4421 self.vertex_attrib(indx, values[0], values[1], 0f32, 1f32);
4422 }
4423
4424 fn VertexAttrib3f(&self, indx: u32, x: f32, y: f32, z: f32) {
4426 self.vertex_attrib(indx, x, y, z, 1f32)
4427 }
4428
4429 fn VertexAttrib3fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4431 let values = match v {
4432 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4433 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4434 };
4435 if values.len() < 3 {
4436 return self.webgl_error(InvalidValue);
4438 }
4439 self.vertex_attrib(indx, values[0], values[1], values[2], 1f32);
4440 }
4441
4442 fn VertexAttrib4f(&self, indx: u32, x: f32, y: f32, z: f32, w: f32) {
4444 self.vertex_attrib(indx, x, y, z, w)
4445 }
4446
4447 fn VertexAttrib4fv(&self, indx: u32, v: Float32ArrayOrUnrestrictedFloatSequence) {
4449 let values = match v {
4450 Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
4451 Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
4452 };
4453 if values.len() < 4 {
4454 return self.webgl_error(InvalidValue);
4456 }
4457 self.vertex_attrib(indx, values[0], values[1], values[2], values[3]);
4458 }
4459
4460 fn VertexAttribPointer(
4462 &self,
4463 index: u32,
4464 size: i32,
4465 type_: u32,
4466 normalized: bool,
4467 stride: i32,
4468 offset: i64,
4469 ) {
4470 let res = match self.webgl_version() {
4471 WebGLVersion::WebGL1 => self
4472 .current_vao()
4473 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
4474 WebGLVersion::WebGL2 => self
4475 .current_vao_webgl2()
4476 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
4477 };
4478 handle_potential_webgl_error!(self, res);
4479 }
4480
4481 fn Viewport(&self, x: i32, y: i32, width: i32, height: i32) {
4483 if width < 0 || height < 0 {
4484 return self.webgl_error(InvalidValue);
4485 }
4486
4487 self.send_command(WebGLCommand::SetViewport(x, y, width, height))
4488 }
4489
4490 #[allow(unsafe_code)]
4492 fn TexImage2D(
4493 &self,
4494 target: u32,
4495 level: i32,
4496 internal_format: i32,
4497 width: i32,
4498 height: i32,
4499 border: i32,
4500 format: u32,
4501 data_type: u32,
4502 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
4503 ) -> ErrorResult {
4504 if !self.extension_manager.is_tex_type_enabled(data_type) {
4505 self.webgl_error(InvalidEnum);
4506 return Ok(());
4507 }
4508
4509 let validator = TexImage2DValidator::new(
4510 self,
4511 target,
4512 level,
4513 internal_format as u32,
4514 width,
4515 height,
4516 border,
4517 format,
4518 data_type,
4519 );
4520
4521 let TexImage2DValidatorResult {
4522 texture,
4523 target,
4524 width,
4525 height,
4526 level,
4527 border,
4528 internal_format,
4529 format,
4530 data_type,
4531 } = match validator.validate() {
4532 Ok(result) => result,
4533 Err(_) => return Ok(()), };
4535
4536 if !internal_format.compatible_data_types().contains(&data_type) {
4537 return {
4538 self.webgl_error(InvalidOperation);
4539 Ok(())
4540 };
4541 }
4542 if texture.is_immutable() {
4543 return {
4544 self.webgl_error(InvalidOperation);
4545 Ok(())
4546 };
4547 }
4548
4549 let unpacking_alignment = self.texture_unpacking_alignment.get();
4550
4551 let expected_byte_length = match self.validate_tex_image_2d_data(
4552 width,
4553 height,
4554 format,
4555 data_type,
4556 unpacking_alignment,
4557 pixels.as_ref(),
4558 ) {
4559 Ok(byte_length) => byte_length,
4560 Err(()) => return Ok(()),
4561 };
4562
4563 let buff = match *pixels {
4566 None => IpcSharedMemory::from_bytes(&vec![0u8; expected_byte_length as usize]),
4567 Some(ref data) => IpcSharedMemory::from_bytes(unsafe { data.as_slice() }),
4568 };
4569
4570 if buff.len() < expected_byte_length as usize {
4577 return {
4578 self.webgl_error(InvalidOperation);
4579 Ok(())
4580 };
4581 }
4582
4583 let size = Size2D::new(width, height);
4584
4585 if !self.validate_filterable_texture(
4586 &texture,
4587 target,
4588 level,
4589 internal_format,
4590 size,
4591 data_type,
4592 ) {
4593 return Ok(());
4596 }
4597
4598 let size = Size2D::new(width, height);
4599
4600 let (alpha_treatment, y_axis_treatment) =
4601 self.get_current_unpack_state(Alpha::NotPremultiplied);
4602
4603 self.tex_image_2d(
4604 &texture,
4605 target,
4606 data_type,
4607 internal_format,
4608 format,
4609 level,
4610 border,
4611 unpacking_alignment,
4612 size,
4613 TexSource::Pixels(TexPixels::from_array(
4614 buff,
4615 size,
4616 alpha_treatment,
4617 y_axis_treatment,
4618 )),
4619 );
4620
4621 Ok(())
4622 }
4623
4624 fn TexImage2D_(
4626 &self,
4627 target: u32,
4628 level: i32,
4629 internal_format: i32,
4630 format: u32,
4631 data_type: u32,
4632 source: TexImageSource,
4633 ) -> ErrorResult {
4634 if !self.extension_manager.is_tex_type_enabled(data_type) {
4635 self.webgl_error(InvalidEnum);
4636 return Ok(());
4637 }
4638
4639 let pixels = match self.get_image_pixels(source)? {
4640 Some(pixels) => pixels,
4641 None => return Ok(()),
4642 };
4643
4644 let validator = TexImage2DValidator::new(
4645 self,
4646 target,
4647 level,
4648 internal_format as u32,
4649 pixels.size().width as i32,
4650 pixels.size().height as i32,
4651 0,
4652 format,
4653 data_type,
4654 );
4655
4656 let TexImage2DValidatorResult {
4657 texture,
4658 target,
4659 level,
4660 border,
4661 internal_format,
4662 format,
4663 data_type,
4664 ..
4665 } = match validator.validate() {
4666 Ok(result) => result,
4667 Err(_) => return Ok(()), };
4669
4670 if !internal_format.compatible_data_types().contains(&data_type) {
4671 return {
4672 self.webgl_error(InvalidOperation);
4673 Ok(())
4674 };
4675 }
4676 if texture.is_immutable() {
4677 return {
4678 self.webgl_error(InvalidOperation);
4679 Ok(())
4680 };
4681 }
4682
4683 if !self.validate_filterable_texture(
4684 &texture,
4685 target,
4686 level,
4687 internal_format,
4688 pixels.size(),
4689 data_type,
4690 ) {
4691 return Ok(());
4694 }
4695
4696 self.tex_image_2d(
4697 &texture,
4698 target,
4699 data_type,
4700 internal_format,
4701 format,
4702 level,
4703 border,
4704 1,
4705 pixels.size(),
4706 TexSource::Pixels(pixels),
4707 );
4708 Ok(())
4709 }
4710
4711 #[allow(unsafe_code)]
4713 fn TexSubImage2D(
4714 &self,
4715 target: u32,
4716 level: i32,
4717 xoffset: i32,
4718 yoffset: i32,
4719 width: i32,
4720 height: i32,
4721 format: u32,
4722 data_type: u32,
4723 pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
4724 ) -> ErrorResult {
4725 let validator = TexImage2DValidator::new(
4726 self, target, level, format, width, height, 0, format, data_type,
4727 );
4728 let TexImage2DValidatorResult {
4729 texture,
4730 target,
4731 width,
4732 height,
4733 level,
4734 format,
4735 data_type,
4736 ..
4737 } = match validator.validate() {
4738 Ok(result) => result,
4739 Err(_) => return Ok(()), };
4741
4742 let unpacking_alignment = self.texture_unpacking_alignment.get();
4743
4744 let expected_byte_length = match self.validate_tex_image_2d_data(
4745 width,
4746 height,
4747 format,
4748 data_type,
4749 unpacking_alignment,
4750 pixels.as_ref(),
4751 ) {
4752 Ok(byte_length) => byte_length,
4753 Err(()) => return Ok(()),
4754 };
4755
4756 let buff = handle_potential_webgl_error!(
4757 self,
4758 pixels
4759 .as_ref()
4760 .map(|p| IpcSharedMemory::from_bytes(unsafe { p.as_slice() }))
4761 .ok_or(InvalidValue),
4762 return Ok(())
4763 );
4764
4765 if buff.len() < expected_byte_length as usize {
4772 return {
4773 self.webgl_error(InvalidOperation);
4774 Ok(())
4775 };
4776 }
4777
4778 let (alpha_treatment, y_axis_treatment) =
4779 self.get_current_unpack_state(Alpha::NotPremultiplied);
4780
4781 self.tex_sub_image_2d(
4782 texture,
4783 target,
4784 level,
4785 xoffset,
4786 yoffset,
4787 format,
4788 data_type,
4789 unpacking_alignment,
4790 TexPixels::from_array(
4791 buff,
4792 Size2D::new(width, height),
4793 alpha_treatment,
4794 y_axis_treatment,
4795 ),
4796 );
4797 Ok(())
4798 }
4799
4800 fn TexSubImage2D_(
4802 &self,
4803 target: u32,
4804 level: i32,
4805 xoffset: i32,
4806 yoffset: i32,
4807 format: u32,
4808 data_type: u32,
4809 source: TexImageSource,
4810 ) -> ErrorResult {
4811 let pixels = match self.get_image_pixels(source)? {
4812 Some(pixels) => pixels,
4813 None => return Ok(()),
4814 };
4815
4816 let validator = TexImage2DValidator::new(
4817 self,
4818 target,
4819 level,
4820 format,
4821 pixels.size().width as i32,
4822 pixels.size().height as i32,
4823 0,
4824 format,
4825 data_type,
4826 );
4827 let TexImage2DValidatorResult {
4828 texture,
4829 target,
4830 level,
4831 format,
4832 data_type,
4833 ..
4834 } = match validator.validate() {
4835 Ok(result) => result,
4836 Err(_) => return Ok(()), };
4838
4839 self.tex_sub_image_2d(
4840 texture, target, level, xoffset, yoffset, format, data_type, 1, pixels,
4841 );
4842 Ok(())
4843 }
4844
4845 fn TexParameterf(&self, target: u32, name: u32, value: f32) {
4847 self.tex_parameter(target, name, TexParameterValue::Float(value))
4848 }
4849
4850 fn TexParameteri(&self, target: u32, name: u32, value: i32) {
4852 self.tex_parameter(target, name, TexParameterValue::Int(value))
4853 }
4854
4855 fn CheckFramebufferStatus(&self, target: u32) -> u32 {
4857 if target != constants::FRAMEBUFFER {
4863 self.webgl_error(InvalidEnum);
4864 return 0;
4865 }
4866
4867 match self.bound_draw_framebuffer.get() {
4868 Some(fb) => fb.check_status(),
4869 None => constants::FRAMEBUFFER_COMPLETE,
4870 }
4871 }
4872
4873 fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
4875 self.renderbuffer_storage(target, 0, internal_format, width, height)
4876 }
4877
4878 fn FramebufferRenderbuffer(
4880 &self,
4881 target: u32,
4882 attachment: u32,
4883 renderbuffertarget: u32,
4884 rb: Option<&WebGLRenderbuffer>,
4885 ) {
4886 if let Some(rb) = rb {
4887 handle_potential_webgl_error!(self, self.validate_ownership(rb), return);
4888 }
4889
4890 if target != constants::FRAMEBUFFER || renderbuffertarget != constants::RENDERBUFFER {
4891 return self.webgl_error(InvalidEnum);
4892 }
4893
4894 match self.bound_draw_framebuffer.get() {
4895 Some(fb) => handle_potential_webgl_error!(self, fb.renderbuffer(attachment, rb)),
4896 None => self.webgl_error(InvalidOperation),
4897 };
4898 }
4899
4900 fn FramebufferTexture2D(
4902 &self,
4903 target: u32,
4904 attachment: u32,
4905 textarget: u32,
4906 texture: Option<&WebGLTexture>,
4907 level: i32,
4908 ) {
4909 if let Some(texture) = texture {
4910 handle_potential_webgl_error!(self, self.validate_ownership(texture), return);
4911 }
4912
4913 if target != constants::FRAMEBUFFER {
4914 return self.webgl_error(InvalidEnum);
4915 }
4916
4917 if level != 0 {
4923 return self.webgl_error(InvalidValue);
4924 }
4925
4926 match self.bound_draw_framebuffer.get() {
4927 Some(fb) => handle_potential_webgl_error!(
4928 self,
4929 fb.texture2d(attachment, textarget, texture, level)
4930 ),
4931 None => self.webgl_error(InvalidOperation),
4932 };
4933 }
4934
4935 fn GetAttachedShaders(&self, program: &WebGLProgram) -> Option<Vec<DomRoot<WebGLShader>>> {
4937 handle_potential_webgl_error!(self, self.validate_ownership(program), return None);
4938 handle_potential_webgl_error!(self, program.attached_shaders().map(Some), None)
4939 }
4940
4941 #[cfg(feature = "webxr")]
4943 fn MakeXRCompatible(&self, can_gc: CanGc) -> Rc<Promise> {
4944 let p = Promise::new(&self.global(), can_gc);
4946 p.resolve_native(&(), can_gc);
4947 p
4948 }
4949}
4950
4951impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> {
4952 fn canvas_data_source(self) -> Option<ImageKey> {
4953 (*self.unsafe_get()).layout_handle()
4954 }
4955}
4956
4957#[derive(Default, JSTraceable, MallocSizeOf)]
4958struct Capabilities {
4959 value: Cell<CapFlags>,
4960}
4961
4962impl Capabilities {
4963 fn set(&self, cap: u32, set: bool) -> WebGLResult<bool> {
4964 let cap = CapFlags::from_enum(cap)?;
4965 let mut value = self.value.get();
4966 if value.contains(cap) == set {
4967 return Ok(false);
4968 }
4969 value.set(cap, set);
4970 self.value.set(value);
4971 Ok(true)
4972 }
4973
4974 fn is_enabled(&self, cap: u32) -> WebGLResult<bool> {
4975 Ok(self.value.get().contains(CapFlags::from_enum(cap)?))
4976 }
4977}
4978
4979impl Default for CapFlags {
4980 fn default() -> Self {
4981 CapFlags::DITHER
4982 }
4983}
4984
4985macro_rules! capabilities {
4986 ($name:ident, $next:ident, $($rest:ident,)*) => {
4987 capabilities!($name, $next, $($rest,)* [$name = 1;]);
4988 };
4989 ($prev:ident, $name:ident, $($rest:ident,)* [$($tt:tt)*]) => {
4990 capabilities!($name, $($rest,)* [$($tt)* $name = Self::$prev.bits() << 1;]);
4991 };
4992 ($prev:ident, [$($name:ident = $value:expr;)*]) => {
4993 #[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
4994 pub(crate) struct CapFlags(u16);
4995
4996 bitflags! {
4997 impl CapFlags: u16 {
4998 $(const $name = $value;)*
4999 }
5000 }
5001
5002 impl CapFlags {
5003 fn from_enum(cap: u32) -> WebGLResult<Self> {
5004 match cap {
5005 $(constants::$name => Ok(Self::$name),)*
5006 _ => Err(InvalidEnum),
5007 }
5008 }
5009 }
5010 };
5011}
5012
5013capabilities! {
5014 BLEND,
5015 CULL_FACE,
5016 DEPTH_TEST,
5017 DITHER,
5018 POLYGON_OFFSET_FILL,
5019 SAMPLE_ALPHA_TO_COVERAGE,
5020 SAMPLE_COVERAGE,
5021 SCISSOR_TEST,
5022 STENCIL_TEST,
5023}
5024
5025#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
5026#[derive(JSTraceable, MallocSizeOf)]
5027pub(crate) struct Textures {
5028 active_unit: Cell<u32>,
5029 units: Box<[TextureUnit]>,
5030}
5031
5032impl Textures {
5033 fn new(max_combined_textures: u32) -> Self {
5034 Self {
5035 active_unit: Default::default(),
5036 units: (0..max_combined_textures)
5037 .map(|_| Default::default())
5038 .collect::<Vec<_>>()
5039 .into(),
5040 }
5041 }
5042
5043 pub(crate) fn active_unit_enum(&self) -> u32 {
5044 self.active_unit.get() + constants::TEXTURE0
5045 }
5046
5047 fn set_active_unit_enum(&self, index: u32) -> WebGLResult<()> {
5048 if index < constants::TEXTURE0 || (index - constants::TEXTURE0) as usize > self.units.len()
5049 {
5050 return Err(InvalidEnum);
5051 }
5052 self.active_unit.set(index - constants::TEXTURE0);
5053 Ok(())
5054 }
5055
5056 pub(crate) fn active_texture_slot(
5057 &self,
5058 target: u32,
5059 webgl_version: WebGLVersion,
5060 ) -> WebGLResult<&MutNullableDom<WebGLTexture>> {
5061 let active_unit = self.active_unit();
5062 let is_webgl2 = webgl_version == WebGLVersion::WebGL2;
5063 match target {
5064 constants::TEXTURE_2D => Ok(&active_unit.tex_2d),
5065 constants::TEXTURE_CUBE_MAP => Ok(&active_unit.tex_cube_map),
5066 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY if is_webgl2 => {
5067 Ok(&active_unit.tex_2d_array)
5068 },
5069 WebGL2RenderingContextConstants::TEXTURE_3D if is_webgl2 => Ok(&active_unit.tex_3d),
5070 _ => Err(InvalidEnum),
5071 }
5072 }
5073
5074 pub(crate) fn active_texture_for_image_target(
5075 &self,
5076 target: TexImageTarget,
5077 ) -> Option<DomRoot<WebGLTexture>> {
5078 let active_unit = self.active_unit();
5079 match target {
5080 TexImageTarget::Texture2D => active_unit.tex_2d.get(),
5081 TexImageTarget::Texture2DArray => active_unit.tex_2d_array.get(),
5082 TexImageTarget::Texture3D => active_unit.tex_3d.get(),
5083 TexImageTarget::CubeMap |
5084 TexImageTarget::CubeMapPositiveX |
5085 TexImageTarget::CubeMapNegativeX |
5086 TexImageTarget::CubeMapPositiveY |
5087 TexImageTarget::CubeMapNegativeY |
5088 TexImageTarget::CubeMapPositiveZ |
5089 TexImageTarget::CubeMapNegativeZ => active_unit.tex_cube_map.get(),
5090 }
5091 }
5092
5093 fn active_unit(&self) -> &TextureUnit {
5094 &self.units[self.active_unit.get() as usize]
5095 }
5096
5097 fn iter(&self) -> impl Iterator<Item = (u32, &TextureUnit)> {
5098 self.units
5099 .iter()
5100 .enumerate()
5101 .map(|(index, unit)| (index as u32 + constants::TEXTURE0, unit))
5102 }
5103}
5104
5105#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
5106#[derive(Default, JSTraceable, MallocSizeOf)]
5107struct TextureUnit {
5108 tex_2d: MutNullableDom<WebGLTexture>,
5109 tex_cube_map: MutNullableDom<WebGLTexture>,
5110 tex_2d_array: MutNullableDom<WebGLTexture>,
5111 tex_3d: MutNullableDom<WebGLTexture>,
5112}
5113
5114impl TextureUnit {
5115 fn unbind(&self, texture: &WebGLTexture) -> Option<u32> {
5116 let fields = [
5117 (&self.tex_2d, constants::TEXTURE_2D),
5118 (&self.tex_cube_map, constants::TEXTURE_CUBE_MAP),
5119 (
5120 &self.tex_2d_array,
5121 WebGL2RenderingContextConstants::TEXTURE_2D_ARRAY,
5122 ),
5123 (&self.tex_3d, WebGL2RenderingContextConstants::TEXTURE_3D),
5124 ];
5125 for &(slot, target) in &fields {
5126 if slot.get().is_some_and(|t| texture == &*t) {
5127 slot.set(None);
5128 return Some(target);
5129 }
5130 }
5131 None
5132 }
5133}
5134
5135pub(crate) struct TexPixels {
5136 data: IpcSharedMemory,
5137 size: Size2D<u32>,
5138 pixel_format: Option<PixelFormat>,
5139 alpha_treatment: Option<AlphaTreatment>,
5140 y_axis_treatment: YAxisTreatment,
5141}
5142
5143impl TexPixels {
5144 fn new(
5145 data: IpcSharedMemory,
5146 size: Size2D<u32>,
5147 pixel_format: PixelFormat,
5148 alpha_treatment: Option<AlphaTreatment>,
5149 y_axis_treatment: YAxisTreatment,
5150 ) -> Self {
5151 Self {
5152 data,
5153 size,
5154 pixel_format: Some(pixel_format),
5155 alpha_treatment,
5156 y_axis_treatment,
5157 }
5158 }
5159
5160 pub(crate) fn from_array(
5161 data: IpcSharedMemory,
5162 size: Size2D<u32>,
5163 alpha_treatment: Option<AlphaTreatment>,
5164 y_axis_treatment: YAxisTreatment,
5165 ) -> Self {
5166 Self {
5167 data,
5168 size,
5169 pixel_format: None,
5170 alpha_treatment,
5171 y_axis_treatment,
5172 }
5173 }
5174
5175 pub(crate) fn size(&self) -> Size2D<u32> {
5176 self.size
5177 }
5178
5179 pub(crate) fn pixel_format(&self) -> Option<PixelFormat> {
5180 self.pixel_format
5181 }
5182
5183 pub(crate) fn alpha_treatment(&self) -> Option<AlphaTreatment> {
5184 self.alpha_treatment
5185 }
5186
5187 pub(crate) fn y_axis_treatment(&self) -> YAxisTreatment {
5188 self.y_axis_treatment
5189 }
5190
5191 pub(crate) fn into_shared_memory(self) -> IpcSharedMemory {
5192 self.data
5193 }
5194}
5195
5196pub(crate) enum TexSource {
5197 Pixels(TexPixels),
5198 BufferOffset(i64),
5199}
5200
5201#[derive(JSTraceable)]
5202pub(crate) struct WebGLCommandSender {
5203 #[no_trace]
5204 sender: WebGLChan,
5205}
5206
5207impl WebGLCommandSender {
5208 pub(crate) fn new(sender: WebGLChan) -> WebGLCommandSender {
5209 WebGLCommandSender { sender }
5210 }
5211
5212 pub(crate) fn send(&self, msg: WebGLMsg) -> WebGLSendResult {
5213 self.sender.send(msg)
5214 }
5215}
5216
5217#[derive(JSTraceable, MallocSizeOf)]
5218pub(crate) struct WebGLMessageSender {
5219 #[no_trace]
5220 sender: WebGLMsgSender,
5221}
5222
5223impl Clone for WebGLMessageSender {
5224 fn clone(&self) -> WebGLMessageSender {
5225 WebGLMessageSender {
5226 sender: self.sender.clone(),
5227 }
5228 }
5229}
5230
5231impl WebGLMessageSender {
5232 pub(crate) fn new(sender: WebGLMsgSender) -> WebGLMessageSender {
5233 WebGLMessageSender { sender }
5234 }
5235
5236 pub(crate) fn context_id(&self) -> WebGLContextId {
5237 self.sender.context_id()
5238 }
5239
5240 pub(crate) fn send(
5241 &self,
5242 msg: WebGLCommand,
5243 backtrace: WebGLCommandBacktrace,
5244 ) -> WebGLSendResult {
5245 self.sender.send(msg, backtrace)
5246 }
5247
5248 pub(crate) fn send_resize(
5249 &self,
5250 size: Size2D<u32>,
5251 sender: WebGLSender<Result<(), String>>,
5252 ) -> WebGLSendResult {
5253 self.sender.send_resize(size, sender)
5254 }
5255
5256 pub(crate) fn send_remove(&self) -> WebGLSendResult {
5257 self.sender.send_remove()
5258 }
5259}
5260
5261fn array_buffer_type_to_sized_type(type_: Type) -> Option<SizedDataType> {
5262 match type_ {
5263 Type::Uint8 | Type::Uint8Clamped => Some(SizedDataType::Uint8),
5264 Type::Uint16 => Some(SizedDataType::Uint16),
5265 Type::Uint32 => Some(SizedDataType::Uint32),
5266 Type::Int8 => Some(SizedDataType::Int8),
5267 Type::Int16 => Some(SizedDataType::Int16),
5268 Type::Int32 => Some(SizedDataType::Int32),
5269 Type::Float32 => Some(SizedDataType::Float32),
5270 Type::Float16 |
5271 Type::Float64 |
5272 Type::BigInt64 |
5273 Type::BigUint64 |
5274 Type::MaxTypedArrayViewType |
5275 Type::Int64 |
5276 Type::Simd128 => None,
5277 }
5278}