diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h index c2ee642ca3..1e43e608bb 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h +++ b/Userland/Libraries/LibJS/Runtime/ArrayBuffer.h @@ -13,6 +13,9 @@ namespace JS { +struct ClampedU8 { +}; + class ArrayBuffer : public Object { JS_OBJECT(ArrayBuffer, Object); @@ -70,26 +73,27 @@ static Value raw_bytes_to_numeric(GlobalObject& global_object, ByteBuffer raw_va for (size_t i = 0; i < raw_value.size() / 2; ++i) swap(raw_value[i], raw_value[raw_value.size() - 1 - i]); } - if constexpr (IsSame) { + using UnderlyingBufferDataType = Conditional, u8, T>; + if constexpr (IsSame) { float value; raw_value.span().copy_to({ &value, sizeof(float) }); if (isnan(value)) return js_nan(); return Value(value); } - if constexpr (IsSame) { + if constexpr (IsSame) { double value; raw_value.span().copy_to({ &value, sizeof(double) }); if (isnan(value)) return js_nan(); return Value(value); } - if constexpr (!IsIntegral) + if constexpr (!IsIntegral) VERIFY_NOT_REACHED(); - T int_value = 0; - raw_value.span().copy_to({ &int_value, sizeof(T) }); - if constexpr (sizeof(T) == 8) { - if constexpr (IsSigned) + UnderlyingBufferDataType int_value = 0; + raw_value.span().copy_to({ &int_value, sizeof(UnderlyingBufferDataType) }); + if constexpr (sizeof(UnderlyingBufferDataType) == 8) { + if constexpr (IsSigned) return js_bigint(global_object.heap(), Crypto::SignedBigInteger::create_from(int_value)); else return js_bigint(global_object.heap(), Crypto::SignedBigInteger { Crypto::UnsignedBigInteger::create_from(int_value) }); @@ -114,41 +118,62 @@ Value ArrayBuffer::get_value(size_t byte_index, [[maybe_unused]] bool is_typed_a template static ByteBuffer numeric_to_raw_bytes(GlobalObject& global_object, Value value, bool is_little_endian) { - ByteBuffer raw_bytes = ByteBuffer::create_uninitialized(sizeof(T)); + using UnderlyingBufferDataType = Conditional, u8, T>; + ByteBuffer raw_bytes = ByteBuffer::create_uninitialized(sizeof(UnderlyingBufferDataType)); auto flip_if_needed = [&]() { if (is_little_endian) return; - VERIFY(sizeof(T) % 2 == 0); - for (size_t i = 0; i < sizeof(T) / 2; ++i) - swap(raw_bytes[i], raw_bytes[sizeof(T) - 1 - i]); + VERIFY(sizeof(UnderlyingBufferDataType) % 2 == 0); + for (size_t i = 0; i < sizeof(UnderlyingBufferDataType) / 2; ++i) + swap(raw_bytes[i], raw_bytes[sizeof(UnderlyingBufferDataType) - 1 - i]); }; - if constexpr (IsSame) { + if constexpr (IsSame) { float raw_value = value.to_double(global_object); ReadonlyBytes { &raw_value, sizeof(float) }.copy_to(raw_bytes); flip_if_needed(); return raw_bytes; } - if constexpr (IsSame) { + if constexpr (IsSame) { double raw_value = value.to_double(global_object); ReadonlyBytes { &raw_value, sizeof(double) }.copy_to(raw_bytes); flip_if_needed(); return raw_bytes; } - if constexpr (!IsIntegral) + if constexpr (!IsIntegral) VERIFY_NOT_REACHED(); - if constexpr (sizeof(T) == 8) { - u64 int_value = value.as_bigint().big_integer().to_u64(); - ReadonlyBytes { &int_value, sizeof(u64) }.copy_to(raw_bytes); + if constexpr (sizeof(UnderlyingBufferDataType) == 8) { + UnderlyingBufferDataType int_value; + + if constexpr (IsSigned) + int_value = value.to_bigint_int64(global_object); + else + int_value = value.to_bigint_uint64(global_object); + + ReadonlyBytes { &int_value, sizeof(UnderlyingBufferDataType) }.copy_to(raw_bytes); flip_if_needed(); return raw_bytes; } else { - T int_value; - if constexpr (IsSigned) - int_value = value.to_i32(global_object); - else - int_value = value.to_u32(global_object); - ReadonlyBytes { &int_value, sizeof(T) }.copy_to(raw_bytes); - flip_if_needed(); + UnderlyingBufferDataType int_value; + if constexpr (IsSigned) { + if constexpr (sizeof(UnderlyingBufferDataType) == 4) + int_value = value.to_i32(global_object); + else if constexpr (sizeof(UnderlyingBufferDataType) == 2) + int_value = value.to_i16(global_object); + else + int_value = value.to_i8(global_object); + } else { + if constexpr (sizeof(UnderlyingBufferDataType) == 4) + int_value = value.to_u32(global_object); + else if constexpr (sizeof(UnderlyingBufferDataType) == 2) + int_value = value.to_u16(global_object); + else if constexpr (!IsSame) + int_value = value.to_u8(global_object); + else + int_value = value.to_u8_clamp(global_object); + } + ReadonlyBytes { &int_value, sizeof(UnderlyingBufferDataType) }.copy_to(raw_bytes); + if constexpr (sizeof(UnderlyingBufferDataType) % 2 == 0) + flip_if_needed(); return raw_bytes; } } diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.h b/Userland/Libraries/LibJS/Runtime/TypedArray.h index 0ef0e600b6..c38b01c644 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -44,9 +44,6 @@ private: virtual void visit_edges(Visitor&) override; }; -struct ClampedU8 { -}; - template class TypedArray : public TypedArrayBase { JS_OBJECT(TypedArray, TypedArrayBase);