mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 13:27:34 +00:00
LibJS+LibWeb: Add JS::Object::inherits(class_name)
To allow implementing the DOM class hierarchy in JS bindings, this patch adds an inherits() function that can be used to ask an Object if it inherits from a specific C++ class (by name). The necessary overrides are baked into each Object subclass by the new JS_OBJECT macro, which works similarly to C_OBJECT in LibCore. Thanks to @Dexesttp for suggesting this approach. :^)
This commit is contained in:
parent
1914f52371
commit
af51dc105a
57 changed files with 122 additions and 106 deletions
|
@ -32,6 +32,7 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class CanvasRenderingContext2DWrapper final : public Wrapper {
|
||||
JS_OBJECT(CanvasRenderingContext2DWrapper, Wrapper);
|
||||
public:
|
||||
CanvasRenderingContext2DWrapper(JS::GlobalObject&, CanvasRenderingContext2D&);
|
||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
||||
|
@ -41,8 +42,6 @@ public:
|
|||
const CanvasRenderingContext2D& impl() const { return m_impl; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "CanvasRenderingContext2DWrapper"; }
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(fill_rect);
|
||||
JS_DECLARE_NATIVE_FUNCTION(stroke_rect);
|
||||
JS_DECLARE_NATIVE_FUNCTION(draw_image);
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class EventListenerWrapper final : public Wrapper {
|
||||
JS_OBJECT(EventListenerWrapper, Wrapper);
|
||||
|
||||
public:
|
||||
EventListenerWrapper(JS::GlobalObject&, EventListener&);
|
||||
virtual ~EventListenerWrapper() override;
|
||||
|
@ -40,8 +42,6 @@ public:
|
|||
const EventListener& impl() const { return *m_impl; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "EventListenerWrapper"; }
|
||||
|
||||
NonnullRefPtr<EventListener> m_impl;
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class EventWrapper : public Wrapper {
|
||||
JS_OBJECT(EventWrapper, Wrapper);
|
||||
|
||||
public:
|
||||
EventWrapper(JS::GlobalObject&, Event&);
|
||||
virtual ~EventWrapper() override;
|
||||
|
@ -40,8 +42,6 @@ public:
|
|||
const Event& event() const { return m_event; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "EventWrapper"; }
|
||||
|
||||
NonnullRefPtr<Event> m_event;
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class ImageDataWrapper : public Wrapper {
|
||||
JS_OBJECT(ImageDataWrapper, Wrapper);
|
||||
|
||||
public:
|
||||
ImageDataWrapper(JS::GlobalObject&, ImageData&);
|
||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
||||
|
@ -41,8 +43,6 @@ public:
|
|||
const ImageData& impl() const { return m_impl; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "ImageDataWrapper"; }
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(width_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(height_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(data_getter);
|
||||
|
|
|
@ -33,14 +33,14 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class LocationObject final : public JS::Object {
|
||||
JS_OBJECT(LocationObject, JS::Object);
|
||||
|
||||
public:
|
||||
explicit LocationObject(JS::GlobalObject&);
|
||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
||||
virtual ~LocationObject() override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "LocationObject"; }
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(reload);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(href_getter);
|
||||
|
|
|
@ -33,14 +33,14 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class NavigatorObject final : public JS::Object {
|
||||
JS_OBJECT(NavigatorObject, JS::Object);
|
||||
|
||||
public:
|
||||
NavigatorObject(JS::GlobalObject&);
|
||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
||||
virtual ~NavigatorObject() override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "NavigatorObject"; }
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(user_agent_getter);
|
||||
};
|
||||
|
||||
|
|
|
@ -37,20 +37,14 @@ namespace Bindings {
|
|||
class Wrapper
|
||||
: public JS::Object
|
||||
, public Weakable<Wrapper> {
|
||||
public:
|
||||
virtual bool is_event_target_wrapper() const { return false; }
|
||||
virtual bool is_node_wrapper() const { return false; }
|
||||
virtual bool is_document_wrapper() const { return false; }
|
||||
virtual bool is_element_wrapper() const { return false; }
|
||||
virtual bool is_htmlelement_wrapper() const { return false; }
|
||||
JS_OBJECT(Wrapper, JS::Object);
|
||||
|
||||
public:
|
||||
protected:
|
||||
explicit Wrapper(Object& prototype)
|
||||
: Object(&prototype)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool is_web_wrapper() const final { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ namespace Web {
|
|||
namespace Bindings {
|
||||
|
||||
class XMLHttpRequestPrototype final : public JS::Object {
|
||||
JS_OBJECT(XMLHttpRequestPrototype, JS::Object);
|
||||
|
||||
public:
|
||||
explicit XMLHttpRequestPrototype(JS::GlobalObject&);
|
||||
virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;
|
||||
virtual ~XMLHttpRequestPrototype() override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "XMLHttpRequestPrototype"; }
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(open);
|
||||
JS_DECLARE_NATIVE_FUNCTION(send);
|
||||
|
||||
|
|
|
@ -315,6 +315,7 @@ static void generate_header(const IDL::Interface& interface)
|
|||
out() << "namespace Bindings {";
|
||||
|
||||
out() << "class " << wrapper_class << " : public " << wrapper_base_class << " {";
|
||||
out() << " JS_OBJECT(" << wrapper_class << ", " << wrapper_base_class << ");";
|
||||
out() << "public:";
|
||||
out() << " " << wrapper_class << "(JS::GlobalObject&, " << interface.name << "&);";
|
||||
out() << " virtual void initialize(JS::Interpreter&, JS::GlobalObject&) override;";
|
||||
|
@ -332,7 +333,6 @@ static void generate_header(const IDL::Interface& interface)
|
|||
out() << " virtual bool " << is_foo_wrapper_name << "() const final { return true; }";
|
||||
|
||||
out() << "private:";
|
||||
out() << " virtual const char* class_name() const override { return \"" << interface.name << "\"; }";
|
||||
|
||||
for (auto& function : interface.functions) {
|
||||
out() << " JS_DECLARE_NATIVE_FUNCTION(" << snake_name(function.name) << ");";
|
||||
|
@ -412,8 +412,7 @@ void generate_implementation(const IDL::Interface& interface)
|
|||
out() << " auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);";
|
||||
out() << " if (!this_object)";
|
||||
out() << " return {};";
|
||||
auto is_foo_wrapper_name = snake_name(String::format("Is%s", wrapper_class.characters()));
|
||||
out() << " if (!this_object->is_web_wrapper() || !static_cast<Wrapper*>(this_object)->" << is_foo_wrapper_name << "()) {";
|
||||
out() << " if (!this_object->inherits(\"" << wrapper_class << "\")) {";
|
||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << interface.name << "\");";
|
||||
out() << " return nullptr;";
|
||||
out() << " }";
|
||||
|
@ -441,8 +440,7 @@ void generate_implementation(const IDL::Interface& interface)
|
|||
out() << " auto " << cpp_name << "_object = " << js_name << js_suffix << ".to_object(interpreter, global_object);";
|
||||
out() << " if (interpreter.exception())";
|
||||
generate_return();
|
||||
auto is_foo_wrapper_name = snake_name(String::format("Is%sWrapper", parameter.type.name.characters()));
|
||||
out() << " if (!" << cpp_name << "_object->is_web_wrapper() || !static_cast<Wrapper*>(" << cpp_name << "_object)->" << is_foo_wrapper_name << "()) {";
|
||||
out() << " if (!" << cpp_name << "_object->inherits(\"" << parameter.type.name << "Wrapper\")) {";
|
||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << parameter.type.name << "\");";
|
||||
generate_return();
|
||||
out() << " }";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue