#include <AK/String.h>
#include <AK/TypeCasts.h>
#include <AK/Variant.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/DOMMatrix.h>
#include <LibWeb/Bindings/DOMMatrixReadOnly.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Geometry/DOMMatrix.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Tracing.h>

namespace Web::Bindings {

void DOMMatrixConstructor::initialize(JS::Realm& realm, JS::NativeFunction& object)
{
    auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;

    object.set_prototype(&ensure_web_constructor<DOMMatrixReadOnlyPrototype>(realm, "DOMMatrixReadOnly"_fly_string));
    object.define_direct_property(vm.names.length, JS::Value(0), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "DOMMatrix"_utf16), JS::Attribute::Configurable);
    object.define_direct_property(vm.names.prototype, &ensure_web_prototype<DOMMatrixPrototype>(realm, "DOMMatrix"_fly_string), 0);
    object.define_native_function(realm, "fromMatrix"_utf16_fly_string, from_matrix, 0, JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable);

    object.define_native_function(realm, "fromFloat32Array"_utf16_fly_string, from_float32_array, 1, JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable);

    object.define_native_function(realm, "fromFloat64Array"_utf16_fly_string, from_float64_array, 1, JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable);

}

JS::ThrowCompletionOr<GC::Ref<JS::Object>> DOMMatrixConstructor::construct([[maybe_unused]] InterfaceConstructor& constructor, [[maybe_unused]] JS::FunctionObject& new_target)
{
    WebIDL::log_trace(constructor.vm(), "DOMMatrixConstructor::construct");
    auto& vm = constructor.vm();
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // To internally create a new object implementing the interface DOMMatrix:

    // 3.2. Let prototype be ? Get(newTarget, "prototype").
    auto prototype = TRY(new_target.get(vm.names.prototype));

    // 3.3. If Type(prototype) is not Object, then:
    if (!prototype.is_object()) {
        // 1. Let targetRealm be ? GetFunctionRealm(newTarget).
        auto* target_realm = TRY(JS::get_function_realm(vm, new_target));

        // 2. Set prototype to the interface prototype object for interface in targetRealm.
        VERIFY(target_realm);
        prototype = &Bindings::ensure_web_prototype<DOMMatrixPrototype>(*target_realm, "DOMMatrix"_fly_string);
    }

    auto arg0 = vm.argument(0);
    Optional<Variant<String, Vector<double>>> init {};
    if (!arg0.is_undefined())
        init = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<Variant<String, Vector<double>>> {

        if (arg0.is_object()) {
            [[maybe_unused]] auto& object = arg0.as_object();

            // 1. Let method be ? GetMethod(V, @@iterator).
            auto method = TRY(arg0.get_method(vm, vm.well_known_symbol_iterator()));

            // 2. If method is not undefined, return the result of creating a sequence of that type from V and method.
            if (method) {
                auto sequence_union_type = TRY([&]() -> JS::ThrowCompletionOr<Vector<double>> {
        // To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
        // 1. Let iteratorRecord be ? GetIteratorFromMethod(iterable, method).
        auto iterator = TRY(JS::get_iterator_from_method(vm, arg0, *method));

        Vector<double> sequence;

        // 2. Initialize i to be 0.
        // 3. Repeat
        for (;;) {
            // 1. Let next be ? IteratorStepValue(iteratorRecord).
            auto next = TRY(JS::iterator_step_value(vm, iterator));

            // 2. If next is done, then return an IDL sequence value of type sequence<T> of length i, where the value of the element at index j is Sj.
            if (!next.has_value())
                break;

            // 3. Initialize Si to the result of converting next to an IDL value of type T.
            auto next_value = next.release_value();
            auto sequence_item = TRY(throw_dom_exception_if_needed(vm, [&] { return next_value.to_double(vm); }));

            // 4. Set i to i + 1.
            sequence.append(sequence_item);
        }

        return sequence;
    }());
                return Variant<String, Vector<double>> { sequence_union_type };
            }

        }

        auto init_string = TRY([&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }());
        return Variant<String, Vector<double>> { init_string };

        return vm.throw_completion<JS::TypeError>("No union types matched"_utf16);
    }(); }));

    auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return Geometry::DOMMatrix::construct_impl(realm, init); }));

    // 7. Set instance.[[Prototype]] to prototype.
    VERIFY(prototype.is_object());
    impl->set_prototype(&prototype.as_object());

    // FIXME: Steps 8...11. of the "internally create a new object implementing the interface DOMMatrix" algorithm
    // (https://webidl.spec.whatwg.org/#js-platform-objects) are currently not handled, or are handled within Geometry::DOMMatrix::construct_impl().

    return *impl;
}

