[gjs: 7/12] cairo: Remove JSClass macros from CairoPattern and subclasses




commit ada5b4d8c4d6826d37bb768efcbf78895081fc58
Author: Philip Chimento <philip chimento gmail com>
Date:   Mon May 11 09:13:07 2020 -0700

    cairo: Remove JSClass macros from CairoPattern and subclasses
    
    Remove the usage of the GJS_DEFINE_PRIV_FROM_JS and GJS_DEFINE_PROTO
    families of macros from the Cairo pattern wrapper types. Use CWrapper
    instead, for more type safety and less boilerplate.

 modules/cairo-context.cpp         |   6 +-
 modules/cairo-gradient.cpp        |  26 ++--
 modules/cairo-linear-gradient.cpp |  77 +++--------
 modules/cairo-pattern.cpp         |  85 ++++--------
 modules/cairo-private.h           | 272 ++++++++++++++++++++++++++++++--------
 modules/cairo-radial-gradient.cpp |  77 +++--------
 modules/cairo-solid-pattern.cpp   |  61 ++-------
 modules/cairo-surface-pattern.cpp |  82 +++---------
 modules/cairo.cpp                 |  12 +-
 9 files changed, 325 insertions(+), 373 deletions(-)
---
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index b1693239..aff8c7b5 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -448,8 +448,7 @@ mask_func(JSContext *context,
                              "pattern", &pattern_wrapper))
         return false;
 
-    cairo_pattern_t* pattern =
-        gjs_cairo_pattern_get_pattern(context, pattern_wrapper);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, pattern_wrapper);
     if (!pattern)
         return false;
 
@@ -566,8 +565,7 @@ setSource_func(JSContext *context,
                              "pattern", &pattern_wrapper))
         return false;
 
-    cairo_pattern_t* pattern =
-        gjs_cairo_pattern_get_pattern(context, pattern_wrapper);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, pattern_wrapper);
     if (!pattern)
         return false;
 
diff --git a/modules/cairo-gradient.cpp b/modules/cairo-gradient.cpp
index 04859431..07c29328 100644
--- a/modules/cairo-gradient.cpp
+++ b/modules/cairo-gradient.cpp
@@ -7,32 +7,26 @@
 #include <cairo.h>
 
 #include <js/CallArgs.h>
-#include <js/Class.h>
 #include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
 #include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
+#include <jsapi.h>    // for JS_NewObjectWithGivenProto
+#include <jspubtd.h>  // for JSProtoKey
 
-#include "gjs/jsapi-class.h"
 #include "gjs/jsapi-util-args.h"
 #include "gjs/jsapi-util.h"
 #include "gjs/macros.h"
 #include "modules/cairo-private.h"
 
-GJS_DEFINE_PROTO_ABSTRACT_WITH_PARENT("Gradient", cairo_gradient,
-                                      cairo_pattern,
-                                      JSCLASS_BACKGROUND_FINALIZE)
-
-static void
-gjs_cairo_gradient_finalize(JSFreeOp *fop,
-                            JSObject *obj)
-{
-    gjs_cairo_pattern_finalize_pattern(fop, obj);
+JSObject* CairoGradient::new_proto(JSContext* cx, JSProtoKey) {
+    JS::RootedObject parent_proto(cx, CairoPattern::prototype(cx));
+    return JS_NewObjectWithGivenProto(cx, nullptr, parent_proto);
 }
 
 /* Properties */
 // clang-format off
-JSPropertySpec gjs_cairo_gradient_proto_props[] = {
+const JSPropertySpec CairoGradient::proto_props[] = {
     JS_STRING_SYM_PS(toStringTag, "Gradient", JSPROP_READONLY),
     JS_PS_END};
 // clang-format on
@@ -55,7 +49,7 @@ addColorStopRGB_func(JSContext *context,
                              "blue", &blue))
         return false;
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -85,7 +79,7 @@ addColorStopRGBA_func(JSContext *context,
                              "alpha", &alpha))
         return false;
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -98,11 +92,9 @@ addColorStopRGBA_func(JSContext *context,
     return true;
 }
 
