/* * Copyright (c) 2024-2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Web::WebGL { static constexpr int UNPACK_FLIP_Y_WEBGL = 0x9240; // NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly. using TexImageSource = Variant, GC::Root, GC::Root, GC::Root, GC::Root, GC::Root>; // FIXME: This object should inherit from Bindings::PlatformObject and implement the WebGLRenderingContextBase IDL interface. // We should make WebGL code generator to produce implementation for this interface. class WebGLRenderingContextBase { public: using Float32List = Variant, Vector>; using Int32List = Variant, Vector>; using Uint32List = Variant, Vector>; virtual GC::Cell const* gc_cell() const = 0; virtual void visit_edges(JS::Cell::Visitor&) = 0; virtual OpenGLContext& context() = 0; virtual bool ext_texture_filter_anisotropic_extension_enabled() const = 0; template static ErrorOr> get_offset_span(Span src_span, WebIDL::UnsignedLongLong src_offset, WebIDL::UnsignedLong src_length_override = 0) { Checked length = src_offset; length += src_length_override; if (length.has_overflow() || length.value_unchecked() > src_span.size()) [[unlikely]] return Error::from_errno(EINVAL); if (src_length_override == 0) return src_span.slice(src_offset, src_span.size() - src_offset); return src_span.slice(src_offset, src_length_override); } template static ErrorOr> get_offset_span(GC::Ref src_data, WebIDL::UnsignedLongLong src_offset, WebIDL::UnsignedLong src_length_override = 0) { auto buffer_size = src_data->byte_length(); if (buffer_size % sizeof(T) != 0) [[unlikely]] return Error::from_errno(EINVAL); auto raw_object = src_data->raw_object(); if (auto* array_buffer = as_if(*raw_object)) { return TRY(get_offset_span(array_buffer->buffer().span(), src_offset, src_length_override)).reinterpret(); } if (auto* data_view = as_if(*raw_object)) { return TRY(get_offset_span(data_view->viewed_array_buffer()->buffer().span(), src_offset, src_length_override)).reinterpret(); } // NOTE: This has to be done because src_offset is the number of elements to offset by, not the number of bytes. #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, Type) \ if (auto* typed_array = as_if(*raw_object)) { \ return TRY(get_offset_span(typed_array->data(), src_offset, src_length_override)).reinterpret(); \ } JS_ENUMERATE_TYPED_ARRAYS #undef __JS_ENUMERATE VERIFY_NOT_REACHED(); } static ErrorOr> span_from_float32_list(Float32List& float32_list, WebIDL::UnsignedLongLong src_offset, WebIDL::UnsignedLong src_length_override = 0) { if (float32_list.has>()) { auto& vector = float32_list.get>(); return get_offset_span(vector.span(), src_offset, src_length_override); } auto& buffer = float32_list.get>(); return get_offset_span(buffer->data(), src_offset, src_length_override); } static ErrorOr> span_from_int32_list(Int32List& int32_list, WebIDL::UnsignedLongLong src_offset, WebIDL::UnsignedLong src_length_override = 0) { if (int32_list.has>()) { auto& vector = int32_list.get>(); return get_offset_span(vector.span(), src_offset, src_length_override); } auto& buffer = int32_list.get>(); return get_offset_span(buffer->data(), src_offset, src_length_override); } static ErrorOr> span_from_uint32_list(Uint32List& uint32_list, WebIDL::UnsignedLongLong src_offset, WebIDL::UnsignedLong src_length_override = 0) { if (uint32_list.has>()) { auto& vector = uint32_list.get>(); return get_offset_span(vector.span(), src_offset, src_length_override); } auto& buffer = uint32_list.get>(); return get_offset_span(buffer->data(), src_offset, src_length_override); } struct ConvertedTexture { ByteBuffer buffer; int width { 0 }; int height { 0 }; }; Optional read_and_pixel_convert_texture_image_source(TexImageSource const& source, WebIDL::UnsignedLong format, WebIDL::UnsignedLong type, Optional destination_width = OptionalNone {}, Optional destination_height = OptionalNone {}); protected: // UNPACK_FLIP_Y_WEBGL of type boolean // If set, then during any subsequent calls to texImage2D or texSubImage2D, the source data is flipped along // the vertical axis, so that conceptually the last row is the first one transferred. The initial value is false. // Any non-zero value is interpreted as true. bool m_unpack_flip_y { false }; }; }