void DOMMatrixPrototype::initialize(JS::Realm& realm, JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;

    object.set_prototype(GC::Ref { ensure_web_prototype<DOMMatrixReadOnlyPrototype>(realm, "DOMMatrixReadOnly"_fly_string) });

    auto a_id = "a"_utf16_fly_string;
    auto native_a_getter = JS::NativeFunction::create(realm, a_getter, 0, a_id, &realm, "get"sv);
    auto native_a_setter = JS::NativeFunction::create(realm, a_setter, 1, a_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto a_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(a_id, native_a_getter, native_a_setter, a_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto b_id = "b"_utf16_fly_string;
    auto native_b_getter = JS::NativeFunction::create(realm, b_getter, 0, b_id, &realm, "get"sv);
    auto native_b_setter = JS::NativeFunction::create(realm, b_setter, 1, b_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto b_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(b_id, native_b_getter, native_b_setter, b_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto c_id = "c"_utf16_fly_string;
    auto native_c_getter = JS::NativeFunction::create(realm, c_getter, 0, c_id, &realm, "get"sv);
    auto native_c_setter = JS::NativeFunction::create(realm, c_setter, 1, c_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto c_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(c_id, native_c_getter, native_c_setter, c_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto d_id = "d"_utf16_fly_string;
    auto native_d_getter = JS::NativeFunction::create(realm, d_getter, 0, d_id, &realm, "get"sv);
    auto native_d_setter = JS::NativeFunction::create(realm, d_setter, 1, d_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto d_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(d_id, native_d_getter, native_d_setter, d_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto e_id = "e"_utf16_fly_string;
    auto native_e_getter = JS::NativeFunction::create(realm, e_getter, 0, e_id, &realm, "get"sv);
    auto native_e_setter = JS::NativeFunction::create(realm, e_setter, 1, e_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto e_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(e_id, native_e_getter, native_e_setter, e_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto f_id = "f"_utf16_fly_string;
    auto native_f_getter = JS::NativeFunction::create(realm, f_getter, 0, f_id, &realm, "get"sv);
    auto native_f_setter = JS::NativeFunction::create(realm, f_setter, 1, f_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto f_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(f_id, native_f_getter, native_f_setter, f_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m11_id = "m11"_utf16_fly_string;
    auto native_m11_getter = JS::NativeFunction::create(realm, m11_getter, 0, m11_id, &realm, "get"sv);
    auto native_m11_setter = JS::NativeFunction::create(realm, m11_setter, 1, m11_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m11_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m11_id, native_m11_getter, native_m11_setter, m11_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m12_id = "m12"_utf16_fly_string;
    auto native_m12_getter = JS::NativeFunction::create(realm, m12_getter, 0, m12_id, &realm, "get"sv);
    auto native_m12_setter = JS::NativeFunction::create(realm, m12_setter, 1, m12_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m12_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m12_id, native_m12_getter, native_m12_setter, m12_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m13_id = "m13"_utf16_fly_string;
    auto native_m13_getter = JS::NativeFunction::create(realm, m13_getter, 0, m13_id, &realm, "get"sv);
    auto native_m13_setter = JS::NativeFunction::create(realm, m13_setter, 1, m13_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m13_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m13_id, native_m13_getter, native_m13_setter, m13_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m14_id = "m14"_utf16_fly_string;
    auto native_m14_getter = JS::NativeFunction::create(realm, m14_getter, 0, m14_id, &realm, "get"sv);
    auto native_m14_setter = JS::NativeFunction::create(realm, m14_setter, 1, m14_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m14_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m14_id, native_m14_getter, native_m14_setter, m14_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m21_id = "m21"_utf16_fly_string;
    auto native_m21_getter = JS::NativeFunction::create(realm, m21_getter, 0, m21_id, &realm, "get"sv);
    auto native_m21_setter = JS::NativeFunction::create(realm, m21_setter, 1, m21_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m21_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m21_id, native_m21_getter, native_m21_setter, m21_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m22_id = "m22"_utf16_fly_string;
    auto native_m22_getter = JS::NativeFunction::create(realm, m22_getter, 0, m22_id, &realm, "get"sv);
    auto native_m22_setter = JS::NativeFunction::create(realm, m22_setter, 1, m22_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m22_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m22_id, native_m22_getter, native_m22_setter, m22_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m23_id = "m23"_utf16_fly_string;
    auto native_m23_getter = JS::NativeFunction::create(realm, m23_getter, 0, m23_id, &realm, "get"sv);
    auto native_m23_setter = JS::NativeFunction::create(realm, m23_setter, 1, m23_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m23_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m23_id, native_m23_getter, native_m23_setter, m23_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m24_id = "m24"_utf16_fly_string;
    auto native_m24_getter = JS::NativeFunction::create(realm, m24_getter, 0, m24_id, &realm, "get"sv);
    auto native_m24_setter = JS::NativeFunction::create(realm, m24_setter, 1, m24_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m24_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m24_id, native_m24_getter, native_m24_setter, m24_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m31_id = "m31"_utf16_fly_string;
    auto native_m31_getter = JS::NativeFunction::create(realm, m31_getter, 0, m31_id, &realm, "get"sv);
    auto native_m31_setter = JS::NativeFunction::create(realm, m31_setter, 1, m31_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m31_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m31_id, native_m31_getter, native_m31_setter, m31_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m32_id = "m32"_utf16_fly_string;
    auto native_m32_getter = JS::NativeFunction::create(realm, m32_getter, 0, m32_id, &realm, "get"sv);
    auto native_m32_setter = JS::NativeFunction::create(realm, m32_setter, 1, m32_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m32_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m32_id, native_m32_getter, native_m32_setter, m32_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m33_id = "m33"_utf16_fly_string;
    auto native_m33_getter = JS::NativeFunction::create(realm, m33_getter, 0, m33_id, &realm, "get"sv);
    auto native_m33_setter = JS::NativeFunction::create(realm, m33_setter, 1, m33_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m33_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m33_id, native_m33_getter, native_m33_setter, m33_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m34_id = "m34"_utf16_fly_string;
    auto native_m34_getter = JS::NativeFunction::create(realm, m34_getter, 0, m34_id, &realm, "get"sv);
    auto native_m34_setter = JS::NativeFunction::create(realm, m34_setter, 1, m34_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m34_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m34_id, native_m34_getter, native_m34_setter, m34_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m41_id = "m41"_utf16_fly_string;
    auto native_m41_getter = JS::NativeFunction::create(realm, m41_getter, 0, m41_id, &realm, "get"sv);
    auto native_m41_setter = JS::NativeFunction::create(realm, m41_setter, 1, m41_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m41_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m41_id, native_m41_getter, native_m41_setter, m41_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m42_id = "m42"_utf16_fly_string;
    auto native_m42_getter = JS::NativeFunction::create(realm, m42_getter, 0, m42_id, &realm, "get"sv);
    auto native_m42_setter = JS::NativeFunction::create(realm, m42_setter, 1, m42_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m42_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m42_id, native_m42_getter, native_m42_setter, m42_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m43_id = "m43"_utf16_fly_string;
    auto native_m43_getter = JS::NativeFunction::create(realm, m43_getter, 0, m43_id, &realm, "get"sv);
    auto native_m43_setter = JS::NativeFunction::create(realm, m43_setter, 1, m43_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m43_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m43_id, native_m43_getter, native_m43_setter, m43_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    auto m44_id = "m44"_utf16_fly_string;
    auto native_m44_getter = JS::NativeFunction::create(realm, m44_getter, 0, m44_id, &realm, "get"sv);
    auto native_m44_setter = JS::NativeFunction::create(realm, m44_setter, 1, m44_id, &realm, "set"sv);

    // 4. Let configurable be false if attr is unforgeable and true otherwise.
    auto m44_attributes = default_attributes;

    // 5. Let desc be the PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]: true, [[Configurable]]: configurable}.

    // 7. Perform ! DefinePropertyOrThrow(target, id, desc).
    object.define_direct_accessor(m44_id, native_m44_getter, native_m44_setter, m44_attributes);

    // 8. FIXME: If attr’s type is an observable array type with type argument T, then set target’s backing observable array exotic object for attr to the result of creating an observable array exotic object in realm, given T, attr’s set an indexed value algorithm, and attr’s delete an indexed value algorithm.
    object.define_native_function(realm, "multiplySelf"_utf16_fly_string, multiply_self, 0, default_attributes);

    object.define_native_function(realm, "preMultiplySelf"_utf16_fly_string, pre_multiply_self, 0, default_attributes);

    object.define_native_function(realm, "translateSelf"_utf16_fly_string, translate_self, 0, default_attributes);

    object.define_native_function(realm, "scaleSelf"_utf16_fly_string, scale_self, 0, default_attributes);

    object.define_native_function(realm, "scale3dSelf"_utf16_fly_string, scale3d_self, 0, default_attributes);

    object.define_native_function(realm, "rotateSelf"_utf16_fly_string, rotate_self, 0, default_attributes);

    object.define_native_function(realm, "rotateFromVectorSelf"_utf16_fly_string, rotate_from_vector_self, 0, default_attributes);

    object.define_native_function(realm, "rotateAxisAngleSelf"_utf16_fly_string, rotate_axis_angle_self, 0, default_attributes);

    object.define_native_function(realm, "skewXSelf"_utf16_fly_string, skew_x_self, 0, default_attributes);

    object.define_native_function(realm, "skewYSelf"_utf16_fly_string, skew_y_self, 0, default_attributes);

    object.define_native_function(realm, "invertSelf"_utf16_fly_string, invert_self, 0, default_attributes);

    if (is<HTML::Window>(realm.global_object())) {
        object.define_native_function(realm, "setMatrixValue"_utf16_fly_string, set_matrix_value, 1, default_attributes);
    
        }
    object.define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "DOMMatrix"_utf16), JS::Attribute::Configurable);
}

void DOMMatrixPrototype::define_unforgeable_attributes(JS::Realm& realm, [[maybe_unused]] JS::Object& object)
{
    [[maybe_unused]] auto& vm = realm.vm();
    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
}

[[maybe_unused]] static JS::ThrowCompletionOr<Geometry::DOMMatrix*> impl_from(JS::VM& vm, JS::Value js_value)
{

    if (auto impl = js_value.as_if<Geometry::DOMMatrix>())
        return impl.ptr();
    return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "DOMMatrix");
}

[[maybe_unused]] static JS::ThrowCompletionOr<Geometry::DOMMatrix*> impl_from(JS::VM& vm)
{
    auto this_value = vm.this_value();
    if (this_value.is_nullish())
        this_value = &vm.current_realm()->global_object();
    return impl_from(vm, this_value);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixConstructor::from_matrix)
{
    WebIDL::log_trace(vm, "DOMMatrixConstructor::from_matrix");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    auto arg0 = vm.argument(0);
    DOMMatrixInit other = DOMMatrixInit {};
    if (!arg0.is_undefined())
        other = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_dom_matrix_init(vm, arg0); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return Geometry::DOMMatrix::from_matrix(vm, other); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixConstructor::from_float32_array)
{
    WebIDL::log_trace(vm, "DOMMatrixConstructor::from_float32_array");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "fromFloat32Array");

    auto arg0 = vm.argument(0);
    auto array32 = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ref<JS::Float32Array>> {
        // A JavaScript value V is converted to an IDL typed array value by running the following algorithm:
        // 1. Let T be the IDL type V is being converted to.
        // 2. If V is not an Object, or V does not have a [[TypedArrayName]] internal slot with a value equal to T's name,
        //    then throw a TypeError.
        auto builtin_buffer = arg0.as_if<JS::Float32Array>();
        if (!builtin_buffer)
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float32Array");

        auto& viewed_array_buffer = *builtin_buffer->viewed_array_buffer();

        // 2. If the conversion is not to an IDL type associated with the [AllowShared] extended attribute, and
        //    IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.
        if (viewed_array_buffer.is_shared_array_buffer())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::SharedArrayBuffer);

        // 3. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and
        //    IsFixedLengthArrayBuffer(V.[[ViewedArrayBuffer]]) is false, then throw a TypeError.
        if (!viewed_array_buffer.is_fixed_length())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "fixed-length Float32Array");

        // 5. Return the IDL value of type T that is a reference to the same object as V.
        return GC::Ref { *builtin_buffer };
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return Geometry::DOMMatrix::from_float32_array(vm, array32); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixConstructor::from_float64_array)
{
    WebIDL::log_trace(vm, "DOMMatrixConstructor::from_float64_array");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "fromFloat64Array");

    auto arg0 = vm.argument(0);
    auto array64 = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<GC::Ref<JS::Float64Array>> {
        // A JavaScript value V is converted to an IDL typed array value by running the following algorithm:
        // 1. Let T be the IDL type V is being converted to.
        // 2. If V is not an Object, or V does not have a [[TypedArrayName]] internal slot with a value equal to T's name,
        //    then throw a TypeError.
        auto builtin_buffer = arg0.as_if<JS::Float64Array>();
        if (!builtin_buffer)
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Float64Array");

        auto& viewed_array_buffer = *builtin_buffer->viewed_array_buffer();

        // 2. If the conversion is not to an IDL type associated with the [AllowShared] extended attribute, and
        //    IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.
        if (viewed_array_buffer.is_shared_array_buffer())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::SharedArrayBuffer);

        // 3. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and
        //    IsFixedLengthArrayBuffer(V.[[ViewedArrayBuffer]]) is false, then throw a TypeError.
        if (!viewed_array_buffer.is_fixed_length())
            return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "fixed-length Float64Array");

        // 5. Return the IDL value of type T that is a reference to the same object as V.
        return GC::Ref { *builtin_buffer };
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return Geometry::DOMMatrix::from_float64_array(vm, array64); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::a_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::a_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->a(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::b_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::b_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->b(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::c_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::c_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->c(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::d_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::d_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->d(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::e_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::e_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->e(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::f_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::f_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->f(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m11_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m11_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m11(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m12_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m12_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m12(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m13_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m13_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m13(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m14_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m14_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m14(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m21_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m21_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m21(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m22_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m22_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m22(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m23_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m23_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m23(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m24_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m24_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m24(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m31_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m31_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m31(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m32_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m32_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m32(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m33_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m33_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m33(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m34_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m34_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m34(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m41_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m41_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m41(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m42_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m42_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m42(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m43_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m43_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m43(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m44_getter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m44_getter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    auto* idl_object = TRY(impl_from(vm));


    auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->m44(); }));

    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::a_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::a_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_a(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::b_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::b_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_b(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::c_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::c_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_c(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::d_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::d_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_d(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::e_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::e_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_e(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::f_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::f_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_f(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m11_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m11_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m11(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m12_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m12_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m12(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m13_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m13_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m13(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m14_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m14_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m14(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m21_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m21_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m21(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m22_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m22_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m22(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m23_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m23_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m23(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m24_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m24_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m24(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m31_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m31_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m31(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m32_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m32_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m32(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m33_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m33_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m33(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m34_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m34_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m34(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m41_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m41_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m41(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m42_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m42_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m42(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m43_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m43_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m43(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::m44_setter)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::m44_setter");
    [[maybe_unused]] auto& realm = *vm.current_realm();

    // 1. Let V be undefined.
    auto V = JS::js_undefined();

    // 2. If any arguments were passed, then set V to the value of the first argument passed.
    if (vm.argument_count() > 0)
        V = vm.argument(0);

    // 3. Let id be attribute’s identifier.

    // 4. Let idlObject be null.
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = nullptr;

    // 5. If attribute is a regular attribute:

    // 1. Let jsValue be the this value, if it is not null or undefined, or realm’s global object otherwise. (This will subsequently cause a TypeError in a few steps, if the global object does not implement target and [LegacyLenientThis] is not specified.)
    auto js_value = vm.this_value();
    if (js_value.is_nullish())
        js_value = &realm.global_object();

    // 2. FIXME: If jsValue is a platform object, then perform a security check, passing jsValue, attribute’s identifier, and "setter".

    // 3. Let validThis be true if jsValue implements target, or false otherwise.
    auto maybe_idl_object = impl_from(vm, js_value);

    // 4. If validThis is false and attribute was not specified with the [LegacyLenientThis] extended attribute, then throw a TypeError.
    idl_object = TRY(maybe_idl_object);

    auto original_steps = [&]() -> JS::ThrowCompletionOr<JS::Value> {
        // 6. Let idlValue be determined as follows:
        // -> Otherwise, idlValue is the result of converting V to an IDL value of attribute’s type.
        auto idl_value = TRY(throw_dom_exception_if_needed(vm, [&] { return V.to_double(vm); }));

        // 7. Run the setter steps of attribute with idlObject as this and idlValue as the value.
        auto setter_result = [&]() -> JS::ThrowCompletionOr<void> {
            TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_m44(idl_value); }));
    return {};
        }();

        if (setter_result.is_error())
            return setter_result.release_error();

        return JS::js_undefined();
    };

    // 8. Return undefined.
    return TRY(original_steps());
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::multiply_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::multiply_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    DOMMatrixInit other = DOMMatrixInit {};
    if (!arg0.is_undefined())
        other = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_dom_matrix_init(vm, arg0); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->multiply_self(other); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::pre_multiply_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::pre_multiply_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    DOMMatrixInit other = DOMMatrixInit {};
    if (!arg0.is_undefined())
        other = TRY(throw_dom_exception_if_needed(vm, [&] { return convert_to_idl_value_for_dom_matrix_init(vm, arg0); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->pre_multiply_self(other); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::translate_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::translate_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double tx = 0;
    if (!arg0.is_undefined())
        tx = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    double ty = 0;
    if (!arg1.is_undefined())
        ty = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    double tz = 0;
    if (!arg2.is_undefined())
        tz = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->translate_self(tx, ty, tz); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::scale_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::scale_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double scale_x = 1;
    if (!arg0.is_undefined())
        scale_x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    Optional<double> scale_y {};
    if (!arg1.is_undefined())
        scale_y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    double scale_z = 1;
    if (!arg2.is_undefined())
        scale_z = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    double origin_x = 0;
    if (!arg3.is_undefined())
        origin_x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    auto arg4 = vm.argument(4);
    double origin_y = 0;
    if (!arg4.is_undefined())
        origin_y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg4.to_double(vm); }));

    auto arg5 = vm.argument(5);
    double origin_z = 0;
    if (!arg5.is_undefined())
        origin_z = TRY(throw_dom_exception_if_needed(vm, [&] { return arg5.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->scale_self(scale_x, scale_y, scale_z, origin_x, origin_y, origin_z); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::scale3d_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::scale3d_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double scale = 1;
    if (!arg0.is_undefined())
        scale = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    double origin_x = 0;
    if (!arg1.is_undefined())
        origin_x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    double origin_y = 0;
    if (!arg2.is_undefined())
        origin_y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    double origin_z = 0;
    if (!arg3.is_undefined())
        origin_z = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->scale3d_self(scale, origin_x, origin_y, origin_z); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::rotate_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::rotate_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double rot_x = 0;
    if (!arg0.is_undefined())
        rot_x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    Optional<double> rot_y {};
    if (!arg1.is_undefined())
        rot_y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    Optional<double> rot_z {};
    if (!arg2.is_undefined())
        rot_z = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->rotate_self(rot_x, rot_y, rot_z); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::rotate_from_vector_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::rotate_from_vector_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double x = 0;
    if (!arg0.is_undefined())
        x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    double y = 0;
    if (!arg1.is_undefined())
        y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->rotate_from_vector_self(x, y); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::rotate_axis_angle_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::rotate_axis_angle_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double x = 0;
    if (!arg0.is_undefined())
        x = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    auto arg1 = vm.argument(1);
    double y = 0;
    if (!arg1.is_undefined())
        y = TRY(throw_dom_exception_if_needed(vm, [&] { return arg1.to_double(vm); }));

    auto arg2 = vm.argument(2);
    double z = 0;
    if (!arg2.is_undefined())
        z = TRY(throw_dom_exception_if_needed(vm, [&] { return arg2.to_double(vm); }));

    auto arg3 = vm.argument(3);
    double angle = 0;
    if (!arg3.is_undefined())
        angle = TRY(throw_dom_exception_if_needed(vm, [&] { return arg3.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->rotate_axis_angle_self(x, y, z, angle); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::skew_x_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::skew_x_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double sx = 0;
    if (!arg0.is_undefined())
        sx = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->skew_x_self(sx); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::skew_y_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::skew_y_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    auto arg0 = vm.argument(0);
    double sy = 0;
    if (!arg0.is_undefined())
        sy = TRY(throw_dom_exception_if_needed(vm, [&] { return arg0.to_double(vm); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->skew_y_self(sy); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::invert_self)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::invert_self");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->invert_self(); }));
    return JS::Value(R);
}

JS_DEFINE_NATIVE_FUNCTION(DOMMatrixPrototype::set_matrix_value)
{
    WebIDL::log_trace(vm, "DOMMatrixPrototype::set_matrix_value");
    [[maybe_unused]] auto& realm = *vm.current_realm();
    [[maybe_unused]] Geometry::DOMMatrix* idl_object = TRY(impl_from(vm));

    if (vm.argument_count() < 1)
        return vm.throw_completion<JS::TypeError>(JS::ErrorType::BadArgCountOne, "setMatrixValue");

    auto arg0 = vm.argument(0);
    auto transform_list = TRY(throw_dom_exception_if_needed(vm, [&] { return [&]() -> JS::ThrowCompletionOr<String> {
        return TRY(WebIDL::to_string(vm, arg0));
    }(); }));

    [[maybe_unused]] auto R = TRY(throw_dom_exception_if_needed(vm, [&] { return idl_object->set_matrix_value(transform_list); }));
    return JS::Value(R);
}

} // namespace Web::Bindings