-JSFunctionSpec gjs_cairo_gradient_proto_funcs[] = {
+const JSFunctionSpec CairoGradient::proto_funcs[] = {
     JS_FN("addColorStopRGB", addColorStopRGB_func, 0, 0),
     JS_FN("addColorStopRGBA", addColorStopRGBA_func, 0, 0),
     // getColorStopRGB
     // getColorStopRGBA
     JS_FS_END};
-
-JSFunctionSpec gjs_cairo_gradient_static_funcs[] = { JS_FS_END };
diff --git a/modules/cairo-linear-gradient.cpp b/modules/cairo-linear-gradient.cpp
index 04693de9..13842396 100644
--- a/modules/cairo-linear-gradient.cpp
+++ b/modules/cairo-linear-gradient.cpp
@@ -5,92 +5,49 @@
 #include <config.h>
 
 #include <cairo.h>
-#include <glib.h>
 
-#include <js/Class.h>
 #include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
 #include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
 #include <jsapi.h>  // for JS_NewObjectWithGivenProto
+#include <jspubtd.h>  // for JSProtoKey
 
-#include "gjs/jsapi-class.h"
 #include "gjs/jsapi-util-args.h"
-#include "gjs/jsapi-util.h"
 #include "modules/cairo-private.h"
 
-[[nodiscard]] static JSObject* gjs_cairo_linear_gradient_get_proto(JSContext*);
+namespace JS {
+class CallArgs;
+}
 
-GJS_DEFINE_PROTO_WITH_PARENT("LinearGradient", cairo_linear_gradient,
-                             cairo_gradient, JSCLASS_BACKGROUND_FINALIZE)
+JSObject* CairoLinearGradient::new_proto(JSContext* cx, JSProtoKey) {
+    JS::RootedObject parent_proto(cx, CairoGradient::prototype(cx));
+    return JS_NewObjectWithGivenProto(cx, nullptr, parent_proto);
+}
 
-GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_linear_gradient)
-{
-    GJS_NATIVE_CONSTRUCTOR_VARIABLES(cairo_linear_gradient)
+cairo_pattern_t* CairoLinearGradient::constructor_impl(
+    JSContext* context, const JS::CallArgs& argv) {
     double x0, y0, x1, y1;
-    cairo_pattern_t *pattern;
-
-    GJS_NATIVE_CONSTRUCTOR_PRELUDE(cairo_linear_gradient);
-
+    cairo_pattern_t* pattern;
     if (!gjs_parse_call_args(context, "LinearGradient", argv, "ffff",
                              "x0", &x0,
                              "y0", &y0,
                              "x1", &x1,
                              "y1", &y1))
-        return false;
+        return nullptr;
 
     pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
 
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
-        return false;
-
-    gjs_cairo_pattern_construct(object, pattern);
-    cairo_pattern_destroy(pattern);
-
-    GJS_NATIVE_CONSTRUCTOR_FINISH(cairo_linear_gradient);
-
-    return true;
-}
+        return nullptr;
 
-static void
-gjs_cairo_linear_gradient_finalize(JSFreeOp *fop,
-                                   JSObject *obj)
-{
-    gjs_cairo_pattern_finalize_pattern(fop, obj);
+    return pattern;
 }
 
-JSPropertySpec gjs_cairo_linear_gradient_proto_props[] = {
+const JSPropertySpec CairoLinearGradient::proto_props[] = {
     JS_STRING_SYM_PS(toStringTag, "LinearGradient", JSPROP_READONLY),
     JS_PS_END};
 
-JSFunctionSpec gjs_cairo_linear_gradient_proto_funcs[] = {
+const JSFunctionSpec CairoLinearGradient::proto_funcs[] = {
     // getLinearPoints
-    JS_FS_END
-};
-
-JSFunctionSpec gjs_cairo_linear_gradient_static_funcs[] = { JS_FS_END };
-
-JSObject *
-gjs_cairo_linear_gradient_from_pattern(JSContext       *context,
-                                       cairo_pattern_t *pattern)
-{
-    g_return_val_if_fail(context, nullptr);
-    g_return_val_if_fail(pattern, nullptr);
-    g_return_val_if_fail(
-        cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_LINEAR, nullptr);
-
-    JS::RootedObject proto(context,
-                           gjs_cairo_linear_gradient_get_proto(context));
-    JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_linear_gradient_class,
-                                   proto));
-    if (!object) {
-        gjs_throw(context, "failed to create linear gradient pattern");
-        return nullptr;
-    }
-
-    gjs_cairo_pattern_construct(object, pattern);
-
-    return object;
-}
-
+    JS_FS_END};
diff --git a/modules/cairo-pattern.cpp b/modules/cairo-pattern.cpp
index 96e594d0..d3f90fae 100644
--- a/modules/cairo-pattern.cpp
+++ b/modules/cairo-pattern.cpp
@@ -4,7 +4,6 @@
 
 #include <config.h>
 
-#include <cairo-gobject.h>
 #include <cairo.h>
 #include <glib.h>
 
@@ -21,25 +20,13 @@
 #include "gjs/macros.h"
 #include "modules/cairo-private.h"
 
-struct GjsCairoPattern
-    : GjsAutoPointer<cairo_pattern_t, cairo_pattern_t, cairo_pattern_destroy,
-                     cairo_pattern_reference> {
-    explicit GjsCairoPattern(cairo_pattern_t* pattern)
-        : GjsAutoPointer(pattern, GjsAutoTakeOwnership()) {}
-};
-
-GJS_DEFINE_PROTO_ABSTRACT_WITH_GTYPE("Pattern", cairo_pattern,
-                                     CAIRO_GOBJECT_TYPE_PATTERN,
-                                     JSCLASS_BACKGROUND_FINALIZE)
-
-static void gjs_cairo_pattern_finalize(JSFreeOp*, JSObject* obj) {
-    delete static_cast<GjsCairoPattern*>(JS_GetPrivate(obj));
-    JS_SetPrivate(obj, nullptr);
-}
-
 /* Properties */
