mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 18:32:45 +00:00 
			
		
		
		
	LibJS+LibWeb: Move native properties to separate getters/setters
This was a bit cumbersome now, but it gets us closer to a format suited for code generation.
This commit is contained in:
		
							parent
							
								
									56936b97d0
								
							
						
					
					
						commit
						30440134cb
					
				
					 19 changed files with 210 additions and 96 deletions
				
			
		|  | @ -27,20 +27,14 @@ | ||||||
| #include <AK/Function.h> | #include <AK/Function.h> | ||||||
| #include <LibJS/Interpreter.h> | #include <LibJS/Interpreter.h> | ||||||
| #include <LibJS/Runtime/Array.h> | #include <LibJS/Runtime/Array.h> | ||||||
|  | #include <LibJS/Runtime/Error.h> | ||||||
| 
 | 
 | ||||||
| namespace JS { | namespace JS { | ||||||
| 
 | 
 | ||||||
| Array::Array() | Array::Array() | ||||||
| { | { | ||||||
|     set_prototype(interpreter().array_prototype()); |     set_prototype(interpreter().array_prototype()); | ||||||
|     put_native_property( |     put_native_property("length", length_getter, length_setter); | ||||||
|         "length", |  | ||||||
|         [this](Object*) { |  | ||||||
|             return Value(length()); |  | ||||||
|         }, |  | ||||||
|         [](Object*, Value) { |  | ||||||
|             ASSERT_NOT_REACHED(); |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Array::~Array() | Array::~Array() | ||||||
|  | @ -96,4 +90,20 @@ bool Array::put_own_property(Object& this_object, const FlyString& property_name | ||||||
|     } |     } | ||||||
|     return Object::put_own_property(this_object, property_name, value); |     return Object::put_own_property(this_object, property_name, value); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | Value Array::length_getter(Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return {}; | ||||||
|  |     if (!this_object->is_array()) | ||||||
|  |         return interpreter.throw_exception<Error>("TypeError", "Not an array"); | ||||||
|  |     return Value(static_cast<const Array*>(this_object)->length()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Array::length_setter(Interpreter&, Value) | ||||||
|  | { | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -50,6 +50,9 @@ private: | ||||||
|     virtual Optional<Value> get_own_property(const Object& this_object, const FlyString& property_name) const override; |     virtual Optional<Value> get_own_property(const Object& this_object, const FlyString& property_name) const override; | ||||||
|     virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value) override; |     virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value) override; | ||||||
| 
 | 
 | ||||||
|  |     static Value length_getter(Interpreter&); | ||||||
|  |     static void length_setter(Interpreter&, Value); | ||||||
|  | 
 | ||||||
|     Vector<Value> m_elements; |     Vector<Value> m_elements; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -36,25 +36,32 @@ namespace JS { | ||||||
| 
 | 
 | ||||||
| ErrorPrototype::ErrorPrototype() | ErrorPrototype::ErrorPrototype() | ||||||
| { | { | ||||||
|     put_native_property( |     put_native_property("name", name_getter, nullptr); | ||||||
|         "name", [](Object* this_object) { |     put_native_property("message", message_getter, nullptr); | ||||||
|             ASSERT(this_object); |  | ||||||
|             ASSERT(this_object->is_error()); |  | ||||||
|             return js_string(this_object->heap(), static_cast<const Error*>(this_object)->name()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
| 
 |  | ||||||
|     put_native_property( |  | ||||||
|         "message", [](Object* this_object) { |  | ||||||
|             ASSERT(this_object); |  | ||||||
|             ASSERT(this_object->is_error()); |  | ||||||
|             return js_string(this_object->heap(), static_cast<const Error*>(this_object)->message()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ErrorPrototype::~ErrorPrototype() | ErrorPrototype::~ErrorPrototype() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Value ErrorPrototype::name_getter(Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return {}; | ||||||
|  |     if (!this_object->is_error()) | ||||||
|  |         return interpreter.throw_exception<Error>("TypeError", "Not an Error object"); | ||||||
|  |     return js_string(interpreter.heap(), static_cast<const Error*>(this_object)->name()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Value ErrorPrototype::message_getter(Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return {}; | ||||||
|  |     if (!this_object->is_error()) | ||||||
|  |         return interpreter.throw_exception<Error>("TypeError", "Not an Error object"); | ||||||
|  |     return js_string(interpreter.heap(), static_cast<const Error*>(this_object)->message()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -37,6 +37,9 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     virtual const char* class_name() const override { return "ErrorPrototype"; } |     virtual const char* class_name() const override { return "ErrorPrototype"; } | ||||||
|  | 
 | ||||||
|  |     static Value name_getter(Interpreter&); | ||||||
|  |     static Value message_getter(Interpreter&); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace JS { | namespace JS { | ||||||
| 
 | 
 | ||||||
| NativeProperty::NativeProperty(AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter) | NativeProperty::NativeProperty(AK::Function<Value(Interpreter&)> getter, AK::Function<void(Interpreter&, Value)> setter) | ||||||
|     : m_getter(move(getter)) |     : m_getter(move(getter)) | ||||||
|     , m_setter(move(setter)) |     , m_setter(move(setter)) | ||||||
| { | { | ||||||
|  | @ -39,18 +39,18 @@ NativeProperty::~NativeProperty() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Value NativeProperty::get(Object* object) const | Value NativeProperty::get(Interpreter& interpreter) const | ||||||
| { | { | ||||||
|     if (!m_getter) |     if (!m_getter) | ||||||
|         return js_undefined(); |         return js_undefined(); | ||||||
|     return m_getter(object); |     return m_getter(interpreter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void NativeProperty::set(Object* object, Value value) | void NativeProperty::set(Interpreter& interpreter, Value value) | ||||||
| { | { | ||||||
|     if (!m_setter) |     if (!m_setter) | ||||||
|         return; |         return; | ||||||
|     m_setter(object, move(value)); |     m_setter(interpreter, move(value)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -33,18 +33,18 @@ namespace JS { | ||||||
| 
 | 
 | ||||||
| class NativeProperty final : public Object { | class NativeProperty final : public Object { | ||||||
| public: | public: | ||||||
|     NativeProperty(AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); |     NativeProperty(AK::Function<Value(Interpreter&)> getter, AK::Function<void(Interpreter&, Value)> setter); | ||||||
|     virtual ~NativeProperty() override; |     virtual ~NativeProperty() override; | ||||||
| 
 | 
 | ||||||
|     Value get(Object*) const; |     Value get(Interpreter&) const; | ||||||
|     void set(Object*, Value); |     void set(Interpreter&, Value); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     virtual bool is_native_property() const override { return true; } |     virtual bool is_native_property() const override { return true; } | ||||||
|     virtual const char* class_name() const override { return "NativeProperty"; } |     virtual const char* class_name() const override { return "NativeProperty"; } | ||||||
| 
 | 
 | ||||||
|     AK::Function<Value(Object*)> m_getter; |     AK::Function<Value(Interpreter&)> m_getter; | ||||||
|     AK::Function<void(Object*, Value)> m_setter; |     AK::Function<void(Interpreter&, Value)> m_setter; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -56,8 +56,15 @@ bool Object::has_prototype(const Object* prototype) const | ||||||
| Optional<Value> Object::get_own_property(const Object& this_object, const FlyString& property_name) const | Optional<Value> Object::get_own_property(const Object& this_object, const FlyString& property_name) const | ||||||
| { | { | ||||||
|     auto value_here = m_properties.get(property_name); |     auto value_here = m_properties.get(property_name); | ||||||
|     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) |     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { | ||||||
|         return static_cast<NativeProperty*>(value_here.value().as_object())->get(&const_cast<Object&>(this_object)); |         auto& native_property = static_cast<const NativeProperty&>(*value_here.value().as_object()); | ||||||
|  |         auto& interpreter = const_cast<Object*>(this)->interpreter(); | ||||||
|  |         auto& call_frame = interpreter.push_call_frame(); | ||||||
|  |         call_frame.this_value = const_cast<Object*>(&this_object); | ||||||
|  |         auto result = native_property.get(interpreter); | ||||||
|  |         interpreter.pop_call_frame(); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|     return value_here; |     return value_here; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -65,7 +72,13 @@ bool Object::put_own_property(Object& this_object, const FlyString& property_nam | ||||||
| { | { | ||||||
|     auto value_here = m_properties.get(property_name); |     auto value_here = m_properties.get(property_name); | ||||||
|     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { |     if (value_here.has_value() && value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { | ||||||
|         static_cast<NativeProperty*>(value_here.value().as_object())->set(&this_object, value); |         auto& native_property = static_cast<NativeProperty&>(*value_here.value().as_object()); | ||||||
|  |         auto& interpreter = const_cast<Object*>(this)->interpreter(); | ||||||
|  |         auto& call_frame = interpreter.push_call_frame(); | ||||||
|  |         call_frame.this_value = &this_object; | ||||||
|  |         dbg() << "put_own_property: " << &this_object << " . " << property_name << " = " << value; | ||||||
|  |         native_property.set(interpreter, value); | ||||||
|  |         interpreter.pop_call_frame(); | ||||||
|     } else { |     } else { | ||||||
|         m_properties.set(property_name, value); |         m_properties.set(property_name, value); | ||||||
|     } |     } | ||||||
|  | @ -91,7 +104,12 @@ void Object::put(const FlyString& property_name, Value value) | ||||||
|         auto value_here = object->m_properties.get(property_name); |         auto value_here = object->m_properties.get(property_name); | ||||||
|         if (value_here.has_value()) { |         if (value_here.has_value()) { | ||||||
|             if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { |             if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) { | ||||||
|                 static_cast<NativeProperty*>(value_here.value().as_object())->set(const_cast<Object*>(this), value); |                 auto& native_property = static_cast<NativeProperty&>(*value_here.value().as_object()); | ||||||
|  |                 auto& interpreter = const_cast<Object*>(this)->interpreter(); | ||||||
|  |                 auto& call_frame = interpreter.push_call_frame(); | ||||||
|  |                 call_frame.this_value = this; | ||||||
|  |                 native_property.set(interpreter, value); | ||||||
|  |                 interpreter.pop_call_frame(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (object->put_own_property(*this, property_name, value)) |             if (object->put_own_property(*this, property_name, value)) | ||||||
|  | @ -107,7 +125,7 @@ void Object::put_native_function(const FlyString& property_name, AK::Function<Va | ||||||
|     put(property_name, heap().allocate<NativeFunction>(move(native_function))); |     put(property_name, heap().allocate<NativeFunction>(move(native_function))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Object::put_native_property(const FlyString& property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter) | void Object::put_native_property(const FlyString& property_name, AK::Function<Value(Interpreter&)> getter, AK::Function<void(Interpreter&, Value)> setter) | ||||||
| { | { | ||||||
|     put(property_name, heap().allocate<NativeProperty>(move(getter), move(setter))); |     put(property_name, heap().allocate<NativeProperty>(move(getter), move(setter))); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ public: | ||||||
|     virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value); |     virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value); | ||||||
| 
 | 
 | ||||||
|     void put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)>); |     void put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)>); | ||||||
|     void put_native_property(const FlyString& property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); |     void put_native_property(const FlyString& property_name, AK::Function<Value(Interpreter&)> getter, AK::Function<void(Interpreter&, Value)> setter); | ||||||
| 
 | 
 | ||||||
|     virtual bool is_error() const { return false; } |     virtual bool is_error() const { return false; } | ||||||
|     virtual bool is_array() const { return false; } |     virtual bool is_array() const { return false; } | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <LibJS/Heap/Heap.h> | #include <LibJS/Heap/Heap.h> | ||||||
| #include <LibJS/Interpreter.h> | #include <LibJS/Interpreter.h> | ||||||
|  | #include <LibJS/Runtime/Error.h> | ||||||
| #include <LibJS/Runtime/PrimitiveString.h> | #include <LibJS/Runtime/PrimitiveString.h> | ||||||
| #include <LibJS/Runtime/StringObject.h> | #include <LibJS/Runtime/StringObject.h> | ||||||
| #include <LibJS/Runtime/StringPrototype.h> | #include <LibJS/Runtime/StringPrototype.h> | ||||||
|  | @ -37,13 +38,7 @@ namespace JS { | ||||||
| 
 | 
 | ||||||
| StringPrototype::StringPrototype() | StringPrototype::StringPrototype() | ||||||
| { | { | ||||||
|     put_native_property( |     put_native_property("length", length_getter, nullptr); | ||||||
|         "length", [](Object* this_object) { |  | ||||||
|             ASSERT(this_object); |  | ||||||
|             ASSERT(this_object->is_string_object()); |  | ||||||
|             return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
|     put_native_function("charAt", char_at); |     put_native_function("charAt", char_at); | ||||||
|     put_native_function("repeat", repeat); |     put_native_function("repeat", repeat); | ||||||
| } | } | ||||||
|  | @ -88,4 +83,14 @@ Value StringPrototype::repeat(Interpreter& interpreter) | ||||||
|     return js_string(interpreter.heap(), builder.to_string()); |     return js_string(interpreter.heap(), builder.to_string()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Value StringPrototype::length_getter(Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return {}; | ||||||
|  |     if (!this_object->is_string_object()) | ||||||
|  |         return interpreter.throw_exception<Error>("TypeError", "Not a String object"); | ||||||
|  |     return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -40,6 +40,8 @@ private: | ||||||
| 
 | 
 | ||||||
|     static Value char_at(Interpreter&); |     static Value char_at(Interpreter&); | ||||||
|     static Value repeat(Interpreter&); |     static Value repeat(Interpreter&); | ||||||
|  | 
 | ||||||
|  |     static Value length_getter(Interpreter&); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,14 +43,7 @@ CanvasRenderingContext2DWrapper* wrap(JS::Heap& heap, CanvasRenderingContext2D& | ||||||
| CanvasRenderingContext2DWrapper::CanvasRenderingContext2DWrapper(CanvasRenderingContext2D& impl) | CanvasRenderingContext2DWrapper::CanvasRenderingContext2DWrapper(CanvasRenderingContext2D& impl) | ||||||
|     : m_impl(impl) |     : m_impl(impl) | ||||||
| { | { | ||||||
|     put_native_property( |     put_native_property("fillStyle", fill_style_getter, fill_style_setter); | ||||||
|         "fillStyle", |  | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::js_string(heap(), m_impl->fill_style()); |  | ||||||
|         }, |  | ||||||
|         [this](JS::Object*, JS::Value value) { |  | ||||||
|             m_impl->set_fill_style(value.to_string()); |  | ||||||
|         }); |  | ||||||
|     put_native_function("fillRect", fill_rect); |     put_native_function("fillRect", fill_rect); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -58,18 +51,39 @@ CanvasRenderingContext2DWrapper::~CanvasRenderingContext2DWrapper() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| JS::Value CanvasRenderingContext2DWrapper::fill_rect(JS::Interpreter& interpreter) | static CanvasRenderingContext2D* impl_from(JS::Interpreter& interpreter) | ||||||
| { | { | ||||||
|     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|     if (!this_object) |     if (!this_object) | ||||||
|         return {}; |         return nullptr; | ||||||
|     // FIXME: Verify that it's a CanvasRenderingContext2DWrapper somehow!
 |     // FIXME: Verify that it's a CanvasRenderingContext2DWrapper somehow!
 | ||||||
|     auto& impl = static_cast<CanvasRenderingContext2DWrapper*>(this_object)->impl(); |     return &static_cast<CanvasRenderingContext2DWrapper*>(this_object)->impl(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value CanvasRenderingContext2DWrapper::fill_rect(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* impl = impl_from(interpreter); | ||||||
|  |     if (!impl) | ||||||
|  |         return {}; | ||||||
|     auto& arguments = interpreter.call_frame().arguments; |     auto& arguments = interpreter.call_frame().arguments; | ||||||
|     if (arguments.size() >= 4) |     if (arguments.size() >= 4) | ||||||
|         impl.fill_rect(arguments[0].to_i32(), arguments[1].to_i32(), arguments[2].to_i32(), arguments[3].to_i32()); |         impl->fill_rect(arguments[0].to_i32(), arguments[1].to_i32(), arguments[2].to_i32(), arguments[3].to_i32()); | ||||||
|     return JS::js_undefined(); |     return JS::js_undefined(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | JS::Value CanvasRenderingContext2DWrapper::fill_style_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* impl = impl_from(interpreter); | ||||||
|  |     if (!impl) | ||||||
|  |         return {}; | ||||||
|  |     return JS::js_string(interpreter.heap(), impl->fill_style()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void CanvasRenderingContext2DWrapper::fill_style_setter(JS::Interpreter& interpreter, JS::Value value) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         impl->set_fill_style(value.to_string()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,6 +43,8 @@ private: | ||||||
|     virtual const char* class_name() const override { return "CanvasRenderingContext2DWrapper"; } |     virtual const char* class_name() const override { return "CanvasRenderingContext2DWrapper"; } | ||||||
| 
 | 
 | ||||||
|     static JS::Value fill_rect(JS::Interpreter&); |     static JS::Value fill_rect(JS::Interpreter&); | ||||||
|  |     static JS::Value fill_style_getter(JS::Interpreter&); | ||||||
|  |     static void fill_style_setter(JS::Interpreter&, JS::Value); | ||||||
| 
 | 
 | ||||||
|     NonnullRefPtr<CanvasRenderingContext2D> m_impl; |     NonnullRefPtr<CanvasRenderingContext2D> m_impl; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <AK/FlyString.h> | #include <AK/FlyString.h> | ||||||
| #include <AK/Function.h> | #include <AK/Function.h> | ||||||
|  | #include <LibJS/Interpreter.h> | ||||||
| #include <LibJS/Runtime/PrimitiveString.h> | #include <LibJS/Runtime/PrimitiveString.h> | ||||||
| #include <LibJS/Runtime/Value.h> | #include <LibJS/Runtime/Value.h> | ||||||
| #include <LibWeb/Bindings/ElementWrapper.h> | #include <LibWeb/Bindings/ElementWrapper.h> | ||||||
|  | @ -37,14 +38,7 @@ namespace Bindings { | ||||||
| ElementWrapper::ElementWrapper(Element& element) | ElementWrapper::ElementWrapper(Element& element) | ||||||
|     : NodeWrapper(element) |     : NodeWrapper(element) | ||||||
| { | { | ||||||
|     put_native_property( |     put_native_property("innerHTML", inner_html_getter, inner_html_setter); | ||||||
|         "innerHTML", |  | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::js_string(heap(), node().inner_html()); |  | ||||||
|         }, |  | ||||||
|         [this](JS::Object*, JS::Value value) { |  | ||||||
|             node().set_inner_html(value.to_string()); |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ElementWrapper::~ElementWrapper() | ElementWrapper::~ElementWrapper() | ||||||
|  | @ -61,5 +55,27 @@ const Element& ElementWrapper::node() const | ||||||
|     return static_cast<const Element&>(NodeWrapper::node()); |     return static_cast<const Element&>(NodeWrapper::node()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static Element* impl_from(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return nullptr; | ||||||
|  |     // FIXME: Verify that it's an ElementWrapper somehow!
 | ||||||
|  |     return &static_cast<ElementWrapper*>(this_object)->node(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value ElementWrapper::inner_html_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         return JS::js_string(interpreter.heap(), impl->inner_html()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ElementWrapper::inner_html_setter(JS::Interpreter& interpreter, JS::Value value) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         impl->set_inner_html(value.to_string()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -41,6 +41,9 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     virtual const char* class_name() const override { return "ElementWrapper"; } |     virtual const char* class_name() const override { return "ElementWrapper"; } | ||||||
|  | 
 | ||||||
|  |     static JS::Value inner_html_getter(JS::Interpreter&); | ||||||
|  |     static void inner_html_setter(JS::Interpreter&, JS::Value); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -42,18 +42,8 @@ HTMLCanvasElementWrapper::HTMLCanvasElementWrapper(HTMLCanvasElement& element) | ||||||
| { | { | ||||||
|     put_native_function("getContext", get_context); |     put_native_function("getContext", get_context); | ||||||
| 
 | 
 | ||||||
|     put_native_property( |     put_native_property("width", width_getter, nullptr); | ||||||
|         "width", |     put_native_property("height", height_getter, nullptr); | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::Value(node().preferred_width()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
|     put_native_property( |  | ||||||
|         "height", |  | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::Value(node().preferred_height()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HTMLCanvasElementWrapper::~HTMLCanvasElementWrapper() | HTMLCanvasElementWrapper::~HTMLCanvasElementWrapper() | ||||||
|  | @ -70,20 +60,41 @@ const HTMLCanvasElement& HTMLCanvasElementWrapper::node() const | ||||||
|     return static_cast<const HTMLCanvasElement&>(NodeWrapper::node()); |     return static_cast<const HTMLCanvasElement&>(NodeWrapper::node()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| JS::Value HTMLCanvasElementWrapper::get_context(JS::Interpreter& interpreter) | static HTMLCanvasElement* impl_from(JS::Interpreter& interpreter) | ||||||
| { | { | ||||||
|     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|     if (!this_object) |     if (!this_object) | ||||||
|  |         return nullptr; | ||||||
|  |     // FIXME: Verify that it's a HTMLCanvasElementWrapper somehow!
 | ||||||
|  |     return &static_cast<HTMLCanvasElementWrapper*>(this_object)->node(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value HTMLCanvasElementWrapper::get_context(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* impl = impl_from(interpreter); | ||||||
|  |     if (!impl) | ||||||
|         return {}; |         return {}; | ||||||
|     // FIXME: Verify that it's an HTMLCanvasElementWrapper somehow!
 |  | ||||||
|     auto& node = static_cast<HTMLCanvasElementWrapper*>(this_object)->node(); |  | ||||||
|     auto& arguments = interpreter.call_frame().arguments; |     auto& arguments = interpreter.call_frame().arguments; | ||||||
|     if (arguments.size() >= 1) { |     if (arguments.size() >= 1) { | ||||||
|         auto* context = node.get_context(arguments[0].to_string()); |         auto* context = impl->get_context(arguments[0].to_string()); | ||||||
|         return wrap(interpreter.heap(), *context); |         return wrap(interpreter.heap(), *context); | ||||||
|     } |     } | ||||||
|     return JS::js_undefined(); |     return JS::js_undefined(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | JS::Value HTMLCanvasElementWrapper::width_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         return JS::Value(impl->preferred_width()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value HTMLCanvasElementWrapper::height_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         return JS::Value(impl->preferred_height()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,6 +43,9 @@ private: | ||||||
|     virtual const char* class_name() const override { return "HTMLCanvasElementWrapper"; } |     virtual const char* class_name() const override { return "HTMLCanvasElementWrapper"; } | ||||||
| 
 | 
 | ||||||
|     static JS::Value get_context(JS::Interpreter&); |     static JS::Value get_context(JS::Interpreter&); | ||||||
|  | 
 | ||||||
|  |     static JS::Value width_getter(JS::Interpreter&); | ||||||
|  |     static JS::Value height_getter(JS::Interpreter&); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,8 +24,9 @@ | ||||||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <AK/Function.h> |  | ||||||
| #include <AK/FlyString.h> | #include <AK/FlyString.h> | ||||||
|  | #include <AK/Function.h> | ||||||
|  | #include <LibJS/Interpreter.h> | ||||||
| #include <LibJS/Runtime/Function.h> | #include <LibJS/Runtime/Function.h> | ||||||
| #include <LibWeb/Bindings/MouseEventWrapper.h> | #include <LibWeb/Bindings/MouseEventWrapper.h> | ||||||
| #include <LibWeb/DOM/MouseEvent.h> | #include <LibWeb/DOM/MouseEvent.h> | ||||||
|  | @ -36,18 +37,8 @@ namespace Bindings { | ||||||
| MouseEventWrapper::MouseEventWrapper(MouseEvent& event) | MouseEventWrapper::MouseEventWrapper(MouseEvent& event) | ||||||
|     : EventWrapper(event) |     : EventWrapper(event) | ||||||
| { | { | ||||||
|     put_native_property( |     put_native_property("offsetX", offset_x_getter, nullptr); | ||||||
|         "offsetX", |     put_native_property("offsetY", offset_y_getter, nullptr); | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::Value(this->event().offset_x()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
|     put_native_property( |  | ||||||
|         "offsetY", |  | ||||||
|         [this](JS::Object*) { |  | ||||||
|             return JS::Value(this->event().offset_y()); |  | ||||||
|         }, |  | ||||||
|         nullptr); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MouseEventWrapper::~MouseEventWrapper() | MouseEventWrapper::~MouseEventWrapper() | ||||||
|  | @ -64,5 +55,28 @@ MouseEvent& MouseEventWrapper::event() | ||||||
|     return static_cast<MouseEvent&>(EventWrapper::event()); |     return static_cast<MouseEvent&>(EventWrapper::event()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static MouseEvent* impl_from(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     auto* this_object = interpreter.this_value().to_object(interpreter.heap()); | ||||||
|  |     if (!this_object) | ||||||
|  |         return nullptr; | ||||||
|  |     // FIXME: Verify that it's a CanvasRenderingContext2DWrapper somehow!
 | ||||||
|  |     return &static_cast<MouseEventWrapper*>(this_object)->event(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value MouseEventWrapper::offset_x_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         return JS::Value(impl->offset_x()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JS::Value MouseEventWrapper::offset_y_getter(JS::Interpreter& interpreter) | ||||||
|  | { | ||||||
|  |     if (auto* impl = impl_from(interpreter)) | ||||||
|  |         return JS::Value(impl->offset_y()); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -41,6 +41,9 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     virtual const char* class_name() const override { return "MouseEventWrapper"; } |     virtual const char* class_name() const override { return "MouseEventWrapper"; } | ||||||
|  | 
 | ||||||
|  |     static JS::Value offset_x_getter(JS::Interpreter&); | ||||||
|  |     static JS::Value offset_y_getter(JS::Interpreter&); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -392,7 +392,7 @@ JS::Interpreter& Document::interpreter() | ||||||
| 
 | 
 | ||||||
|         m_interpreter->global_object().put_native_property( |         m_interpreter->global_object().put_native_property( | ||||||
|             "document", |             "document", | ||||||
|             [this](JS::Object*) { |             [this](JS::Interpreter&) { | ||||||
|                 return wrap(m_interpreter->heap(), *this); |                 return wrap(m_interpreter->heap(), *this); | ||||||
|             }, |             }, | ||||||
|             nullptr); |             nullptr); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling