[gjs/wip/ptomato/mozjs45: 2/33] jsapi-class: GJS_DEFINE_PROTO stores protos in global slots



commit 0304cc69281684a31e154b94a1476f0713c213ff
Author: Philip Chimento <philip chimento gmail com>
Date:   Sun Apr 9 16:19:48 2017 -0700

    jsapi-class: GJS_DEFINE_PROTO stores protos in global slots
    
    This refactors the GJS_DEFINE_PROTO family of macros to store the created
    prototype objects in slots on the global object. We split up the
    gjs_WHATEVER_create_proto() function into two functions: one that must be
    called at least once for each type to define the class, store the prototype
    in a global slot, and define the constructor as a property on a passed-in
    module or global object, gjs_WHATEVER_define_proto(); and one that
    retrieves the prototype from its global slot, gjs_WHATEVER_get_proto().
    
    We also add two macros, GJS_DEFINE_PROTO_WITH_PARENT and
    GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT, which also move the definition of
    the parent to compile time rather than runtime, and keep it in the same
    place as the rest of each class's macro definition. Similarly, previously
    we had to pass the parent prototype object to gjs_WHATEVER_create_proto().
    
    This mostly affects the cairo module.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=614413

 gi/gtype.cpp                      |   24 +++----
 gjs/jsapi-class.h                 |  119 +++++++++++++++++++++++++------------
 gjs/jsapi-util.h                  |   15 +++++
 modules/cairo-context.cpp         |    6 +-
 modules/cairo-gradient.cpp        |    5 +-
 modules/cairo-image-surface.cpp   |   12 +++-
 modules/cairo-linear-gradient.cpp |   10 ++-
 modules/cairo-path.cpp            |    6 +-
 modules/cairo-pdf-surface.cpp     |    9 ++-
 modules/cairo-private.h           |   93 +++++++++++++++--------------
 modules/cairo-ps-surface.cpp      |    9 ++-
 modules/cairo-radial-gradient.cpp |   10 ++-
 modules/cairo-region.cpp          |    6 +-
 modules/cairo-solid-pattern.cpp   |   10 ++-
 modules/cairo-surface-pattern.cpp |   10 ++-
 modules/cairo-surface.cpp         |    4 +-
 modules/cairo-svg-surface.cpp     |    9 ++-
 modules/cairo.cpp                 |   58 ++++++------------
 18 files changed, 244 insertions(+), 171 deletions(-)
---
diff --git a/gi/gtype.cpp b/gi/gtype.cpp
index cac9640..bfd8d2c 100644
--- a/gi/gtype.cpp
+++ b/gi/gtype.cpp
@@ -35,10 +35,9 @@
 static bool weak_pointer_callback = false;
 static std::set<GType> weak_pointer_list;
 
-static JSObject *
-gjs_gtype_create_proto(JSContext       *context,
-                       JS::HandleObject module,
-                       JS::HandleObject parent);
+static JSObject *gjs_gtype_get_proto(JSContext *) G_GNUC_UNUSED;
+static bool gjs_gtype_define_proto(JSContext *, JS::HandleObject,
+                                   JS::MutableHandleObject);
 
 GJS_DEFINE_PROTO_ABSTRACT("GIRepositoryGType", gtype, 0);
 
@@ -150,31 +149,28 @@ JSObject *
 gjs_gtype_create_gtype_wrapper (JSContext *context,
                                 GType      gtype)
 {
-    JS_BeginRequest(context);
-
-    /* put constructor for GIRepositoryGType() in the global namespace */
-    JS::RootedObject global(context, gjs_get_import_global(context));
-    JS::RootedObject proto(context,
-        gjs_gtype_create_proto(context, global, JS::NullPtr()));
+    JSAutoRequest ar(context);
 
     auto heap_wrapper =
         static_cast<JS::Heap<JSObject *> *>(g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark()));
     if (heap_wrapper != nullptr)
-        goto out;
+        return *heap_wrapper;
+
+    JS::RootedObject proto(context);
+    if (!gjs_gtype_define_proto(context, JS::NullPtr(), &proto))
+        return nullptr;
 
     heap_wrapper = new JS::Heap<JSObject *>();
     *heap_wrapper = JS_NewObjectWithGivenProto(context, &gjs_gtype_class, proto,
                                                JS::NullPtr());
     if (*heap_wrapper == nullptr)
-        goto out;
+        return nullptr;
 
     JS_SetPrivate(*heap_wrapper, GSIZE_TO_POINTER(gtype));
     ensure_weak_pointer_callback(context);
     g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), heap_wrapper);
     weak_pointer_list.insert(gtype);
 
- out:
-    JS_EndRequest(context);
     return *heap_wrapper;
 }
 
diff --git a/gjs/jsapi-class.h b/gjs/jsapi-class.h
index a30519c..86371fa 100644
--- a/gjs/jsapi-class.h
+++ b/gjs/jsapi-class.h
@@ -116,6 +116,13 @@ JSObject *gjs_construct_object_dynamic(JSContext                  *cx,
         return false;                                     \
     type *priv = priv_from_js(cx, to)
 
+/* Helper for GJS_DEFINE_PROTO_* macros with no parent */
+static inline JSObject *
+gjs_no_parent_get_proto(JSContext *cx)
+{
+    return nullptr;
+}
+
 /**
  * GJS_DEFINE_PROTO:
  * @tn: The name of the prototype, as a string
@@ -138,27 +145,29 @@ _GJS_DEFINE_PROTO_FULL(tn, cn, gjs_##cn##_constructor, G_TYPE_NONE, flags)
  * you won't be able to instantiate it using the new keyword
  */
 #define GJS_DEFINE_PROTO_ABSTRACT(tn, cn, flags)                 \
-_GJS_DEFINE_PROTO_FULL(tn, cn, nullptr, G_TYPE_NONE, flags)
+_GJS_DEFINE_PROTO_FULL(tn, cn, no_parent, nullptr, G_TYPE_NONE,  \
+                       flags)
 
 #define GJS_DEFINE_PROTO_WITH_GTYPE(tn, cn, gtype, flags)          \
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cn);                                \
-_GJS_DEFINE_PROTO_FULL(tn, cn, gjs_##cn##_constructor, gtype, flags)
+_GJS_DEFINE_PROTO_FULL(tn, cn, no_parent, gjs_##cn##_constructor,  \
+                       gtype, flags)
 
 #define GJS_DEFINE_PROTO_ABSTRACT_WITH_GTYPE(tn, cn, gtype, flags)  \
-_GJS_DEFINE_PROTO_FULL(tn, cn, nullptr, gtype, flags)
+_GJS_DEFINE_PROTO_FULL(tn, cn, no_parent, nullptr, gtype, flags)
 
-#define GJS_DEFINE_PROTO_WITH_PARENT(tn, cn, flags)     \
-GJS_NATIVE_CONSTRUCTOR_DECLARE(cn);                     \
-_GJS_DEFINE_PROTO_FULL(tn, cn, gjs_##cn##_constructor, G_TYPE_NONE, flags)
+#define GJS_DEFINE_PROTO_WITH_PARENT(tn, cn, parent_cn, flags)     \
+GJS_NATIVE_CONSTRUCTOR_DECLARE(cn);                                \
+_GJS_DEFINE_PROTO_FULL(tn, cn, parent_cn, gjs_##cn##_constructor,  \
+                       G_TYPE_NONE, flags)
 
-#define GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT(tn, cn, flags)  \
-_GJS_DEFINE_PROTO_FULL(tn, cn, nullptr, G_TYPE_NONE, flags)
+#define GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT(tn, cn, parent_cn, flags)  \
+_GJS_DEFINE_PROTO_FULL(tn, cn, parent_cn, nullptr, G_TYPE_NONE, flags)
 
-#define _GJS_DEFINE_PROTO_FULL(type_name, cname, ctor, gtype, jsclass_flags) \
+#define _GJS_DEFINE_PROTO_FULL(type_name, cname, parent_cname, ctor, gtype, jsclass_flags) \
 extern JSPropertySpec gjs_##cname##_proto_props[];                           \
 extern JSFunctionSpec gjs_##cname##_proto_funcs[];                           \
 static void gjs_##cname##_finalize(JSFreeOp *fop, JSObject *obj);            \
-static JS::PersistentRootedObject gjs_##cname##_prototype;                   \
 static struct JSClass gjs_##cname##_class = {                                \
     type_name,                                                               \
     JSCLASS_HAS_PRIVATE | jsclass_flags,                                     \
@@ -172,42 +181,76 @@ static struct JSClass gjs_##cname##_class = {                                \
     gjs_##cname##_finalize                                                   \
 };                                                                           \
 JSObject *                                                                   \
-gjs_##cname##_create_proto(JSContext       *cx,                              \
-                           JS::HandleObject module,                          \
-                           JS::HandleObject parent)                          \
+gjs_##cname##_get_proto(JSContext *cx)                                       \
 {                                                                            \
-    JS::RootedObject rval(cx);                                               \
-    JS::RootedObject global(cx, gjs_get_import_global(cx));                  \
+    JS::RootedValue v_proto(cx,                                              \
+        gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname));         \
+    g_assert(((void) "gjs_" #cname "_define_proto() must be called before "  \
+              "gjs_" #cname "_get_proto()", !v_proto.isUndefined()));        \
+    g_assert(((void) "Someone stored some weird value in a global slot",     \
+              v_proto.isObject()));                                          \
+    return &v_proto.toObject();                                              \
+}                                                                            \
+bool                                                                         \
+gjs_##cname##_define_proto(JSContext              *cx,                       \
+                           JS::HandleObject        module,                   \
+                           JS::MutableHandleObject proto)                    \
+{                                                                            \
+    /* If we've been here more than once, we already have the proto */       \
+    JS::RootedValue v_proto(cx,                                              \
+        gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname));         \
+    if (!v_proto.isUndefined()) {                                            \
+        g_assert(((void) "Someone stored some weird value in a global slot", \
+                  v_proto.isObject()));                                      \
+        proto.set(&v_proto.toObject());                                      \
+        return true;                                                         \
+    }                                                                        \
+                                                                             \
+    /* If module is not given, we are defining a global class */             \
+    JS::RootedObject in_obj(cx, module);                                     \
+    if (!in_obj)                                                             \
+        in_obj = gjs_get_import_global(cx);                                  \
+                                                                             \
+    /* Create the class, prototype, and constructor */                       \
+    JS::RootedObject parent_proto(cx, gjs_##parent_cname##_get_proto(cx));   \
+    proto.set(JS_InitClass(cx, in_obj, parent_proto, &gjs_##cname##_class,   \
+                           ctor, 0, gjs_##cname##_proto_props,               \
+                           gjs_##cname##_proto_funcs, nullptr, nullptr));    \
+    if (!proto)                                                              \
+        return false;                                                        \
+    gjs_set_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname,               \
+                        JS::ObjectValue(*proto));                            \
+                                                                             \
+    /* Look up the constructor (but if no constructor function, then it is   \
+     * equal to the prototype) */                                            \
+    JS::RootedObject ctor_obj(cx, proto);                                    \
     JS::RootedId class_name(cx,                                              \
         gjs_intern_string_to_id(cx, gjs_##cname##_class.name));              \
-    bool found = false;                                                      \
-    if (!JS_AlreadyHasOwnPropertyById(cx, global, class_name, &found))       \
-        return nullptr;                                                      \
-    if (!found) {                                                            \
-        gjs_##cname##_prototype.init(cx);                                    \
-        gjs_##cname##_prototype =                                            \
-            JS_InitClass(cx, global, parent, &gjs_##cname##_class, ctor,     \
-                         0, &gjs_##cname##_proto_props[0],                   \
-                         &gjs_##cname##_proto_funcs[0],                      \
-                         nullptr, nullptr);                                  \
-        if (!gjs_##cname##_prototype)                                        \
-            return nullptr;                                                  \
+    if (ctor != nullptr) {                                                   \
+        if (!gjs_object_require_property(cx, in_obj, #cname " constructor",  \
+                                         class_name, &ctor_obj))             \
+            return false;                                                    \
+    }                                                                        \
+                                                                             \
+    /* JS_InitClass defines the constructor as a property on the given       \
+     * "global" object. If it's a module and not the real global object,     \
+     * redefine it with different flags so it's enumerable; cairo copies     \
+     * properties from cairoNative, for example */                           \
+    if (module) {                                                            \
+        if (!JS_DefinePropertyById(cx, module, class_name, ctor_obj,         \
+                                   GJS_MODULE_PROP_FLAGS))                   \
+            return false;                                                    \
     }                                                                        \
-    if (!gjs_object_require_property(cx, global, nullptr,                    \
-                                     class_name, &rval))                     \
-        return nullptr;                                                      \
-    if (found)                                                               \
-        return rval;                                                         \
-    if (!JS_DefinePropertyById(cx, module, class_name,                       \
-                               rval, GJS_MODULE_PROP_FLAGS))                 \
-        return nullptr;                                                      \
+                                                                             \
+    /* Define the GType value as a "$gtype" property on the constructor */   \
     if (gtype != G_TYPE_NONE) {                                              \
         JS::RootedObject gtype_obj(cx,                                       \
             gjs_gtype_create_gtype_wrapper(cx, gtype));                      \
-        JS_DefineProperty(cx, rval, "$gtype", gtype_obj,                     \
-                          JSPROP_PERMANENT);                                 \
+        if (!JS_DefineProperty(cx, ctor_obj, "$gtype", gtype_obj,            \
+                               JSPROP_PERMANENT))                            \
+            return false;                                                    \
     }                                                                        \
-    return rval;                                                             \
+    return true;                                                             \
 }
 
 /**
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index b640056..e8a6ca7 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -74,7 +74,22 @@ enum {
 
 typedef enum {
     GJS_GLOBAL_SLOT_IMPORTS,
+    GJS_GLOBAL_SLOT_PROTOTYPE_gtype,
     GJS_GLOBAL_SLOT_BYTE_ARRAY_PROTOTYPE,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_context,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_gradient,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_image_surface,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_linear_gradient,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_path,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_pattern,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_pdf_surface,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_ps_surface,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_radial_gradient,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_region,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_solid_pattern,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_surface,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_surface_pattern,
+    GJS_GLOBAL_SLOT_PROTOTYPE_cairo_svg_surface,
     GJS_GLOBAL_SLOT_LAST,
 } GjsGlobalSlot;
 
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index 66bc9d5..cc43992 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -238,6 +238,8 @@ typedef struct {
     cairo_t * cr;
 } GjsCairoContext;
 
+static JSObject *gjs_cairo_context_get_proto(JSContext *);
+
 GJS_DEFINE_PROTO_WITH_GTYPE("Context", cairo_context,
                             CAIRO_GOBJECT_TYPE_CONTEXT,
                             JSCLASS_BACKGROUND_FINALIZE)
@@ -925,9 +927,9 @@ JSObject *
 gjs_cairo_context_from_context(JSContext *context,
                                cairo_t *cr)
 {
+    JS::RootedObject proto(context, gjs_cairo_context_get_proto(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_context_class,
-                                   gjs_cairo_context_prototype));
+        JS_NewObjectWithGivenProto(context, &gjs_cairo_context_class, proto));
     if (!object)
         return NULL;
 
diff --git a/modules/cairo-gradient.cpp b/modules/cairo-gradient.cpp
index 18138ae..b551d34 100644
--- a/modules/cairo-gradient.cpp
+++ b/modules/cairo-gradient.cpp
@@ -28,8 +28,9 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO_ABSTRACT("Gradient", cairo_gradient,
-                          JSCLASS_BACKGROUND_FINALIZE)
+GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT("Gradient", cairo_gradient,
+                                      cairo_pattern,
+                                      JSCLASS_BACKGROUND_FINALIZE)
 
 static void
 gjs_cairo_gradient_finalize(JSFreeOp *fop,
diff --git a/modules/cairo-image-surface.cpp b/modules/cairo-image-surface.cpp
index 3d009cd..cca5256 100644
--- a/modules/cairo-image-surface.cpp
+++ b/modules/cairo-image-surface.cpp
@@ -29,8 +29,10 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO("ImageSurface", cairo_image_surface,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_image_surface_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("ImageSurface", cairo_image_surface,
+                             cairo_surface, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_image_surface)
 {
@@ -89,9 +91,10 @@ createFromPNG_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_surface_status(surface), "surface"))
         return false;
 
+    JS::RootedObject proto(context, gjs_cairo_image_surface_get_proto(context));
     JS::RootedObject surface_wrapper(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_image_surface_class,
-                                   gjs_cairo_image_surface_prototype));
+                                   proto));
     if (!surface_wrapper) {
         gjs_throw(context, "failed to create surface");
         return false;
@@ -217,9 +220,10 @@ gjs_cairo_image_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(surface != NULL, NULL);
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_image_surface_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_image_surface_class,
-                                   gjs_cairo_image_surface_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create image surface");
         return NULL;
diff --git a/modules/cairo-linear-gradient.cpp b/modules/cairo-linear-gradient.cpp
index 7bbcff0..cbe6be7 100644
--- a/modules/cairo-linear-gradient.cpp
+++ b/modules/cairo-linear-gradient.cpp
@@ -28,8 +28,10 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO("LinearGradient", cairo_linear_gradient,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_linear_gradient_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("LinearGradient", cairo_linear_gradient,
+                             cairo_gradient, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_linear_gradient)
 {
@@ -83,9 +85,11 @@ gjs_cairo_linear_gradient_from_pattern(JSContext       *context,
     g_return_val_if_fail(pattern != NULL, NULL);
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_LINEAR, NULL);
 
+    JS::RootedObject proto(context,
+                           gjs_cairo_linear_gradient_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_linear_gradient_class,
-                                   gjs_cairo_linear_gradient_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create linear gradient pattern");
         return NULL;
diff --git a/modules/cairo-path.cpp b/modules/cairo-path.cpp
index 09ac852..dbd990e 100644
--- a/modules/cairo-path.cpp
+++ b/modules/cairo-path.cpp
@@ -34,6 +34,8 @@ typedef struct {
     cairo_path_t    *path;
 } GjsCairoPath;
 
+static JSObject *gjs_cairo_path_get_proto(JSContext *);
+
 GJS_DEFINE_PROTO_ABSTRACT("Path", cairo_path, JSCLASS_BACKGROUND_FINALIZE)
 GJS_DEFINE_PRIV_FROM_JS(GjsCairoPath, gjs_cairo_path_class)
 
@@ -75,9 +77,9 @@ gjs_cairo_path_from_path(JSContext    *context,
     g_return_val_if_fail(context != NULL, NULL);
     g_return_val_if_fail(path != NULL, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_path_get_proto(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_path_class,
-                                   gjs_cairo_path_prototype));
+        JS_NewObjectWithGivenProto(context, &gjs_cairo_path_class, proto));
     if (!object) {
         gjs_throw(context, "failed to create path");
         return NULL;
diff --git a/modules/cairo-pdf-surface.cpp b/modules/cairo-pdf-surface.cpp
index fe211ae..b1dc925 100644
--- a/modules/cairo-pdf-surface.cpp
+++ b/modules/cairo-pdf-surface.cpp
@@ -31,8 +31,10 @@
 #if CAIRO_HAS_PDF_SURFACE
 #include <cairo-pdf.h>
 
-GJS_DEFINE_PROTO("PDFSurface", cairo_pdf_surface,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_pdf_surface_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("PDFSurface", cairo_pdf_surface,
+                             cairo_surface, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_pdf_surface)
 {
@@ -89,9 +91,10 @@ gjs_cairo_pdf_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(surface != NULL, NULL);
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_PDF, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_pdf_surface_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_pdf_surface_class,
-                                   gjs_cairo_pdf_surface_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create pdf surface");
         return NULL;
diff --git a/modules/cairo-private.h b/modules/cairo-private.h
index ab77bac..caef140 100644
--- a/modules/cairo-private.h
+++ b/modules/cairo-private.h
@@ -30,15 +30,15 @@ bool             gjs_cairo_check_status                 (JSContext       *contex
                                                          cairo_status_t   status,
                                                          const char      *name);
 
-JSObject *gjs_cairo_region_create_proto(JSContext       *cx,
-                                        JS::HandleObject module,
-                                        JS::HandleObject parent);
+bool gjs_cairo_region_define_proto(JSContext              *cx,
+                                   JS::HandleObject        module,
+                                   JS::MutableHandleObject proto);
 
 void             gjs_cairo_region_init                  (JSContext       *context);
 
-JSObject *gjs_cairo_context_create_proto(JSContext       *cx,
-                                         JS::HandleObject module,
-                                         JS::HandleObject parent);
+bool gjs_cairo_context_define_proto(JSContext              *cx,
+                                    JS::HandleObject        module,
+                                    JS::MutableHandleObject proto);
 
 cairo_t *        gjs_cairo_context_get_context          (JSContext       *context,
                                                          JS::HandleObject object);
@@ -47,11 +47,10 @@ JSObject *       gjs_cairo_context_from_context         (JSContext       *contex
 void             gjs_cairo_context_init                 (JSContext       *context);
 void             gjs_cairo_surface_init                 (JSContext       *context);
 
-
-/* cairo_path_t */
-JSObject *gjs_cairo_path_create_proto(JSContext       *cx,
-                                      JS::HandleObject module,
-                                      JS::HandleObject parent);
+/* path */
+bool gjs_cairo_path_define_proto(JSContext              *cx,
+                                 JS::HandleObject        module,
+                                 JS::MutableHandleObject proto);
 
 JSObject *       gjs_cairo_path_from_path               (JSContext       *context,
                                                          cairo_path_t    *path);
@@ -59,9 +58,11 @@ cairo_path_t *   gjs_cairo_path_get_path                (JSContext       *contex
                                                          JSObject        *path_wrapper);
 
 /* surface */
-JSObject *gjs_cairo_surface_create_proto(JSContext       *cx,
-                                         JS::HandleObject module,
-                                         JS::HandleObject parent);
+JSObject *gjs_cairo_surface_get_proto(JSContext *cx);
+
+bool gjs_cairo_surface_define_proto(JSContext              *cx,
+                                    JS::HandleObject        module,
+                                    JS::MutableHandleObject proto);
 
 void             gjs_cairo_surface_construct            (JSContext       *context,
                                                          JS::HandleObject object,
@@ -74,9 +75,9 @@ cairo_surface_t* gjs_cairo_surface_get_surface          (JSContext       *contex
                                                          JSObject        *object);
 
 /* image surface */
-JSObject *gjs_cairo_image_surface_create_proto(JSContext       *cx,
-                                               JS::HandleObject module,
-                                               JS::HandleObject parent);
+bool gjs_cairo_image_surface_define_proto(JSContext              *cx,
+                                          JS::HandleObject        module,
+                                          JS::MutableHandleObject proto);
 
 void             gjs_cairo_image_surface_init           (JSContext       *context,
                                                          JS::HandleObject proto);
@@ -86,35 +87,37 @@ JSObject *       gjs_cairo_image_surface_from_surface   (JSContext       *contex
 
 /* postscript surface */
 #ifdef CAIRO_HAS_PS_SURFACE
-JSObject *gjs_cairo_ps_surface_create_proto(JSContext       *cx,
-                                            JS::HandleObject module,
-                                            JS::HandleObject parent);
+bool gjs_cairo_ps_surface_define_proto(JSContext              *cx,
+                                       JS::HandleObject        module,
+                                       JS::MutableHandleObject proto);
 #endif
 JSObject *       gjs_cairo_ps_surface_from_surface       (JSContext       *context,
                                                           cairo_surface_t *surface);
 
 /* pdf surface */
 #ifdef CAIRO_HAS_PDF_SURFACE
-JSObject *gjs_cairo_pdf_surface_create_proto(JSContext       *cx,
-                                             JS::HandleObject module,
-                                             JS::HandleObject parent);
+bool gjs_cairo_pdf_surface_define_proto(JSContext              *cx,
+                                        JS::HandleObject        module,
+                                        JS::MutableHandleObject proto);
 #endif
 JSObject *       gjs_cairo_pdf_surface_from_surface     (JSContext       *context,
                                                          cairo_surface_t *surface);
 
 /* svg surface */
 #ifdef CAIRO_HAS_SVG_SURFACE
-JSObject *gjs_cairo_svg_surface_create_proto(JSContext       *cx,
-                                             JS::HandleObject module,
-                                             JS::HandleObject parent);
+bool gjs_cairo_svg_surface_define_proto(JSContext              *cx,
+                                        JS::HandleObject        module,
+                                        JS::MutableHandleObject proto);
 #endif
 JSObject *       gjs_cairo_svg_surface_from_surface     (JSContext       *context,
                                                          cairo_surface_t *surface);
 
 /* pattern */
-JSObject *gjs_cairo_pattern_create_proto(JSContext       *cx,
-                                         JS::HandleObject module,
-                                         JS::HandleObject parent);
+JSObject *gjs_cairo_pattern_get_proto(JSContext *cx);
+
+bool gjs_cairo_pattern_define_proto(JSContext              *cx,
+                                    JS::HandleObject        module,
+                                    JS::MutableHandleObject proto);
 
 void             gjs_cairo_pattern_construct            (JSContext       *context,
                                                          JS::HandleObject object,
@@ -127,38 +130,40 @@ cairo_pattern_t* gjs_cairo_pattern_get_pattern          (JSContext       *contex
                                                          JSObject        *object);
 
 /* gradient */
-JSObject *gjs_cairo_gradient_create_proto(JSContext       *cx,
-                                          JS::HandleObject module,
-                                          JS::HandleObject parent);
+JSObject *gjs_cairo_gradient_get_proto(JSContext *cx);
+
+bool gjs_cairo_gradient_define_proto(JSContext              *cx,
+                                     JS::HandleObject        module,
+                                     JS::MutableHandleObject proto);
 
 /* linear gradient */
-JSObject *gjs_cairo_linear_gradient_create_proto(JSContext       *cx,
-                                                 JS::HandleObject module,
-                                                 JS::HandleObject parent);
+bool gjs_cairo_linear_gradient_define_proto(JSContext              *cx,
+                                            JS::HandleObject        module,
+                                            JS::MutableHandleObject proto);
 
 JSObject *       gjs_cairo_linear_gradient_from_pattern (JSContext       *context,
                                                          cairo_pattern_t *pattern);
 
 /* radial gradient */
-JSObject *gjs_cairo_radial_gradient_create_proto(JSContext       *cx,
-                                                 JS::HandleObject module,
-                                                 JS::HandleObject parent);
+bool gjs_cairo_radial_gradient_define_proto(JSContext              *cx,
+                                            JS::HandleObject        module,
+                                            JS::MutableHandleObject proto);
 
 JSObject *       gjs_cairo_radial_gradient_from_pattern (JSContext       *context,
                                                          cairo_pattern_t *pattern);
 
 /* surface pattern */
-JSObject *gjs_cairo_surface_pattern_create_proto(JSContext       *cx,
-                                                 JS::HandleObject module,
-                                                 JS::HandleObject parent);
+bool gjs_cairo_surface_pattern_define_proto(JSContext              *cx,
+                                            JS::HandleObject        module,
+                                            JS::MutableHandleObject proto);
 
 JSObject *       gjs_cairo_surface_pattern_from_pattern (JSContext       *context,
                                                          cairo_pattern_t *pattern);
 
 /* solid pattern */
-JSObject *gjs_cairo_solid_pattern_create_proto(JSContext       *cx,
-                                               JS::HandleObject module,
-                                               JS::HandleObject parent);
+bool gjs_cairo_solid_pattern_define_proto(JSContext              *cx,
+                                          JS::HandleObject        module,
+                                          JS::MutableHandleObject proto);
 
 JSObject *       gjs_cairo_solid_pattern_from_pattern   (JSContext       *context,
                                                          cairo_pattern_t *pattern);
diff --git a/modules/cairo-ps-surface.cpp b/modules/cairo-ps-surface.cpp
index 478d605..b1051ed 100644
--- a/modules/cairo-ps-surface.cpp
+++ b/modules/cairo-ps-surface.cpp
@@ -31,7 +31,10 @@
 #if CAIRO_HAS_PS_SURFACE
 #include <cairo-ps.h>
 
-GJS_DEFINE_PROTO("PSSurface", cairo_ps_surface, JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_ps_surface_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("PSSurface", cairo_ps_surface, cairo_surface,
+                             JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_ps_surface)
 {
@@ -97,9 +100,9 @@ gjs_cairo_ps_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(surface != NULL, NULL);
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_PS, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_ps_surface_get_proto(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_ps_surface_class,
-                                   gjs_cairo_ps_surface_prototype));
+        JS_NewObjectWithGivenProto(context, &gjs_cairo_ps_surface_class, proto));
     if (!object) {
         gjs_throw(context, "failed to create ps surface");
         return NULL;
diff --git a/modules/cairo-radial-gradient.cpp b/modules/cairo-radial-gradient.cpp
index 59785f9..7c54f51 100644
--- a/modules/cairo-radial-gradient.cpp
+++ b/modules/cairo-radial-gradient.cpp
@@ -28,8 +28,10 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO("RadialGradient", cairo_radial_gradient,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_radial_gradient_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("RadialGradient", cairo_radial_gradient,
+                             cairo_gradient, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_radial_gradient)
 {
@@ -85,9 +87,11 @@ gjs_cairo_radial_gradient_from_pattern(JSContext       *context,
     g_return_val_if_fail(pattern != NULL, NULL);
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_RADIAL, NULL);
 
+    JS::RootedObject proto(context,
+                           gjs_cairo_radial_gradient_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_radial_gradient_class,
-                                   gjs_cairo_radial_gradient_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create radial gradient pattern");
         return NULL;
diff --git a/modules/cairo-region.cpp b/modules/cairo-region.cpp
index 9fdf436..23eb31a 100644
--- a/modules/cairo-region.cpp
+++ b/modules/cairo-region.cpp
@@ -37,6 +37,8 @@ typedef struct {
     cairo_region_t *region;
 } GjsCairoRegion;
 
+static JSObject *gjs_cairo_region_get_proto(JSContext *);
+
 GJS_DEFINE_PROTO_WITH_GTYPE("Region", cairo_region,
                             CAIRO_GOBJECT_TYPE_REGION,
                             JSCLASS_BACKGROUND_FINALIZE)
@@ -279,9 +281,9 @@ static JSObject *
 gjs_cairo_region_from_region(JSContext *context,
                              cairo_region_t *region)
 {
+    JS::RootedObject proto(context, gjs_cairo_region_get_proto(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_region_class,
-                                   gjs_cairo_region_prototype));
+        JS_NewObjectWithGivenProto(context, &gjs_cairo_region_class, proto));
     if (!object)
         return NULL;
 
diff --git a/modules/cairo-solid-pattern.cpp b/modules/cairo-solid-pattern.cpp
index 1c603f4..edd91b7 100644
--- a/modules/cairo-solid-pattern.cpp
+++ b/modules/cairo-solid-pattern.cpp
@@ -28,8 +28,11 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO_ABSTRACT("SolidPattern", cairo_solid_pattern,
-                          JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_solid_pattern_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT("SolidPattern", cairo_solid_pattern,
+                                      cairo_pattern,
+                                      JSCLASS_BACKGROUND_FINALIZE)
 
 static void
 gjs_cairo_solid_pattern_finalize(JSFreeOp *fop,
@@ -113,9 +116,10 @@ gjs_cairo_solid_pattern_from_pattern(JSContext       *context,
     g_return_val_if_fail(pattern != NULL, NULL);
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SOLID, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_solid_pattern_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_solid_pattern_class,
-                                   gjs_cairo_solid_pattern_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create solid pattern");
         return NULL;
diff --git a/modules/cairo-surface-pattern.cpp b/modules/cairo-surface-pattern.cpp
index 6f96095..fcf289d 100644
--- a/modules/cairo-surface-pattern.cpp
+++ b/modules/cairo-surface-pattern.cpp
@@ -28,8 +28,10 @@
 #include <cairo.h>
 #include "cairo-private.h"
 
-GJS_DEFINE_PROTO("SurfacePattern", cairo_surface_pattern,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_surface_pattern_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("SurfacePattern", cairo_surface_pattern,
+                             cairo_pattern, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_surface_pattern)
 {
@@ -188,9 +190,11 @@ gjs_cairo_surface_pattern_from_pattern(JSContext       *context,
     g_return_val_if_fail(pattern != NULL, NULL);
     g_return_val_if_fail(cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SURFACE, NULL);
 
+    JS::RootedObject proto(context,
+                           gjs_cairo_surface_pattern_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_surface_pattern_class,
-                                   gjs_cairo_surface_pattern_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create surface pattern");
         return NULL;
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp
index 50439aa..5d31e4b 100644
--- a/modules/cairo-surface.cpp
+++ b/modules/cairo-surface.cpp
@@ -208,9 +208,9 @@ gjs_cairo_surface_from_surface(JSContext       *context,
     if (type == CAIRO_SURFACE_TYPE_SVG)
         return gjs_cairo_svg_surface_from_surface(context, surface);
 
+    JS::RootedObject proto(context, gjs_cairo_surface_get_proto(context));
     JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_surface_class,
-                                   gjs_cairo_surface_prototype));
+        JS_NewObjectWithGivenProto(context, &gjs_cairo_surface_class, proto));
     if (!object) {
         gjs_throw(context, "failed to create surface");
         return NULL;
diff --git a/modules/cairo-svg-surface.cpp b/modules/cairo-svg-surface.cpp
index e10ccb7..2a409eb 100644
--- a/modules/cairo-svg-surface.cpp
+++ b/modules/cairo-svg-surface.cpp
@@ -31,8 +31,10 @@
 #if CAIRO_HAS_SVG_SURFACE
 #include <cairo-svg.h>
 
-GJS_DEFINE_PROTO("SVGSurface", cairo_svg_surface,
-                 JSCLASS_BACKGROUND_FINALIZE)
+static JSObject *gjs_cairo_svg_surface_get_proto(JSContext *);
+
+GJS_DEFINE_PROTO_WITH_PARENT("SVGSurface", cairo_svg_surface,
+                             cairo_surface, JSCLASS_BACKGROUND_FINALIZE)
 
 GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_svg_surface)
 {
@@ -89,9 +91,10 @@ gjs_cairo_svg_surface_from_surface(JSContext       *context,
     g_return_val_if_fail(surface != NULL, NULL);
     g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_SVG, NULL);
 
+    JS::RootedObject proto(context, gjs_cairo_svg_surface_get_proto(context));
     JS::RootedObject object(context,
         JS_NewObjectWithGivenProto(context, &gjs_cairo_svg_surface_class,
-                                   gjs_cairo_svg_surface_prototype));
+                                   proto));
     if (!object) {
         gjs_throw(context, "failed to create svg surface");
         return NULL;
diff --git a/modules/cairo.cpp b/modules/cairo.cpp
index b562ac0..d414b6a 100644
--- a/modules/cairo.cpp
+++ b/modules/cairo.cpp
@@ -60,63 +60,41 @@ gjs_js_define_cairo_stuff(JSContext              *context,
                           JS::MutableHandleObject module)
 {
     module.set(JS_NewObject(context, NULL));
+    JS::RootedObject proto(context);  /* not used */
 
-    if (!gjs_cairo_region_create_proto(context, module, JS::NullPtr()))
+    if (!gjs_cairo_region_define_proto(context, module, &proto))
         return false;
     gjs_cairo_region_init(context);
 
-    if (!gjs_cairo_context_create_proto(context, module, JS::NullPtr()))
+    if (!gjs_cairo_context_define_proto(context, module, &proto))
         return false;
     gjs_cairo_context_init(context);
 
-    JS::RootedObject surface_proto(context,
-        gjs_cairo_surface_create_proto(context, module, JS::NullPtr()));
-    if (!surface_proto)
+    if (!gjs_cairo_surface_define_proto(context, module, &proto))
         return false;
     gjs_cairo_surface_init(context);
 
-    JS::RootedObject image_surface_proto(context,
-        gjs_cairo_image_surface_create_proto(context, module, surface_proto));
-    if (!image_surface_proto)
+    JS::RootedObject image_surface_proto(context);
+    if (!gjs_cairo_image_surface_define_proto(context, module,
+                                              &image_surface_proto))
         return false;
     gjs_cairo_image_surface_init(context, image_surface_proto);
 
+    return
+        gjs_cairo_path_define_proto(context, module, &proto) &&
 #if CAIRO_HAS_PS_SURFACE
-    if (!gjs_cairo_ps_surface_create_proto(context, module, surface_proto))
-        return false;
+        gjs_cairo_ps_surface_define_proto(context, module, &proto) &&
 #endif
-
 #if CAIRO_HAS_PDF_SURFACE
-    if (!gjs_cairo_pdf_surface_create_proto(context, module, surface_proto))
-        return false;
+        gjs_cairo_pdf_surface_define_proto(context, module, &proto) &&
 #endif
-
 #if CAIRO_HAS_SVG_SURFACE
-    if (!gjs_cairo_svg_surface_create_proto(context, module, surface_proto))
-        return false;
+        gjs_cairo_svg_surface_define_proto(context, module, &proto) &&
 #endif
-
-    JS::RootedObject pattern_proto(context,
-        gjs_cairo_pattern_create_proto(context, module, JS::NullPtr()));
-    if (!pattern_proto)
-        return false;
-
-    JS::RootedObject gradient_proto(context,
-        gjs_cairo_gradient_create_proto(context, module, pattern_proto));
-    if (!gradient_proto)
-        return false;
-
-    if (!gjs_cairo_linear_gradient_create_proto(context, module, gradient_proto))
-        return false;
-
-    if (!gjs_cairo_radial_gradient_create_proto(context, module, gradient_proto))
-        return false;
-
-    if (!gjs_cairo_surface_pattern_create_proto(context, module, pattern_proto))
-        return false;
-
-    if (!gjs_cairo_solid_pattern_create_proto(context, module, pattern_proto))
-        return false;
-
-    return true;
+        gjs_cairo_pattern_define_proto(context, module, &proto) &&
+        gjs_cairo_gradient_define_proto(context, module, &proto) &&
+        gjs_cairo_linear_gradient_define_proto(context, module, &proto) &&
+        gjs_cairo_radial_gradient_define_proto(context, module, &proto) &&
+        gjs_cairo_surface_pattern_define_proto(context, module, &proto) &&
+        gjs_cairo_solid_pattern_define_proto(context, module, &proto);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]