-JSPropertySpec gjs_cairo_pattern_proto_props[] = {
-    JS_STRING_SYM_PS(toStringTag, "Pattern", JSPROP_READONLY), JS_PS_END};
+
+// clang-format off
+const JSPropertySpec CairoPattern::proto_props[] = {
+    JS_STRING_SYM_PS(toStringTag, "Pattern", JSPROP_READONLY),
+    JS_PS_END};
+// clang-format on
 
 /* Methods */
 
@@ -57,7 +44,7 @@ getType_func(JSContext *context,
         return false;
     }
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -70,52 +57,27 @@ getType_func(JSContext *context,
     return true;
 }
 
-JSFunctionSpec gjs_cairo_pattern_proto_funcs[] = {
+const JSFunctionSpec CairoPattern::proto_funcs[] = {
     // getMatrix
     JS_FN("getType", getType_func, 0, 0),
     // setMatrix
     JS_FS_END};
 
-JSFunctionSpec gjs_cairo_pattern_static_funcs[] = { JS_FS_END };
-
 /* Public API */
 
 /**
- * gjs_cairo_pattern_construct:
- * @object: object to construct
- * @pattern: cairo_pattern to attach to the object
- *
- * Constructs a pattern wrapper giving an empty JSObject and a
- * cairo pattern. A reference to @pattern will be taken.
- *
- * This is mainly used for subclasses where object is already created.
- */
-void gjs_cairo_pattern_construct(JSObject* object, cairo_pattern_t* pattern) {
-    g_return_if_fail(object);
-    g_return_if_fail(pattern);
-
-    g_assert(!JS_GetPrivate(object));
-    JS_SetPrivate(object, new GjsCairoPattern(pattern));
-}
-
-/**
- * gjs_cairo_pattern_finalize:
+ * CairoPattern::finalize_impl:
  * @fop: the free op
- * @object: object to finalize
+ * @pattern: pointer to free
  *
  * Destroys the resources associated with a pattern wrapper.
  *
  * This is mainly used for subclasses.
  */
-
-void
-gjs_cairo_pattern_finalize_pattern(JSFreeOp *fop,
-                                   JSObject *object)
-{
-    g_return_if_fail(fop);
-    g_return_if_fail(object);
-
-    gjs_cairo_pattern_finalize(fop, object);
+void CairoPattern::finalize_impl(JSFreeOp*, cairo_pattern_t* pattern) {
+    if (!pattern)
+        return;
+    cairo_pattern_destroy(pattern);
 }
 
 /**
@@ -136,13 +98,13 @@ gjs_cairo_pattern_from_pattern(JSContext       *context,
 
     switch (cairo_pattern_get_type(pattern)) {
         case CAIRO_PATTERN_TYPE_SOLID:
-            return gjs_cairo_solid_pattern_from_pattern(context, pattern);
+            return CairoSolidPattern::from_c_ptr(context, pattern);
         case CAIRO_PATTERN_TYPE_SURFACE:
-            return gjs_cairo_surface_pattern_from_pattern(context, pattern);
+            return CairoSurfacePattern::from_c_ptr(context, pattern);
         case CAIRO_PATTERN_TYPE_LINEAR:
-            return gjs_cairo_linear_gradient_from_pattern(context, pattern);
+            return CairoLinearGradient::from_c_ptr(context, pattern);
         case CAIRO_PATTERN_TYPE_RADIAL:
-            return gjs_cairo_radial_gradient_from_pattern(context, pattern);
+            return CairoRadialGradient::from_c_ptr(context, pattern);
         case CAIRO_PATTERN_TYPE_MESH:
         case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
         default:
@@ -154,18 +116,18 @@ gjs_cairo_pattern_from_pattern(JSContext       *context,
 }
 
 /**
- * gjs_cairo_pattern_get_pattern:
+ * CairoPattern::for_js:
  * @cx: the context
  * @pattern_wrapper: pattern wrapper
  *
  * Returns: the pattern attached to the wrapper.
  */
-cairo_pattern_t* gjs_cairo_pattern_get_pattern(
-    JSContext* cx, JS::HandleObject pattern_wrapper) {
+cairo_pattern_t* CairoPattern::for_js(JSContext* cx,
+                                      JS::HandleObject pattern_wrapper) {
     g_return_val_if_fail(cx, nullptr);
     g_return_val_if_fail(pattern_wrapper, nullptr);
 
-    JS::RootedObject proto(cx, gjs_cairo_pattern_get_proto(cx));
+    JS::RootedObject proto(cx, CairoPattern::prototype(cx));
 
     bool is_pattern_subclass = false;
     if (!gjs_object_in_prototype_chain(cx, proto, pattern_wrapper,
@@ -177,6 +139,5 @@ cairo_pattern_t* gjs_cairo_pattern_get_pattern(
         return nullptr;
     }
 
-    auto* priv = static_cast<GjsCairoPattern*>(JS_GetPrivate(pattern_wrapper));
-    return priv ? priv->get() : nullptr;
+    return static_cast<cairo_pattern_t*>(JS_GetPrivate(pattern_wrapper));
 }
diff --git a/modules/cairo-private.h b/modules/cairo-private.h
index 601632b1..dd8e97ce 100644
--- a/modules/cairo-private.h
+++ b/modules/cairo-private.h
@@ -13,11 +13,12 @@
 #include <cairo.h>
 #include <glib-object.h>
 
+#include <js/Class.h>
 #include <js/PropertySpec.h>
 #include <js/TypeDecls.h>
+#include <jspubtd.h>  // for JSProtoKey
 
 #include "gi/cwrapper.h"
-#include "gi/wrapperutils.h"
 #include "gjs/global.h"
 #include "gjs/macros.h"
 #include "util/log.h"
@@ -25,10 +26,6 @@
 namespace JS {
 class CallArgs;
 }
-namespace js {
-struct ClassSpec;
-}
-struct JSClass;
 
 GJS_JSAPI_RETURN_CONVENTION
 bool             gjs_cairo_check_status                 (JSContext       *context,
@@ -161,69 +158,236 @@ JSObject *       gjs_cairo_svg_surface_from_surface     (JSContext       *contex
                                                          cairo_surface_t *surface);
 
 /* pattern */
-[[nodiscard]] JSObject* gjs_cairo_pattern_get_proto(JSContext* cx);
 
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_pattern_define_proto(JSContext              *cx,
-                                    JS::HandleObject        module,
-                                    JS::MutableHandleObject proto);
+class CairoPattern : public CWrapper<CairoPattern, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoPattern, cairo_pattern_t>;
+    friend CWrapper<CairoPattern, cairo_pattern_t>;
+    friend class CairoGradient;  // "inherits" from CairoPattern
+    friend class CairoLinearGradient;
+    friend class CairoRadialGradient;
+    friend class CairoSurfacePattern;
+    friend class CairoSolidPattern;
+
+    CairoPattern() = delete;
+    CairoPattern(CairoPattern&) = delete;
+    CairoPattern(CairoPattern&&) = delete;
+
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_pattern;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
+
+    static const JSFunctionSpec proto_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        &CairoPattern::create_abstract_constructor,
+        nullptr,  // createPrototype
+        nullptr,  // constructorFunctions
+        nullptr,  // constructorProperties
+        CairoPattern::proto_funcs,
+        CairoPattern::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "Pattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoPattern::class_spec};
+
+    static GType gtype() { return CAIRO_GOBJECT_TYPE_PATTERN; }
+
+    static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
+        return cairo_pattern_reference(pattern);
+    }
+
+ protected:
+    static void finalize_impl(JSFreeOp* fop, cairo_pattern_t* pattern);
+
+ public:
+    static cairo_pattern_t* for_js(JSContext* cx,
+                                   JS::HandleObject pattern_wrapper);
+};
 
-void gjs_cairo_pattern_construct(JSObject* object, cairo_pattern_t* pattern);
-void             gjs_cairo_pattern_finalize_pattern     (JSFreeOp        *fop,
-                                                         JSObject        *object);
 GJS_JSAPI_RETURN_CONVENTION
 JSObject*        gjs_cairo_pattern_from_pattern         (JSContext       *context,
                                                          cairo_pattern_t *pattern);
-GJS_JSAPI_RETURN_CONVENTION
-cairo_pattern_t* gjs_cairo_pattern_get_pattern(
-    JSContext* cx, JS::HandleObject pattern_wrapper);
 
-/* gradient */
-[[nodiscard]] JSObject* gjs_cairo_gradient_get_proto(JSContext* cx);
+class CairoGradient : public CWrapper<CairoGradient, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoGradient, cairo_pattern_t>;
+    friend CWrapper<CairoGradient, cairo_pattern_t>;
+    friend class CairoLinearGradient;  // "inherits" from CairoGradient
+    friend class CairoRadialGradient;
 
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_gradient_define_proto(JSContext              *cx,
-                                     JS::HandleObject        module,
-                                     JS::MutableHandleObject proto);
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_gradient;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
 
-/* linear gradient */
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_linear_gradient_define_proto(JSContext              *cx,
-                                            JS::HandleObject        module,
-                                            JS::MutableHandleObject proto);
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_proto(JSContext* cx, JSProtoKey);
 
-GJS_JSAPI_RETURN_CONVENTION
-JSObject *       gjs_cairo_linear_gradient_from_pattern (JSContext       *context,
-                                                         cairo_pattern_t *pattern);
+    static const JSFunctionSpec proto_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        &CairoGradient::create_abstract_constructor,
+        &CairoGradient::new_proto,
+        nullptr,  // constructorFunctions
+        nullptr,  // constructorProperties
+        CairoGradient::proto_funcs,
+        CairoGradient::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "Gradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoGradient::class_spec};
 
-/* radial gradient */
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_radial_gradient_define_proto(JSContext              *cx,
-                                            JS::HandleObject        module,
-                                            JS::MutableHandleObject proto);
+    static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
+};
 
-GJS_JSAPI_RETURN_CONVENTION
-JSObject *       gjs_cairo_radial_gradient_from_pattern (JSContext       *context,
-                                                         cairo_pattern_t *pattern);
+class CairoLinearGradient
+    : public CWrapper<CairoLinearGradient, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoLinearGradient, cairo_pattern_t>;
+    friend CWrapper<CairoLinearGradient, cairo_pattern_t>;
 
-/* surface pattern */
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_surface_pattern_define_proto(JSContext              *cx,
-                                            JS::HandleObject        module,
-                                            JS::MutableHandleObject proto);
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_linear_gradient;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
+    static constexpr unsigned constructor_nargs = 4;
 
-GJS_JSAPI_RETURN_CONVENTION
-JSObject *       gjs_cairo_surface_pattern_from_pattern (JSContext       *context,
-                                                         cairo_pattern_t *pattern);
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_proto(JSContext* cx, JSProtoKey);
 
-/* solid pattern */
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_cairo_solid_pattern_define_proto(JSContext              *cx,
-                                          JS::HandleObject        module,
-                                          JS::MutableHandleObject proto);
+    static const JSFunctionSpec proto_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        nullptr,  // createConstructor
+        &CairoLinearGradient::new_proto,
+        nullptr,  // constructorFunctions
+        nullptr,  // constructorProperties
+        CairoLinearGradient::proto_funcs,
+        CairoLinearGradient::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "LinearGradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoLinearGradient::class_spec};
 
-GJS_JSAPI_RETURN_CONVENTION
-JSObject *       gjs_cairo_solid_pattern_from_pattern   (JSContext       *context,
-                                                         cairo_pattern_t *pattern);
+    static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
+        return cairo_pattern_reference(pattern);
+    }
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static cairo_pattern_t* constructor_impl(JSContext* cx,
+                                             const JS::CallArgs& args);
+
+    static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
+};
+
+class CairoRadialGradient
+    : public CWrapper<CairoRadialGradient, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoRadialGradient, cairo_pattern_t>;
+    friend CWrapper<CairoRadialGradient, cairo_pattern_t>;
+
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_radial_gradient;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
+    static constexpr unsigned constructor_nargs = 6;
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_proto(JSContext* cx, JSProtoKey);
+
+    static const JSFunctionSpec proto_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        nullptr,  // createConstructor
+        &CairoRadialGradient::new_proto,
+        nullptr,  // constructorFunctions
+        nullptr,  // constructorProperties
+        CairoRadialGradient::proto_funcs,
+        CairoRadialGradient::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "RadialGradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoRadialGradient::class_spec};
+
+    static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
+        return cairo_pattern_reference(pattern);
+    }
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static cairo_pattern_t* constructor_impl(JSContext* cx,
+                                             const JS::CallArgs& args);
+
+    static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
+};
+
+class CairoSurfacePattern
+    : public CWrapper<CairoSurfacePattern, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoSurfacePattern, cairo_pattern_t>;
+    friend CWrapper<CairoSurfacePattern, cairo_pattern_t>;
+
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_surface_pattern;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
+    static constexpr unsigned constructor_nargs = 1;
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_proto(JSContext* cx, JSProtoKey);
+
+    static const JSFunctionSpec proto_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        nullptr,  // createConstructor
+        &CairoSurfacePattern::new_proto,
+        nullptr,  // constructorFunctions
+        nullptr,  // constructorProperties
+        CairoSurfacePattern::proto_funcs,
+        CairoSurfacePattern::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "SurfacePattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoSurfacePattern::class_spec};
+
+    static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
+        return cairo_pattern_reference(pattern);
+    }
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static cairo_pattern_t* constructor_impl(JSContext* cx,
+                                             const JS::CallArgs& args);
+
+    static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
+};
+
+class CairoSolidPattern : public CWrapper<CairoSolidPattern, cairo_pattern_t> {
+    friend CWrapperPointerOps<CairoSolidPattern, cairo_pattern_t>;
+    friend CWrapper<CairoSolidPattern, cairo_pattern_t>;
+
+    static constexpr GjsGlobalSlot PROTOTYPE_SLOT =
+        GjsGlobalSlot::PROTOTYPE_cairo_solid_pattern;
+    static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_CAIRO;
+
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* new_proto(JSContext* cx, JSProtoKey);
+
+    static const JSFunctionSpec static_funcs[];
+    static const JSPropertySpec proto_props[];
+    static constexpr js::ClassSpec class_spec = {
+        &CairoSolidPattern::create_abstract_constructor,
+        &CairoSolidPattern::new_proto,
+        CairoSolidPattern::static_funcs,
+        nullptr,  // constructorProperties
+        nullptr,  // prototypeFunctions
+        CairoSolidPattern::proto_props,
+        &CairoPattern::define_gtype_prop,
+    };
+    static constexpr JSClass klass = {
+        "SolidPattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+        &CairoPattern::class_ops, &CairoSolidPattern::class_spec};
+
+    static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
+        return cairo_pattern_reference(pattern);
+    }
+
+    static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
+};
 
 #endif  // MODULES_CAIRO_PRIVATE_H_
