1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:07:47 +00:00

LibJS+LibWeb: Make Uint8ClampedArray use TypedArray

Instead of being its own separate unrelated class.
This automatically makes typed array properties available to it,
as well as making it available to the runtime.
This commit is contained in:
Ali Mohammad Pur 2021-05-22 23:33:26 +04:30 committed by Ali Mohammad Pur
parent ba5da79617
commit 6af596d9e8
7 changed files with 36 additions and 129 deletions

View file

@ -82,7 +82,6 @@ set(SOURCES
Runtime/TypedArray.cpp Runtime/TypedArray.cpp
Runtime/TypedArrayConstructor.cpp Runtime/TypedArrayConstructor.cpp
Runtime/TypedArrayPrototype.cpp Runtime/TypedArrayPrototype.cpp
Runtime/Uint8ClampedArray.cpp
Runtime/VM.cpp Runtime/VM.cpp
Runtime/Value.cpp Runtime/Value.cpp
Runtime/WithScope.cpp Runtime/WithScope.cpp

View file

@ -54,14 +54,15 @@
__JS_ENUMERATE(TypeError, type_error, TypeErrorPrototype, TypeErrorConstructor, void) \ __JS_ENUMERATE(TypeError, type_error, TypeErrorPrototype, TypeErrorConstructor, void) \
__JS_ENUMERATE(URIError, uri_error, URIErrorPrototype, URIErrorConstructor, void) __JS_ENUMERATE(URIError, uri_error, URIErrorPrototype, URIErrorConstructor, void)
#define JS_ENUMERATE_TYPED_ARRAYS \ #define JS_ENUMERATE_TYPED_ARRAYS \
__JS_ENUMERATE(Uint8Array, uint8_array, Uint8ArrayPrototype, Uint8ArrayConstructor, u8) \ __JS_ENUMERATE(Uint8Array, uint8_array, Uint8ArrayPrototype, Uint8ArrayConstructor, u8) \
__JS_ENUMERATE(Uint16Array, uint16_array, Uint16ArrayPrototype, Uint16ArrayConstructor, u16) \ __JS_ENUMERATE(Uint8ClampedArray, uint8_clamped_array, Uint8ClampedArrayPrototype, Uint8ClampedArrayConstructor, ClampedU8) \
__JS_ENUMERATE(Uint32Array, uint32_array, Uint32ArrayPrototype, Uint32ArrayConstructor, u32) \ __JS_ENUMERATE(Uint16Array, uint16_array, Uint16ArrayPrototype, Uint16ArrayConstructor, u16) \
__JS_ENUMERATE(Int8Array, int8_array, Int8ArrayPrototype, Int8ArrayConstructor, i8) \ __JS_ENUMERATE(Uint32Array, uint32_array, Uint32ArrayPrototype, Uint32ArrayConstructor, u32) \
__JS_ENUMERATE(Int16Array, int16_array, Int16ArrayPrototype, Int16ArrayConstructor, i16) \ __JS_ENUMERATE(Int8Array, int8_array, Int8ArrayPrototype, Int8ArrayConstructor, i8) \
__JS_ENUMERATE(Int32Array, int32_array, Int32ArrayPrototype, Int32ArrayConstructor, i32) \ __JS_ENUMERATE(Int16Array, int16_array, Int16ArrayPrototype, Int16ArrayConstructor, i16) \
__JS_ENUMERATE(Float32Array, float32_array, Float32ArrayPrototype, Float32ArrayConstructor, float) \ __JS_ENUMERATE(Int32Array, int32_array, Int32ArrayPrototype, Int32ArrayConstructor, i32) \
__JS_ENUMERATE(Float32Array, float32_array, Float32ArrayPrototype, Float32ArrayConstructor, float) \
__JS_ENUMERATE(Float64Array, float64_array, Float64ArrayPrototype, Float64ArrayConstructor, double) __JS_ENUMERATE(Float64Array, float64_array, Float64ArrayPrototype, Float64ArrayConstructor, double)
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \ #define JS_ENUMERATE_ITERATOR_PROTOTYPES \
@ -131,7 +132,6 @@ class Shape;
class Statement; class Statement;
class Symbol; class Symbol;
class Token; class Token;
class Uint8ClampedArray;
class VM; class VM;
class Value; class Value;
enum class DeclarationKind; enum class DeclarationKind;
@ -146,6 +146,9 @@ class ProxyConstructor;
class TypedArrayConstructor; class TypedArrayConstructor;
class TypedArrayPrototype; class TypedArrayPrototype;
// Tag type used to differentiate between u8 as used by Uint8Array and u8 as used by Uint8ClampedArray.
struct ClampedU8;
#define __JS_ENUMERATE(ClassName, snake_name, ConstructorName, PrototypeName, ArrayType) \ #define __JS_ENUMERATE(ClassName, snake_name, ConstructorName, PrototypeName, ArrayType) \
class ClassName; \ class ClassName; \
class ConstructorName; \ class ConstructorName; \

View file

@ -44,22 +44,29 @@ private:
virtual void visit_edges(Visitor&) override; virtual void visit_edges(Visitor&) override;
}; };
struct ClampedU8 {
};
template<typename T> template<typename T>
class TypedArray : public TypedArrayBase { class TypedArray : public TypedArrayBase {
JS_OBJECT(TypedArray, TypedArrayBase); JS_OBJECT(TypedArray, TypedArrayBase);
using UnderlyingBufferDataType = Conditional<IsSame<ClampedU8, T>, u8, T>;
public: public:
virtual bool put_by_index(u32 property_index, Value value) override virtual bool put_by_index(u32 property_index, Value value) override
{ {
if (property_index >= m_array_length) if (property_index >= m_array_length)
return Base::put_by_index(property_index, value); return Base::put_by_index(property_index, value);
if constexpr (sizeof(T) < 4) { if constexpr (sizeof(UnderlyingBufferDataType) < 4) {
auto number = value.to_i32(global_object()); auto number = value.to_i32(global_object());
if (vm().exception()) if (vm().exception())
return {}; return {};
if constexpr (IsSame<T, ClampedU8>)
number = clamp(number, 0, 255);
data()[property_index] = number; data()[property_index] = number;
} else if constexpr (sizeof(T) == 4 || sizeof(T) == 8) { } else if constexpr (sizeof(UnderlyingBufferDataType) == 4 || sizeof(UnderlyingBufferDataType) == 8) {
auto number = value.to_double(global_object()); auto number = value.to_double(global_object());
if (vm().exception()) if (vm().exception())
return {}; return {};
@ -75,13 +82,13 @@ public:
if (property_index >= m_array_length) if (property_index >= m_array_length)
return Base::get_by_index(property_index); return Base::get_by_index(property_index);
if constexpr (sizeof(T) < 4) { if constexpr (sizeof(UnderlyingBufferDataType) < 4) {
return Value((i32)data()[property_index]); return Value((i32)data()[property_index]);
} else if constexpr (sizeof(T) == 4 || sizeof(T) == 8) { } else if constexpr (sizeof(UnderlyingBufferDataType) == 4 || sizeof(UnderlyingBufferDataType) == 8) {
auto value = data()[property_index]; auto value = data()[property_index];
if constexpr (IsFloatingPoint<T>) { if constexpr (IsFloatingPoint<UnderlyingBufferDataType>) {
return Value((double)value); return Value((double)value);
} else if constexpr (NumericLimits<T>::is_signed()) { } else if constexpr (NumericLimits<UnderlyingBufferDataType>::is_signed()) {
if (value > NumericLimits<i32>::max() || value < NumericLimits<i32>::min()) if (value > NumericLimits<i32>::max() || value < NumericLimits<i32>::min())
return Value((double)value); return Value((double)value);
} else { } else {
@ -94,23 +101,23 @@ public:
} }
} }
Span<const T> data() const Span<const UnderlyingBufferDataType> data() const
{ {
return { reinterpret_cast<const T*>(m_viewed_array_buffer->buffer().data() + m_byte_offset), m_array_length }; return { reinterpret_cast<const UnderlyingBufferDataType*>(m_viewed_array_buffer->buffer().data() + m_byte_offset), m_array_length };
} }
Span<T> data() Span<UnderlyingBufferDataType> data()
{ {
return { reinterpret_cast<T*>(m_viewed_array_buffer->buffer().data() + m_byte_offset), m_array_length }; return { reinterpret_cast<UnderlyingBufferDataType*>(m_viewed_array_buffer->buffer().data() + m_byte_offset), m_array_length };
} }
virtual size_t element_size() const override { return sizeof(T); }; virtual size_t element_size() const override { return sizeof(UnderlyingBufferDataType); };
protected: protected:
TypedArray(u32 array_length, Object& prototype) TypedArray(u32 array_length, Object& prototype)
: TypedArrayBase(prototype) : TypedArrayBase(prototype)
{ {
VERIFY(!Checked<u32>::multiplication_would_overflow(array_length, sizeof(T))); VERIFY(!Checked<u32>::multiplication_would_overflow(array_length, sizeof(UnderlyingBufferDataType)));
m_viewed_array_buffer = ArrayBuffer::create(global_object(), array_length * sizeof(T)); m_viewed_array_buffer = ArrayBuffer::create(global_object(), array_length * sizeof(UnderlyingBufferDataType));
if (array_length) if (array_length)
VERIFY(!data().is_null()); VERIFY(!data().is_null());
m_array_length = array_length; m_array_length = array_length;

View file

@ -1,65 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Function.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Uint8ClampedArray.h>
namespace JS {
Uint8ClampedArray* Uint8ClampedArray::create(GlobalObject& global_object, u32 length)
{
return global_object.heap().allocate<Uint8ClampedArray>(global_object, length, *global_object.array_prototype());
}
Uint8ClampedArray::Uint8ClampedArray(u32 length, Object& prototype)
: Object(prototype)
, m_length(length)
{
auto& vm = this->vm();
define_native_property(vm.names.length, length_getter, {});
m_data = (u8*)calloc(m_length, 1);
}
Uint8ClampedArray::~Uint8ClampedArray()
{
VERIFY(m_data);
free(m_data);
m_data = nullptr;
}
JS_DEFINE_NATIVE_GETTER(Uint8ClampedArray::length_getter)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (StringView(this_object->class_name()) != "Uint8ClampedArray") {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Uint8ClampedArray");
return {};
}
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length());
}
bool Uint8ClampedArray::put_by_index(u32 property_index, Value value)
{
if (property_index >= m_length)
return Base::put_by_index(property_index, value);
auto number = value.to_i32(global_object());
if (vm().exception())
return {};
m_data[property_index] = clamp(number, 0, 255);
return true;
}
Value Uint8ClampedArray::get_by_index(u32 property_index) const
{
if (property_index >= m_length)
return Base::get_by_index(property_index);
return Value((i32)m_data[property_index]);
}
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/Object.h>
namespace JS {
class Uint8ClampedArray final : public Object {
JS_OBJECT(Uint8ClampedArray, Object);
public:
static Uint8ClampedArray* create(GlobalObject&, u32 length);
Uint8ClampedArray(u32 length, Object& prototype);
virtual ~Uint8ClampedArray() override;
i32 length() const { return m_length; }
virtual bool put_by_index(u32 property_index, Value value) override;
virtual Value get_by_index(u32 property_index) const override;
u8* data() { return m_data; }
const u8* data() const { return m_data; }
private:
JS_DECLARE_NATIVE_GETTER(length_getter);
u8* m_data { nullptr };
u32 m_length { 0 };
};
}

View file

@ -856,7 +856,7 @@ void generate_implementation(const IDL::Interface& interface)
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Uint8ClampedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h> #include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/@prototype_class@.h> #include <LibWeb/Bindings/@prototype_class@.h>
#include <LibWeb/Bindings/@wrapper_class@.h> #include <LibWeb/Bindings/@wrapper_class@.h>
@ -1200,7 +1200,7 @@ void generate_prototype_implementation(const IDL::Interface& interface)
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Uint8ClampedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/@prototype_class@.h> #include <LibWeb/Bindings/@prototype_class@.h>
#include <LibWeb/Bindings/@wrapper_class@.h> #include <LibWeb/Bindings/@wrapper_class@.h>
#include <LibWeb/Bindings/CSSStyleDeclarationWrapper.h> #include <LibWeb/Bindings/CSSStyleDeclarationWrapper.h>

View file

@ -5,7 +5,7 @@
*/ */
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <LibJS/Runtime/Uint8ClampedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/HTML/ImageData.h> #include <LibWeb/HTML/ImageData.h>
namespace Web::HTML { namespace Web::HTML {
@ -26,7 +26,7 @@ RefPtr<ImageData> ImageData::create_with_size(JS::GlobalObject& global_object, i
auto data_handle = JS::make_handle(data); auto data_handle = JS::make_handle(data);
auto bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize(width, height), 1, width * sizeof(u32), (u32*)data->data()); auto bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize(width, height), 1, width * sizeof(u32), data->data().data());
if (!bitmap) if (!bitmap)
return nullptr; return nullptr;
return adopt_ref(*new ImageData(bitmap.release_nonnull(), move(data_handle))); return adopt_ref(*new ImageData(bitmap.release_nonnull(), move(data_handle)));