-/* $Id: js_gd.c,v 1.4 2006/10/25 19:32:24 mmondor Exp $ */
+/* $Id: js_gd.c,v 1.5 2006/10/26 00:35:00 mmondor Exp $ */
/*
* Copyright (c) 2006, Matthew Mondor
#include <jsapi.h>
#include <gd.h>
+#include <gdfonts.h>
+#include <gdfontl.h>
+#include <gdfontmb.h>
+#include <gdfontg.h>
+#include <gdfontt.h>
#include <js_gd.h>
#include <js_file.h>
jsval *);
static JSBool gd_sm_true_color_alpha(JSContext *, JSObject *, uintN, jsval *,
jsval *);
+static JSBool gd_sm_ft_use_fontconfig(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
/* GDImage */
static JSObject *js_InitGDImageClass(JSContext *, JSObject *);
static JSBool gdimage_m_color_transparent(JSContext *, JSObject *, uintN,
jsval *, jsval *);
+static JSBool gdimage_m_char_i(JSContext *, JSObject *, uintN, jsval *,
+ jsval *,
+ void (*)(gdImagePtr, gdFontPtr, int, int, int, int));
+static JSBool gdimage_m_string_i(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void (*)(gdImagePtr, gdFontPtr, int, int,
+ unsigned char *, int));
+static JSBool gdimage_m_char(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_char_up(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_string(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_string_up(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_string_ft(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_string_ft_ex(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_string_ft_circle(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+
static JSBool gdimage_m_copy(JSContext *, JSObject *, uintN, jsval *,
jsval *);
static JSBool gdimage_m_copy_resized(JSContext *, JSObject *, uintN, jsval *,
static JSBool gdimage_m_interlace(JSContext *, JSObject *, uintN, jsval *,
jsval *);
+/* GDFont */
+static JSObject *js_InitGDFontClass(JSContext *, JSObject *, JSObject *);
+static JSBool gdfont_constructor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static void gdfont_finalize(JSContext *, JSObject *);
+static JSObject *gdfont_new(JSContext *, gdFontPtr);
+static gdFontPtr gdfont_get(JSContext *, jsval);
+
/*
#endif
{ "trueColor", gd_sm_true_color, 3, 0, 0 },
{ "trueColorAlpha", gd_sm_true_color_alpha, 4, 0, 0 },
+ { "ftUseFontConfig", gd_sm_ft_use_fontconfig, 1, 0, 0 },
{ NULL, NULL, 0, 0, 0 }
};
SP(GD_CMP_BACKGROUND),
SP(GD_CMP_INTERLACE),
SP(GD_CMP_TRUECOLOR),
+ SP(gdFTEX_Unicode),
+ SP(gdFTEX_Shift_JIS),
+ SP(gdFTEX_Big5),
{ NULL, 0 }
};
{ "colorDeallocate", gdimage_m_color_deallocate, 1, 0, 0 },
{ "colorTransparent", gdimage_m_color_transparent, 1, 0, 0 },
+ /*
+ * We don't implement charRight16, charUp16, stringRight16 and
+ * stringUp16 because GD fonts actually don't support 16-bit chars.
+ * stringFt[Ex] may be used instead which allow UTF-8 and use of
+ * external fonts. Moreover, we don't support stringFtt which was for
+ * use with FontType v1, and is now deprecated (calling the v2
+ * function internally for compatibility).
+ */
+ { "charRight", gdimage_m_char, 5, 0, 0 }, /* char == reserved! */
+ { "charUp", gdimage_m_char_up, 5, 0, 0 },
+ { "stringRight", gdimage_m_string, 5, 0, 0 }, /* string reserved! */
+ { "stringUp", gdimage_m_string_up, 5, 0, 0 },
+ { "stringFt", gdimage_m_string_ft, 7, 0, 0 },
+ { "stringFtEx", gdimage_m_string_ft_ex, 8, 0, 0 },
+ { "stringFtCircle", gdimage_m_string_ft_circle, 10, 0, 0 },
+
{ "copy", gdimage_m_copy, 7, 0, 0 },
{ "copyResized", gdimage_m_copy_resized, 9, 0, 0 },
{ "copyResamped", gdimage_m_copy_resampled, 9, 0, 0 },
{ "squareToCircle", gdimage_m_square_to_circle, 1, 0, 0 },
{ "compare", gdimage_m_compare, 1, 0, 0 },
- { "interlace", gdimage_m_compare, 1, 0, 0 },
+ { "interlace", gdimage_m_interlace, 1, 0, 0 },
{ NULL, NULL, 0, 0, 0 }
};
/*
+ * GDFont
+ */
+
+/* Class */
+static JSClass gdfont_class = {
+ "GDFont", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, gdfont_finalize
+};
+
+
+
+/*
* GD object control
*/
(void) fprintf(stderr, "GD: InitGDImageClass()\n");
goto err;
}
+ /*
+ * Same for GDFont, which will use our supplied GD object pointer to
+ * set properties for existing fonts.
+ */
+ if (js_InitGDFontClass(cx, obj, ctor) == NULL) {
+ (void) fprintf(stderr, "GD: InitGDFontClass()\n");
+ goto err;
+ }
+
+ if (gdFontCacheSetup() != 0) {
+ (void) fprintf(stderr, "gdFontCacheSetup()\n");
+ goto err;
+ }
return proto;
return JS_FALSE;
}
+static JSBool
+gd_sm_ft_use_fontconfig(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ int v;
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_BOOLEAN(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a Boolean");
+ goto err;
+ }
+
+ v = gdFTUseFontConfig((int)JSVAL_TO_BOOLEAN(argv[0]));
+ *rval = BOOLEAN_TO_JSVAL((JSBool)v);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
/*
* GDImage object control
static JSBool
+gdimage_m_char_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void (*funcptr)(gdImagePtr, gdFontPtr, int, int, int, int))
+{
+ gdImagePtr img;
+ gdFontPtr f;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 5) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((f = gdfont_get(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a GDFont object");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ funcptr(img, f, JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]),
+ JSVAL_TO_INT(argv[3]), JSVAL_TO_INT(argv[4]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_string_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval,
+ void (*funcptr)(gdImagePtr, gdFontPtr, int, int, unsigned char *, int))
+{
+ gdImagePtr img;
+ gdFontPtr f;
+ char *bytes;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 5) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((f = gdfont_get(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a GDFont object");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[3]) ||
+ (bytes = JS_GetStringBytes(JSVAL_TO_STRING(argv[3]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 4 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ funcptr(img, f, JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]), bytes,
+ JSVAL_TO_INT(argv[4]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_char(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_char_i(cx, obj, argc, argv, rval, gdImageChar);
+}
+
+static JSBool
+gdimage_m_char_up(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_char_i(cx, obj, argc, argv, rval, gdImageCharUp);
+}
+
+static JSBool
+gdimage_m_string(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_string_i(cx, obj, argc, argv, rval, gdImageString);
+}
+
+static JSBool
+gdimage_m_string_up(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_string_i(cx, obj, argc, argv, rval, gdImageStringUp);
+}
+
+static JSBool
+gdimage_m_string_ft(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ char *font, *string, *error;
+ jsdouble ptsize, angle;
+ int brect[8], i;
+ jsval rect[8];
+ JSObject *a;
+
+ if (argc != 7) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[1]) ||
+ (font = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 2 not a String");
+ goto err;
+ }
+ if (!JSVAL_IS_NUMBER(argv[2]) ||
+ !JS_ValueToNumber(cx, argv[2], &ptsize)) {
+ QUEUE_EXCEPTION("Argument 3 not a Number");
+ goto err;
+ }
+ if (!JSVAL_IS_NUMBER(argv[3]) ||
+ !JS_ValueToNumber(cx, argv[3], &angle)) {
+ QUEUE_EXCEPTION("Argument 4 not a Number");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[5])) {
+ QUEUE_EXCEPTION("Argument 6 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[6]) ||
+ (string = JS_GetStringBytes(JSVAL_TO_STRING(argv[6]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 7 not a String");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((error = gdImageStringFT(img, brect, JSVAL_TO_INT(argv[0]), font,
+ (double)ptsize, (double)angle, JSVAL_TO_INT(argv[4]),
+ JSVAL_TO_INT(argv[5]), string)) != NULL) {
+ QUEUE_EXCEPTION(error);
+ goto err;
+ }
+
+ for (i = 0; i < 8; i++)
+ rect[i] = INT_TO_JSVAL(brect[i]);
+ if ((a = JS_NewArrayObject(cx, 8, rect)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(a);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_string_ft_ex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ char *font, *string, *error;
+ jsdouble ptsize, angle;
+ int brect[8], i;
+ jsval rect[8];
+ JSObject *o, *a;
+ JSString *str;
+ gdFTStringExtra ex;
+
+ ex.flags = gdFTEX_XSHOW | gdFTEX_RETURNFONTPATHNAME |
+ gdFTEX_RESOLUTION;
+ ex.hdpi = ex.vdpi = 96;
+ ex.xshow = ex.fontpath = NULL;
+
+ if (argc != 8) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[1]) ||
+ (font = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 2 not a String");
+ goto err;
+ }
+ if (!JSVAL_IS_NUMBER(argv[2]) ||
+ !JS_ValueToNumber(cx, argv[2], &ptsize)) {
+ QUEUE_EXCEPTION("Argument 3 not a Number");
+ goto err;
+ }
+ if (!JSVAL_IS_NUMBER(argv[3]) ||
+ !JS_ValueToNumber(cx, argv[3], &angle)) {
+ QUEUE_EXCEPTION("Argument 4 not a Number");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[5])) {
+ QUEUE_EXCEPTION("Argument 6 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[6]) ||
+ (string = JS_GetStringBytes(JSVAL_TO_STRING(argv[6]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 7 not a String");
+ goto err;
+ }
+ if (!JSVAL_IS_NULL(argv[7]) && !JSVAL_IS_OBJECT(argv[7])) {
+ QUEUE_EXCEPTION("Argument 8 not Null or Object");
+ goto err;
+ }
+
+ if (!JSVAL_IS_NULL(argv[7])) {
+ JSObject *o;
+ jsval v;
+
+ o = JSVAL_TO_OBJECT(argv[7]);
+
+ if (JS_GetProperty(cx, o, "linespacing", &v) &&
+ !JSVAL_IS_VOID(v)) {
+ jsdouble d;
+
+ if (!JSVAL_IS_NUMBER(v) ||
+ !JS_ValueToNumber(cx, v, &d)) {
+ QUEUE_EXCEPTION("linespacing not a Number");
+ goto err;
+ }
+ ex.linespacing = (double)d;
+ ex.flags |= gdFTEX_LINESPACE;
+ }
+ if (JS_GetProperty(cx, o, "charmap", &v) &&
+ !JSVAL_IS_VOID(v)) {
+ if (!JSVAL_IS_INT(v)) {
+ QUEUE_EXCEPTION("charmap not an Integer");
+ goto err;
+ }
+ ex.charmap = JSVAL_TO_INT(v);
+ ex.flags |= gdFTEX_CHARMAP;
+ }
+ if (JS_GetProperty(cx, o, "hdpi", &v) && !JSVAL_IS_VOID(v)) {
+ if (!JSVAL_IS_INT(v)) {
+ QUEUE_EXCEPTION("hdpi not an Integer");
+ goto err;
+ }
+ ex.hdpi = JSVAL_TO_INT(v);
+ }
+ if (JS_GetProperty(cx, o, "vdpi", &v) && !JSVAL_IS_VOID(v)) {
+ if (!JSVAL_IS_INT(v)) {
+ QUEUE_EXCEPTION("vdpi not an Integer");
+ goto err;
+ }
+ ex.vdpi = JSVAL_TO_INT(v);
+ }
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((error = gdImageStringFTEx(img, brect, JSVAL_TO_INT(argv[0]), font,
+ (double)ptsize, (double)angle, JSVAL_TO_INT(argv[4]),
+ JSVAL_TO_INT(argv[5]), string, &ex)) != NULL) {
+ QUEUE_EXCEPTION(error);
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL)
+ goto err2;
+ *rval = OBJECT_TO_JSVAL(o);
+
+ if (ex.xshow != NULL) {
+ if ((str = JS_NewStringCopyZ(cx, ex.xshow)) == NULL)
+ goto err2;
+ if (!JS_DefineProperty(cx, o, "xshow", STRING_TO_JSVAL(str),
+ NULL, NULL, JSPROP_ENUMERATE))
+ goto err2;
+ gdFree(ex.xshow);
+ ex.xshow = NULL;
+ }
+ if (ex.fontpath != NULL) {
+ if ((str = JS_NewStringCopyZ(cx, ex.fontpath)) == NULL)
+ goto err2;
+ if (!JS_DefineProperty(cx, o, "fontpath", STRING_TO_JSVAL(str),
+ NULL, NULL, JSPROP_ENUMERATE))
+ goto err2;
+ gdFree(ex.fontpath);
+ ex.fontpath = NULL;
+ }
+
+ for (i = 0; i < 8; i++)
+ rect[i] = INT_TO_JSVAL(brect[i]);
+ if ((a = JS_NewArrayObject(cx, 8, rect)) == NULL)
+ goto err2;
+ if (!JS_DefineProperty(cx, o, "brect", OBJECT_TO_JSVAL(a), NULL, NULL,
+ JSPROP_ENUMERATE))
+ goto err2;
+
+ return JS_TRUE;
+
+err2:
+ QUEUE_EXCEPTION("Internal error!");
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (ex.xshow != NULL)
+ gdFree(ex.xshow);
+ if (ex.fontpath != NULL)
+ gdFree(ex.fontpath);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_string_ft_circle(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+ char *font, *topstr, *botstr, *error;
+ jsdouble radius, textradius, fillportion, ptsize;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 10) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[2]) ||
+ !JS_ValueToNumber(cx, argv[2], &radius)) {
+ QUEUE_EXCEPTION("Argument 3 not a Number");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[3]) ||
+ !JS_ValueToNumber(cx, argv[3], &textradius)) {
+ QUEUE_EXCEPTION("Argument 4 not a Number");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[4]) ||
+ !JS_ValueToNumber(cx, argv[4], &fillportion)) {
+ QUEUE_EXCEPTION("Argument 5 not a Number");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[5]) ||
+ (font = JS_GetStringBytes(JSVAL_TO_STRING(argv[5]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 6 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_NUMBER(argv[6]) ||
+ !JS_ValueToNumber(cx, argv[6], &ptsize)) {
+ QUEUE_EXCEPTION("Argument 7 not a Number");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[7]) ||
+ (topstr = JS_GetStringBytes(JSVAL_TO_STRING(argv[7]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 8 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_STRING(argv[8]) ||
+ (botstr = JS_GetStringBytes(JSVAL_TO_STRING(argv[8]))) == NULL) {
+ QUEUE_EXCEPTION("Argument 9 not a String");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[9])) {
+ QUEUE_EXCEPTION("Argument 10 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((error = gdImageStringFTCircle(img, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]), (double)radius, (double)textradius,
+ (double)fillportion, font, (double)ptsize, topstr, botstr,
+ JSVAL_TO_INT(argv[9]))) != NULL) {
+ QUEUE_EXCEPTION(error);
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+
+static JSBool
gdimage_m_copy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
return JS_TRUE;
}
+
+
+/*
+ * GDFont object control
+ */
+
+JSObject *
+js_InitGDFontClass(JSContext *cx, JSObject *obj, JSObject *obj2)
+{
+ JSObject *proto, *o;
+
+ if ((proto = JS_InitClass(cx, obj, NULL, &gdfont_class,
+ gdfont_constructor, 0, NULL, NULL, NULL, NULL)) == NULL)
+ return NULL;
+
+ /* Attach font objects statically to the global GD object */
+ if ((o = gdfont_new(cx, gdFontGetSmall())) != NULL)
+ JS_DefineProperty(cx, obj2, "gdFontSmall", OBJECT_TO_JSVAL(o),
+ NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT |
+ JSPROP_ENUMERATE);
+ if ((o = gdfont_new(cx, gdFontGetLarge())) != NULL)
+ JS_DefineProperty(cx, obj2, "gdFontLarge", OBJECT_TO_JSVAL(o),
+ NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT |
+ JSPROP_ENUMERATE);
+ if ((o = gdfont_new(cx, gdFontGetMediumBold())) != NULL)
+ JS_DefineProperty(cx, obj2, "gdFontMediumBold",
+ OBJECT_TO_JSVAL(o), NULL, NULL,
+ JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE);
+ if ((o = gdfont_new(cx, gdFontGetGiant())) != NULL)
+ JS_DefineProperty(cx, obj2, "gdFontGiant", OBJECT_TO_JSVAL(o),
+ NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT |
+ JSPROP_ENUMERATE);
+ if ((o = gdfont_new(cx, gdFontGetTiny())) != NULL)
+ JS_DefineProperty(cx, obj2, "gdFontTiny", OBJECT_TO_JSVAL(o),
+ NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT |
+ JSPROP_ENUMERATE);
+
+ return proto;
+}
+
+static JSBool
+gdfont_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+ QUEUE_EXCEPTION("GDFont object not user-instanciable");
+
+ return JS_FALSE;
+}
+
+static void
+gdfont_finalize(JSContext *cx, JSObject *obj)
+{
+
+ if (JS_GetInstancePrivate(cx, obj, &gdfont_class, NULL) != NULL)
+ (void) JS_SetPrivate(cx, obj, NULL);
+}
+
+static JSObject *
+gdfont_new(JSContext *cx, gdFontPtr f)
+{
+ JSObject *o;
+
+ if (f == NULL)
+ return NULL;
+
+ if ((o = JS_NewObject(cx, &gdfont_class, NULL, NULL)) == NULL)
+ return NULL;
+
+ if (!JS_SetPrivate(cx, o, f))
+ return NULL;
+
+ return o;
+}
+
+static gdFontPtr
+gdfont_get(JSContext *cx, jsval v)
+{
+ JSObject *o;
+ gdFontPtr f;
+
+ if (!JSVAL_IS_OBJECT(v))
+ return NULL;
+ o = JSVAL_TO_OBJECT(v);
+
+ if (!JS_InstanceOf(cx, o, &gdfont_class, NULL))
+ return NULL;
+
+ f = JS_GetInstancePrivate(cx, o, &gdfont_class, NULL);
+ assert(f != NULL);
+
+ return f;
+}