diff --git a/modules/cairo-radial-gradient.cpp b/modules/cairo-radial-gradient.cpp
index 51620a62..3f558a3d 100644
--- a/modules/cairo-radial-gradient.cpp
+++ b/modules/cairo-radial-gradient.cpp
@@ -5,33 +5,30 @@
 #include <config.h>
 
 #include <cairo.h>
-#include <glib.h>
 
-#include <js/Class.h>
 #include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
 #include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
 #include <jsapi.h>  // for JS_NewObjectWithGivenProto
+#include <jspubtd.h>  // for JSProtoKey
 
-#include "gjs/jsapi-class.h"
 #include "gjs/jsapi-util-args.h"
-#include "gjs/jsapi-util.h"
 #include "modules/cairo-private.h"
 
-[[nodiscard]] static JSObject* gjs_cairo_radial_gradient_get_proto(JSContext*);
+namespace JS {
+class CallArgs;
+}
 
-GJS_DEFINE_PROTO_WITH_PARENT("RadialGradient", cairo_radial_gradient,
-                             cairo_gradient, JSCLASS_BACKGROUND_FINALIZE)
+JSObject* CairoRadialGradient::new_proto(JSContext* cx, JSProtoKey) {
+    JS::RootedObject parent_proto(cx, CairoGradient::prototype(cx));
+    return JS_NewObjectWithGivenProto(cx, nullptr, parent_proto);
+}
 
-GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_radial_gradient)
-{
-    GJS_NATIVE_CONSTRUCTOR_VARIABLES(cairo_radial_gradient)
+cairo_pattern_t* CairoRadialGradient::constructor_impl(
+    JSContext* context, const JS::CallArgs& argv) {
     double cx0, cy0, radius0, cx1, cy1, radius1;
-    cairo_pattern_t *pattern;
-
-    GJS_NATIVE_CONSTRUCTOR_PRELUDE(cairo_radial_gradient);
-
+    cairo_pattern_t* pattern;
     if (!gjs_parse_call_args(context, "RadialGradient", argv, "ffffff",
                              "cx0", &cx0,
                              "cy0", &cy0,
@@ -39,60 +36,20 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_radial_gradient)
                              "cx1", &cx1,
                              "cy1", &cy1,
                              "radius1", &radius1))
-        return false;
+        return nullptr;
 
     pattern = cairo_pattern_create_radial(cx0, cy0, radius0, cx1, cy1, radius1);
 
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
-        return false;
-
-    gjs_cairo_pattern_construct(object, pattern);
-    cairo_pattern_destroy(pattern);
-
-    GJS_NATIVE_CONSTRUCTOR_FINISH(cairo_radial_gradient);
-
-    return true;
-}
+        return nullptr;
 
-static void
-gjs_cairo_radial_gradient_finalize(JSFreeOp *fop,
-                                   JSObject *obj)
-{
-    gjs_cairo_pattern_finalize_pattern(fop, obj);
+    return pattern;
 }
 
-JSPropertySpec gjs_cairo_radial_gradient_proto_props[] = {
+const JSPropertySpec CairoRadialGradient::proto_props[] = {
     JS_STRING_SYM_PS(toStringTag, "RadialGradient", JSPROP_READONLY),
     JS_PS_END};
 
-JSFunctionSpec gjs_cairo_radial_gradient_proto_funcs[] = {
+const JSFunctionSpec CairoRadialGradient::proto_funcs[] = {
     // getRadialCircles
-    JS_FS_END
-};
-
-JSFunctionSpec gjs_cairo_radial_gradient_static_funcs[] = { JS_FS_END };
-
-JSObject *
-gjs_cairo_radial_gradient_from_pattern(JSContext       *context,
-                                       cairo_pattern_t *pattern)
-{
-    g_return_val_if_fail(context, nullptr);
-    g_return_val_if_fail(pattern, nullptr);
-    g_return_val_if_fail(
-        cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_RADIAL, nullptr);
-
-    JS::RootedObject proto(context,
-                           gjs_cairo_radial_gradient_get_proto(context));
-    JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_radial_gradient_class,
-                                   proto));
-    if (!object) {
-        gjs_throw(context, "failed to create radial gradient pattern");
-        return nullptr;
-    }
-
-    gjs_cairo_pattern_construct(object, pattern);
-
-    return object;
-}
-
+    JS_FS_END};
diff --git a/modules/cairo-solid-pattern.cpp b/modules/cairo-solid-pattern.cpp
index 9caec715..cc09ab3c 100644
--- a/modules/cairo-solid-pattern.cpp
+++ b/modules/cairo-solid-pattern.cpp
@@ -5,37 +5,26 @@
 #include <config.h>
 
 #include <cairo.h>
-#include <glib.h>
 
 #include <js/CallArgs.h>
-#include <js/Class.h>
 #include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
 #include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
 #include <jsapi.h>  // for JS_NewObjectWithGivenProto
+#include <jspubtd.h>  // for JSProtoKey
 
-#include "gjs/jsapi-class.h"
 #include "gjs/jsapi-util-args.h"
-#include "gjs/jsapi-util.h"
 #include "gjs/macros.h"
 #include "modules/cairo-private.h"
 
-[[nodiscard]] 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,
-                                 JSObject *obj)
-{
-    gjs_cairo_pattern_finalize_pattern(fop, obj);
+JSObject* CairoSolidPattern::new_proto(JSContext* cx, JSProtoKey) {
+    JS::RootedObject parent_proto(cx, CairoPattern::prototype(cx));
+    return JS_NewObjectWithGivenProto(cx, nullptr, parent_proto);
 }
 
 // clang-format off
-JSPropertySpec gjs_cairo_solid_pattern_proto_props[] = {
+const JSPropertySpec CairoSolidPattern::proto_props[] = {
     JS_STRING_SYM_PS(toStringTag, "SolidPattern", JSPROP_READONLY),
     JS_PS_END};
 // clang-format on
@@ -49,7 +38,6 @@ createRGB_func(JSContext *context,
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
     double red, green, blue;
     cairo_pattern_t *pattern;
-    JSObject *pattern_wrapper;
 
     if (!gjs_parse_call_args(context, "createRGB", argv, "fff",
                              "red", &red,
@@ -61,7 +49,9 @@ createRGB_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    pattern_wrapper = gjs_cairo_solid_pattern_from_pattern(context, pattern);
+    JSObject* pattern_wrapper = CairoSolidPattern::from_c_ptr(context, pattern);
+    if (!pattern_wrapper)
+        return false;
     cairo_pattern_destroy(pattern);
 
     argv.rval().setObjectOrNull(pattern_wrapper);
@@ -78,7 +68,6 @@ createRGBA_func(JSContext *context,
     JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
     double red, green, blue, alpha;
     cairo_pattern_t *pattern;
-    JSObject *pattern_wrapper;
 
     if (!gjs_parse_call_args(context, "createRGBA", argv, "ffff",
                              "red", &red,
@@ -91,7 +80,9 @@ createRGBA_func(JSContext *context,
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
         return false;
 
-    pattern_wrapper = gjs_cairo_solid_pattern_from_pattern(context, pattern);
+    JSObject* pattern_wrapper = CairoSolidPattern::from_c_ptr(context, pattern);
+    if (!pattern_wrapper)
+        return false;
     cairo_pattern_destroy(pattern);
 
     argv.rval().setObjectOrNull(pattern_wrapper);
@@ -99,33 +90,9 @@ createRGBA_func(JSContext *context,
     return true;
 }
 
-JSFunctionSpec gjs_cairo_solid_pattern_proto_funcs[] = {
+// clang-format off
+const JSFunctionSpec CairoSolidPattern::static_funcs[] = {
     JS_FN("createRGB", createRGB_func, 0, 0),
     JS_FN("createRGBA", createRGBA_func, 0, 0),
     JS_FS_END};
-
-JSFunctionSpec gjs_cairo_solid_pattern_static_funcs[] = { JS_FS_END };
-
-JSObject *
-gjs_cairo_solid_pattern_from_pattern(JSContext       *context,
-                                     cairo_pattern_t *pattern)
-{
-    g_return_val_if_fail(context, nullptr);
-    g_return_val_if_fail(pattern, nullptr);
-    g_return_val_if_fail(
-        cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SOLID, nullptr);
-
-    JS::RootedObject proto(context, gjs_cairo_solid_pattern_get_proto(context));
-    JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_solid_pattern_class,
-                                   proto));
-    if (!object) {
-        gjs_throw(context, "failed to create solid pattern");
-        return nullptr;
-    }
-
-    gjs_cairo_pattern_construct(object, pattern);
-
-    return object;
-}
-
+// clang-format on
diff --git a/modules/cairo-surface-pattern.cpp b/modules/cairo-surface-pattern.cpp
index b5a3c85a..2639e422 100644
--- a/modules/cairo-surface-pattern.cpp
+++ b/modules/cairo-surface-pattern.cpp
@@ -5,66 +5,47 @@
 #include <config.h>
 
 #include <cairo.h>
-#include <glib.h>
 
 #include <js/CallArgs.h>
-#include <js/Class.h>
 #include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
 #include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/TypeDecls.h>
 #include <jsapi.h>  // for JS_NewObjectWithGivenProto
+#include <jspubtd.h>  // for JSProtoKey
 
-#include "gjs/jsapi-class.h"
 #include "gjs/jsapi-util-args.h"
 #include "gjs/jsapi-util.h"
 #include "gjs/macros.h"
 #include "modules/cairo-private.h"
 
-[[nodiscard]] static JSObject* gjs_cairo_surface_pattern_get_proto(JSContext*);
-
-GJS_DEFINE_PROTO_WITH_PARENT("SurfacePattern", cairo_surface_pattern,
-                             cairo_pattern, JSCLASS_BACKGROUND_FINALIZE)
+JSObject* CairoSurfacePattern::new_proto(JSContext* cx, JSProtoKey) {
+    JS::RootedObject parent_proto(cx, CairoPattern::prototype(cx));
+    return JS_NewObjectWithGivenProto(cx, nullptr, parent_proto);
+}
 
-GJS_NATIVE_CONSTRUCTOR_DECLARE(cairo_surface_pattern)
-{
-    GJS_NATIVE_CONSTRUCTOR_VARIABLES(cairo_surface_pattern)
+cairo_pattern_t* CairoSurfacePattern::constructor_impl(
+    JSContext* context, const JS::CallArgs& argv) {
     cairo_pattern_t *pattern;
-
-    GJS_NATIVE_CONSTRUCTOR_PRELUDE(cairo_surface_pattern);
-
     JS::RootedObject surface_wrapper(context);
     if (!gjs_parse_call_args(context, "SurfacePattern", argv, "o",
                              "surface", &surface_wrapper))
-        return false;
+        return nullptr;
 
     cairo_surface_t* surface =
         gjs_cairo_surface_get_surface(context, surface_wrapper);
     if (!surface)
-        return false;
+        return nullptr;
 
     pattern = cairo_pattern_create_for_surface(surface);
 
     if (!gjs_cairo_check_status(context, cairo_pattern_status(pattern), "pattern"))
-        return false;
-
-    gjs_cairo_pattern_construct(object, pattern);
-    cairo_pattern_destroy(pattern);
-
-    GJS_NATIVE_CONSTRUCTOR_FINISH(cairo_surface_pattern);
-
-    return true;
-}
-
+        return nullptr;
 
-static void
-gjs_cairo_surface_pattern_finalize(JSFreeOp *fop,
-                                   JSObject *obj)
-{
-    gjs_cairo_pattern_finalize_pattern(fop, obj);
+    return pattern;
 }
 
-JSPropertySpec gjs_cairo_surface_pattern_proto_props[] = {
+const JSPropertySpec CairoSurfacePattern::proto_props[] = {
     JS_STRING_SYM_PS(toStringTag, "SurfacePattern", JSPROP_READONLY),
     JS_PS_END};
 
@@ -81,7 +62,7 @@ setExtend_func(JSContext *context,
                              "extend", &extend))
         return false;
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -108,7 +89,7 @@ getExtend_func(JSContext *context,
         return false;
     }
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -135,7 +116,7 @@ setFilter_func(JSContext *context,
                              "filter", &filter))
         return false;
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -162,7 +143,7 @@ getFilter_func(JSContext *context,
         return false;
     }
 
-    cairo_pattern_t* pattern = gjs_cairo_pattern_get_pattern(context, obj);
+    cairo_pattern_t* pattern = CairoPattern::for_js(context, obj);
     if (!pattern)
         return false;
 
@@ -176,36 +157,11 @@ getFilter_func(JSContext *context,
     return true;
 }
 
-JSFunctionSpec gjs_cairo_surface_pattern_proto_funcs[] = {
+// clang-format off
+const JSFunctionSpec CairoSurfacePattern::proto_funcs[] = {
     JS_FN("setExtend", setExtend_func, 0, 0),
     JS_FN("getExtend", getExtend_func, 0, 0),
     JS_FN("setFilter", setFilter_func, 0, 0),
     JS_FN("getFilter", getFilter_func, 0, 0),
     JS_FS_END};
-
-JSFunctionSpec gjs_cairo_surface_pattern_static_funcs[] = { JS_FS_END };
-
-JSObject *
-gjs_cairo_surface_pattern_from_pattern(JSContext       *context,
-                                       cairo_pattern_t *pattern)
-{
-    g_return_val_if_fail(context, nullptr);
-    g_return_val_if_fail(pattern, nullptr);
-    g_return_val_if_fail(
-        cairo_pattern_get_type(pattern) == CAIRO_PATTERN_TYPE_SURFACE, nullptr);
-
-    JS::RootedObject proto(context,
-                           gjs_cairo_surface_pattern_get_proto(context));
-    JS::RootedObject object(context,
-        JS_NewObjectWithGivenProto(context, &gjs_cairo_surface_pattern_class,
-                                   proto));
-    if (!object) {
-        gjs_throw(context, "failed to create surface pattern");
-        return nullptr;
-    }
-
-    gjs_cairo_pattern_construct(object, pattern);
-
-    return object;
-}
-
+// clang-format on
diff --git a/modules/cairo.cpp b/modules/cairo.cpp
index c2d3e764..ad994435 100644
--- a/modules/cairo.cpp
+++ b/modules/cairo.cpp
@@ -81,10 +81,10 @@ gjs_js_define_cairo_stuff(JSContext              *context,
 #if CAIRO_HAS_SVG_SURFACE
         gjs_cairo_svg_surface_define_proto(context, module, &proto) &&
 #endif
-        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);
+        CairoPattern::create_prototype(context, module) &&
+        CairoGradient::create_prototype(context, module) &&
+        CairoLinearGradient::create_prototype(context, module) &&
+        CairoRadialGradient::create_prototype(context, module) &&
+        CairoSurfacePattern::create_prototype(context, module) &&
+        CairoSolidPattern::create_prototype(context, module);
 }


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