--- /dev/null
+/* $Id: js_gd.c,v 1.1 2006/10/24 12:42:43 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+/*
+ * Refer to http://www.boutell.com/gd/manual2.0.33.html for more information.
+ *
+ * XXX TODO XXX
+ * - Implement GDIOCtx and related functions
+ * - gdImageSetBrush() and gdImageSetTile() functions documentation specify
+ * that one should not use the special gdBrushed or gdTiled if no image was
+ * set for them or if their image were destroyed. It would be lame to have
+ * to do this checking in this code, but we might have to. Will have to try
+ * or to check the code to see if a crash can occur.
+ */
+
+
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jsapi.h>
+
+#include <gd.h>
+
+#include <js_gd.h>
+#include <js_file.h>
+
+
+
+#define QUEUE_EXCEPTION(s) do { \
+ JS_SetPendingException(cx, \
+ STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \
+} while (/* CONSTCOND */0)
+
+struct property_spec {
+ const char *name;
+ int value;
+};
+
+#define SP(n) \
+ { #n, n }
+
+
+
+/*
+ * Static prototypes
+ */
+
+/* GD */
+static JSBool gd_constructor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static void gd_finalize(JSContext *, JSObject *);
+
+static JSBool gd_sm_create(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool gd_sm_create_truecolor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+
+static JSBool gd_sm_create_from_file_i(JSContext *, JSObject *, uintN,
+ jsval *, jsval *, gdImagePtr (*)(FILE *), const char *);
+static JSBool gd_sm_create_from_str_i(JSContext *, JSObject *, uintN,
+ jsval *, jsval *, gdImagePtr (*)(int, void *),
+ const char *);
+
+static JSBool gd_sm_create_from_jpeg(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_jpeg_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_png(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_png_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_gif(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_gif_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_gd(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_gd_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_gd2(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_gd2_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_gd2_part(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_gd2_part_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_wbmp(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_create_from_wbmp_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gd_sm_create_from_xbm(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+#ifdef HAVE_XPM
+static JSBool gd_sm_create_from_xpm(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+#endif
+static JSBool gd_sm_true_color(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gd_sm_true_color_alpha(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+
+/* GDImage */
+static JSObject *js_InitGDImageClass(JSContext *, JSObject *);
+static JSBool gdimage_constructor(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static void gdimage_finalize(JSContext *, JSObject *);
+
+static JSBool gdimage_get_property(JSContext *, JSObject *, jsval id,
+ jsval *);
+static JSBool gdimage_set_property(JSContext *, JSObject *, jsval id,
+ jsval *);
+
+static JSBool gdimage_m_image_destroy(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_save_file_i0(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void (*)(gdImagePtr, FILE *));
+static JSBool gdimage_m_save_file_i1(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void (*)(gdImagePtr, FILE *, int));
+static JSBool gdimage_m_save_str_i0(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void *(*)(gdImagePtr, int *), const char *);
+static JSBool gdimage_m_save_str_i1(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void *(*)(gdImagePtr, int *, int), const char *);
+static JSBool gdimage_m_jpeg(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_jpeg_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gif(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gif_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gif_anim_begin(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_gif_anim_begin_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_gif_anim_add(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gif_anim_add_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_gif_anim_end(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gif_anim_end_str(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_png(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_png_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_png_ex(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_png_ex_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_wbmp(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_wbmp_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gd(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool gdimage_m_gd_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gd2(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_gd2_str(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_truecolor_to_palette(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_create_palette_from_truecolor(JSContext *,
+ JSObject *, uintN, jsval *, jsval *);
+static JSBool gdimage_m_set_pixel(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_primitive5_i(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void (*)(gdImagePtr, int, int, int, int, int));
+static JSBool gdimage_m_line(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_dashed_line(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static gdPointPtr array_to_gdpoints_i(JSContext *, jsval, int *);
+static int *array_to_ints_i(JSContext *, jsval, int *);
+static JSBool gdimage_m_polygon_i(JSContext *, JSObject *, uintN, jsval *,
+ jsval *, void (*)(gdImagePtr, gdPointPtr, int, int));
+static JSBool gdimage_m_polygon(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_open_polygon(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_rectangle(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_filled_polygon(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_filled_rectangle(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_arc(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_filled_arc(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_filled_ellipse(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_fill_to_border(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_fill(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_set_antialiased(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_set_antialiaseddontblend(JSContext *, JSObject *,
+ uintN, jsval *, jsval *);
+static JSBool gdimage_m_set_brush(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_set_tile(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_set_style(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_set_thickness(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_alpha_blending(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+static JSBool gdimage_m_save_alpha(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_set_clip(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+static JSBool gdimage_m_get_clip(JSContext *, JSObject *, uintN, jsval *,
+ jsval *);
+
+static JSBool gdimage_m_color_allocate(JSContext *, JSObject *, uintN,
+ jsval *, jsval *);
+
+
+
+/*
+ * Static globals
+ */
+
+/*
+ * GD
+ */
+
+static JSClass gd_class = {
+ "GD", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, gd_finalize
+};
+
+/* Static methods */
+static JSFunctionSpec gd_smethods[] = {
+ { "create", gd_sm_create, 2, 0, 0 },
+ { "createTrueColor", gd_sm_create_truecolor, 2, 0, 0 },
+ { "createFromJpeg", gd_sm_create_from_jpeg, 1, 0, 0 },
+ { "createFromJpegStr", gd_sm_create_from_jpeg_str, 1, 0, 0 },
+ { "createFromPng", gd_sm_create_from_png, 1, 0, 0 },
+ { "createFromPngStr", gd_sm_create_from_png_str, 1, 0, 0 },
+ { "createFromGif", gd_sm_create_from_gif, 1, 0, 0 },
+ { "createFromGifStr", gd_sm_create_from_gif_str, 1, 0, 0 },
+ { "createFromGd", gd_sm_create_from_gd, 1, 0, 0 },
+ { "createFromGdStr", gd_sm_create_from_gd_str, 1, 0, 0 },
+ { "createFromGd2", gd_sm_create_from_gd2, 1, 0, 0 },
+ { "createFromGd2Str", gd_sm_create_from_gd2_str, 1, 0, 0 },
+ { "createFromGd2Part", gd_sm_create_from_gd2_part, 5, 0, 0 },
+ { "createFromGd2PartStr", gd_sm_create_from_gd2_part_str, 5, 0, 0 },
+ { "createFromWBMP", gd_sm_create_from_wbmp, 1, 0, 0 },
+ { "createFromWBMPStr", gd_sm_create_from_wbmp_str, 1, 0, 0 },
+ { "createFromXbm", gd_sm_create_from_xbm, 1, 0, 0 },
+#ifdef HAVE_XPM
+ { "createFromXpm", gd_sm_create_from_xpm, 1, 0, 0 },
+#endif
+ { "trueColor", gd_sm_true_color, 3, 0, 0 },
+ { "trueColorAlpha", gd_sm_true_color_alpha, 4, 0, 0 },
+ { NULL, NULL, 0, 0, 0 }
+};
+
+/* Static properties */
+static struct property_spec gd_sprops[] = {
+ SP(gdDisposalNone),
+ SP(gdDisposalUnknown),
+ SP(gdDisposalRestoreBackground),
+ SP(gdDisposalRestorePrevious),
+ SP(GD2_FMT_RAW),
+ SP(GD2_FMT_COMPRESSED),
+ SP(gdAntiAliased),
+ SP(gdBrushed),
+ SP(gdMaxColors),
+ SP(gdStyled),
+ SP(gdStyledBrushed),
+ SP(gdDashSize),
+ SP(gdTiled),
+ SP(gdTransparent),
+ SP(gdArc),
+ SP(gdChord),
+ SP(gdPie),
+ SP(gdNoFill),
+ SP(gdEdged),
+ SP(gdAlphaOpaque),
+ SP(gdAlphaTransparent),
+ { NULL, 0 }
+};
+
+
+
+/*
+ * GDImage
+ */
+
+/* Class */
+static JSClass gdimage_class = {
+ "GDImage", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub,
+ gdimage_get_property, gdimage_set_property, JS_EnumerateStub,
+ JS_ResolveStub, JS_ConvertStub, gdimage_finalize
+};
+
+/* Properties */
+enum gdimage_props {
+ GDIMAGE_P_SX,
+ GDIMAGE_P_SY,
+ GDIMAGE_P_MAX
+};
+
+static JSPropertySpec gdimage_properties[GDIMAGE_P_MAX + 1] = {
+ { "sx", GDIMAGE_P_SX, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL },
+ { "sy", GDIMAGE_P_SY, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL },
+ { NULL, 0, 0, NULL, NULL }
+};
+
+/* Methods */
+static JSFunctionSpec gdimage_methods[] = {
+ { "destroy", gdimage_m_image_destroy, 0, 0, 0 },
+ { "jpeg", gdimage_m_jpeg, 2, 0, 0 },
+ { "jpegStr", gdimage_m_jpeg_str, 1, 0, 0 },
+ { "gif", gdimage_m_gif, 1, 0, 0 },
+ { "gifStr", gdimage_m_gif_str, 0, 0, 0 },
+ { "gifAnimBegin", gdimage_m_gif_anim_begin, 3, 0, 0 },
+ { "gifAnimBeginStr", gdimage_m_gif_anim_begin_str, 2, 0, 0 },
+ { "gifAnimAdd", gdimage_m_gif_anim_add, 7, 0, 0 },
+ { "gifAnimAddStr", gdimage_m_gif_anim_add_str, 6, 0, 0 },
+ { "gifAnimEnd", gdimage_m_gif_anim_end, 1, 0, 0 },
+ { "gifAnimEndStr", gdimage_m_gif_anim_end_str, 0, 0, 0 },
+ { "png", gdimage_m_png, 1, 0, 0 },
+ { "pngStr", gdimage_m_png_str, 0, 0, 0 },
+ { "pngEx", gdimage_m_png_ex, 2, 0, 0 },
+ { "pngExStr", gdimage_m_png_ex_str, 1, 0, 0 },
+ { "wbmp", gdimage_m_wbmp, 2, 0, 0 },
+ { "wbmpStr", gdimage_m_wbmp_str, 1, 0, 0 },
+ { "gd", gdimage_m_gd, 1, 0, 0 },
+ { "gdStr", gdimage_m_gd_str, 0, 0, 0 },
+ { "gd2", gdimage_m_gd2, 3, 0, 0 },
+ { "gd2Str", gdimage_m_gd2_str, 2, 0, 0 },
+ { "trueColorToPalette", gdimage_m_truecolor_to_palette, 2, 0, 0 },
+ { "createPaletteFromTrueColor",
+ gdimage_m_create_palette_from_truecolor, 2, 0, 0 },
+ { "setPixel", gdimage_m_set_pixel, 3, 0, 0 },
+ { "line", gdimage_m_line, 5, 0, 0 },
+ { "dashedLine", gdimage_m_dashed_line, 5, 0, 0 },
+ { "polygon", gdimage_m_polygon, 2, 0, 0 },
+ { "openPolygon", gdimage_m_open_polygon, 2, 0, 0 },
+ { "rectangle", gdimage_m_rectangle, 5, 0, 0 },
+ { "filledPolygon", gdimage_m_filled_polygon, 2, 0, 0 },
+ { "filledRectangle", gdimage_m_filled_rectangle, 5, 0, 0 },
+ { "arc", gdimage_m_arc, 7, 0, 0 },
+ { "filledArc", gdimage_m_filled_arc, 8, 0, 0 },
+ { "filledEllipse", gdimage_m_filled_ellipse, 5, 0, 0 },
+ { "fillToBorder", gdimage_m_fill_to_border, 4, 0, 0 },
+ { "fill", gdimage_m_fill, 3, 0, 0 },
+ { "setAntiAliased", gdimage_m_set_antialiased, 1, 0, 0 },
+ { "setAntiAliasedDontBlend", gdimage_m_set_antialiaseddontblend,
+ 2, 0, 0 },
+ { "setBrush", gdimage_m_set_brush, 1, 0, 0 },
+ { "setTile", gdimage_m_set_tile, 1, 0, 0 },
+ { "setStyle", gdimage_m_set_style, 1, 0, 0 },
+ { "setThickness", gdimage_m_set_thickness, 1, 0, 0 },
+ { "alphaBlending", gdimage_m_alpha_blending, 1, 0, 0 },
+ { "saveAlpha", gdimage_m_save_alpha, 1, 0, 0 },
+ { "setClip", gdimage_m_set_clip, 4, 0, 0 },
+ { "getClip", gdimage_m_get_clip, 0, 0, 0 },
+
+ { "colorAllocate", gdimage_m_color_allocate, 3, 0, 0 },
+ { NULL, NULL, 0, 0, 0 }
+};
+
+
+
+/*
+ * GD object control
+ */
+
+JSObject *
+js_InitGDClass(JSContext *cx, JSObject *obj)
+{
+ JSObject *proto, *ctor;
+ struct property_spec *sp;
+
+ if ((proto = JS_InitClass(cx, obj, NULL, &gd_class, gd_constructor,
+ 0, NULL, NULL, NULL, gd_smethods)) == NULL) {
+ (void) fprintf(stderr, "Error initializing GD class\n");
+ goto err;
+ }
+
+ /* Create static properties. */
+ if ((ctor = JS_GetConstructor(cx, proto)) == NULL) {
+ (void) fprintf(stderr, "GD: JS_GetConstructor == NULL\n");
+ return NULL;
+ }
+ for (sp = gd_sprops; sp->name != NULL; sp++) {
+ if (JS_DefineProperty(cx, ctor, sp->name,
+ INT_TO_JSVAL(sp->value), NULL, NULL,
+ JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) {
+ (void) fprintf(stderr,
+ "GD: Error defining property %s\n", sp->name);
+ return NULL;
+ }
+ }
+
+ /*
+ * Initialize GDImage class since we'll need to instanciate it from C
+ */
+ if (js_InitGDImageClass(cx, obj) == NULL) {
+ (void) fprintf(stderr, "GD: InitGDImageClass()\n");
+ goto err;
+ }
+
+ return proto;
+
+err:
+ return NULL;
+}
+
+/* ARGSUSED */
+static JSBool
+gd_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+ QUEUE_EXCEPTION("GD object not user-instanciable");
+
+ return JS_FALSE;
+}
+
+/* ARGSUSED */
+static void
+gd_finalize(JSContext *cx, JSObject *obj)
+{
+
+ /* NOOP */
+}
+
+
+
+/* GD static methods */
+static JSBool
+gd_sm_create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 2) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ if ((img = gdImageCreate(JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("gdImageCreate()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_truecolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 2) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ if ((img = gdImageCreateTrueColor(JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("gdImageCreate()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_file_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, gdImagePtr (*funcptr)(FILE *), const char *funcname)
+{
+ FILE *fh;
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ goto err;
+ }
+
+ if ((img = funcptr(fh)) == NULL) {
+ QUEUE_EXCEPTION(funcname);
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+/*
+ * We replace gdImageCreateFrom*Ptr() by methods using a String.
+ */
+static JSBool
+gd_sm_create_from_str_i(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval, gdImagePtr (*funcptr)(int, void *),
+ const char *funcname)
+{
+ JSString *str;
+ char *bytes;
+ size_t size;
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ goto err;
+ }
+
+ str = JSVAL_TO_STRING(argv[0]);
+ if ((bytes = JS_GetStringBytes(str)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ size = JS_GetStringLength(str);
+
+ if ((img = funcptr((int)size, bytes)) == NULL) {
+ QUEUE_EXCEPTION(funcname);
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_jpeg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromJpeg, "gdImageCreateFromJpeg()");
+}
+
+static JSBool
+gd_sm_create_from_jpeg_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromJpegPtr, "gdImageCreateFromJpegPtr()");
+}
+
+static JSBool
+gd_sm_create_from_png(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromPng, "gdImageCreateFromPng()");
+}
+
+static JSBool
+gd_sm_create_from_png_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromPngPtr, "gdImageCreateFromPngPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gif(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGif, "gdImageCreateFromGif()");
+}
+
+static JSBool
+gd_sm_create_from_gif_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGifPtr, "gdImageCreateFromGifPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGd, "gdImageCreateFromGd()");
+}
+
+static JSBool
+gd_sm_create_from_gd_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGdPtr, "gdImageCreateFromGdPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gd2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGd2, "gdImageCreateFromGd2()");
+}
+
+static JSBool
+gd_sm_create_from_gd2_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromGd2Ptr, "gdImageCreateFromGd2Ptr()");
+}
+
+static JSBool
+gd_sm_create_from_gd2_part(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ FILE *fh;
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 5) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ goto err;
+ }
+
+ if ((img = gdImageCreateFromGd2Part(fh, JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+ JSVAL_TO_INT(argv[4]))) == NULL) {
+ QUEUE_EXCEPTION("gdImageCreateFromGd2Part()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+/*
+ * We replace gdImageCreateFrom*Ptr() by methods using a String.
+ */
+static JSBool
+gd_sm_create_from_gd2_part_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ JSString *str;
+ char *bytes;
+ size_t size;
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 5) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ goto err;
+ }
+
+ str = JSVAL_TO_STRING(argv[0]);
+ if ((bytes = JS_GetStringBytes(str)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ size = JS_GetStringLength(str);
+
+ if ((img = gdImageCreateFromGd2PartPtr((int)size, bytes,
+ JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]),
+ JSVAL_TO_INT(argv[3]), JSVAL_TO_INT(argv[4]))) == NULL) {
+ QUEUE_EXCEPTION("GdImageCreateFromGd2PartPtr()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_wbmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromWBMP, "gdImageCreateFromWBMP()");
+}
+
+static JSBool
+gd_sm_create_from_wbmp_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromWBMPPtr, "gdImageCreateFromWBMPPtr()");
+}
+
+static JSBool
+gd_sm_create_from_xbm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+ gdImageCreateFromXbm, "gdImageCreateFromXbm()");
+}
+
+#ifdef HAVE_XPM
+static JSBool
+gd_sm_create_from_xpm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, gdImagePtr (*funcptr)(FILE *), const char *funcname)
+{
+ const char *bytes;
+ gdImagePtr img = NULL;
+ JSObject *o;
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_STRING(argv[0]) ||
+ (bytes = JS_GetStringBytes(argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a String");
+ goto err;
+ }
+
+ /* XXX Perform path sanity/access checking */
+ if ((img = gdImageCreateFromXpm(bytes)) == NULL) {
+ QUEUE_EXCEPTION("gdImageCreateFromXpm()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img != NULL)
+ gdImageDestroy(img);
+
+ return JS_FALSE;
+}
+#endif
+
+static JSBool
+gd_sm_true_color(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ int col, i1, i2, i3;
+
+ if (argc != 3) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+
+ /* Since gdTrueColor is a macro, avoid side-effects */
+ i1 = JSVAL_TO_INT(argv[0]);
+ i2 = JSVAL_TO_INT(argv[1]);
+ i3 = JSVAL_TO_INT(argv[2]);
+ col = gdTrueColor(i1, i2, i3);
+ *rval = INT_TO_JSVAL(col);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gd_sm_true_color_alpha(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ int col, i1, i2, i3, i4;
+
+ if (argc != 4) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ goto err;
+ }
+
+ /* Since gdTrueColorAlpha() is a macro, avoid side-effects */
+ i1 = JSVAL_TO_INT(argv[0]);
+ i2 = JSVAL_TO_INT(argv[1]);
+ i3 = JSVAL_TO_INT(argv[2]);
+ i4 = JSVAL_TO_INT(argv[3]);
+ col = gdTrueColorAlpha(i1, i2, i3, i4);
+ *rval = INT_TO_JSVAL(col);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+
+/*
+ * GDImage object control
+ */
+
+static JSObject *
+js_InitGDImageClass(JSContext *cx, JSObject *obj)
+{
+
+ return (JS_InitClass(cx, obj, NULL, &gdimage_class,
+ gdimage_constructor, 0, gdimage_properties, gdimage_methods, NULL,
+ NULL));
+}
+
+/* ARGSUSED */
+static JSBool
+gdimage_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ QUEUE_EXCEPTION("GDImage class not user-instanciable");
+
+ return JS_FALSE;
+}
+
+static void
+gdimage_finalize(JSContext *cx, JSObject *obj)
+{
+ gdImagePtr img;
+
+ if ((img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL))
+ != NULL) {
+ gdImageDestroy(img);
+ (void) JS_SetPrivate(cx, obj, NULL);
+ }
+}
+
+
+/* GDImage object property setters/getters */
+static JSBool
+gdimage_get_property(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint p;
+ gdImagePtr img;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ p = (int)JSVAL_TO_INT(id);
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ switch (p) {
+ case GDIMAGE_P_SX:
+ *vp = INT_TO_JSVAL(img->sx);
+ break;
+ case GDIMAGE_P_SY:
+ *vp = INT_TO_JSVAL(img->sy);
+ break;
+ }
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_set_property(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ jsint p;
+ gdImagePtr img;
+
+ if (!JSVAL_IS_INT(id))
+ return JS_TRUE;
+ p = (int)JSVAL_TO_INT(id);
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ switch (p) {
+ /* XXX No writable property yet */
+ }
+
+ return JS_TRUE;
+}
+
+
+/*
+ * GDImage object properties
+ */
+
+/*
+ * GDImage object methods
+ */
+
+static JSBool
+gdimage_m_image_destroy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageDestroy(img);
+ (void) JS_SetPrivate(cx, obj, NULL);
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_TRUE;
+}
+
+/*
+ * Called by multiple similar functions
+ */
+static JSBool
+gdimage_m_save_file_i0(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void (*funcptr)(gdImagePtr, FILE *))
+{
+ FILE *fh;
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ funcptr(img, fh);
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_file_i1(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void (*funcptr)(gdImagePtr, FILE *, int))
+{
+ FILE *fh;
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ funcptr(img, fh, JSVAL_TO_INT(argv[1]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_str_i0(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void *(*funcptr)(gdImagePtr, int *), const char *funcname)
+{
+ gdImagePtr img;
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((data = funcptr(img, &size)) == NULL) {
+ QUEUE_EXCEPTION(funcname);
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_save_str_i1(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void *(*funcptr)(gdImagePtr, int *, int),
+ const char *funcname)
+{
+ gdImagePtr img;
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((data = funcptr(img, &size, JSVAL_TO_INT(argv[0]))) == NULL) {
+ QUEUE_EXCEPTION(funcname);
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_jpeg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_file_i1(cx, obj, argc, argv, rval, gdImageJpeg);
+}
+
+static JSBool
+gdimage_m_jpeg_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i1(cx, obj, argc, argv, rval,
+ gdImageJpegPtr, "gdImageJpegPtr()");
+}
+
+static JSBool
+gdimage_m_gif(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImageGif);
+}
+
+static JSBool
+gdimage_m_gif_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i0(cx, obj, argc, argv, rval,
+ gdImageGifPtr, "gdImageGifPtr()");
+}
+
+static JSBool
+gdimage_m_gif_anim_begin(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ FILE *fh;
+ gdImagePtr img;
+
+ if (argc != 3) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageGifAnimBegin(img, fh, JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]));
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_begin_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 2) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((data = gdImageGifAnimBeginPtr(img, &size, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("gdImageGifAnimBeginPtr()");
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_add(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ FILE *fh;
+ gdImagePtr img, img2;
+
+ if (argc != 7) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ 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_NULL(argv[6]))
+ img2 = NULL;
+ else {
+ JSObject *o;
+
+ if (!JSVAL_IS_OBJECT(argv[6])) {
+ QUEUE_EXCEPTION(
+ "Argument 7 not Null or GDImage object");
+ goto err;
+ }
+ o = JSVAL_TO_OBJECT(argv[6]);
+ if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+ QUEUE_EXCEPTION(
+ "Argument 7 not Null or GDImage object");
+ goto err;
+ }
+
+ img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+ assert(img2 != NULL);
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageGifAnimAdd(img, fh, JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+ JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]), img2);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_add_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img, img2;
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 6) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[3])) {
+ QUEUE_EXCEPTION("Argument 4 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[4])) {
+ QUEUE_EXCEPTION("Argument 5 not an Integer");
+ goto err;
+ }
+ if (JSVAL_IS_NULL(argv[5]))
+ img2 = NULL;
+ else {
+ JSObject *o;
+
+ if (!JSVAL_IS_OBJECT(argv[5])) {
+ QUEUE_EXCEPTION(
+ "Argument 6 not Null or GDImage object");
+ goto err;
+ }
+ o = JSVAL_TO_OBJECT(argv[6]);
+ if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+ QUEUE_EXCEPTION(
+ "Argument 6 not Null or GDImage object");
+ goto err;
+ }
+
+ img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+ assert(img2 != NULL);
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((data = gdImageGifAnimAddPtr(img, &size, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+ JSVAL_TO_INT(argv[4]), img2)) == NULL) {
+ QUEUE_EXCEPTION("gdImageGifAnimAddPtr()");
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+/*
+ * For consistency, GD authors should have made these two still require the
+ * gdImagePtr argument. However, they don't... so we had to rewrite these.
+ * We however still present a consistent API and attach this method to the
+ * GDImage object.
+ */
+static JSBool
+gdimage_m_gif_anim_end(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ FILE *fh;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ return JS_FALSE;
+ }
+
+ gdImageGifAnimEnd(fh);
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_gif_anim_end_str(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+
+ if ((data = gdImageGifAnimEndPtr(&size)) == NULL) {
+ QUEUE_EXCEPTION("gdImageGifAnimEndPtr()");
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_png(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImagePng);
+}
+
+static JSBool
+gdimage_m_png_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i0(cx, obj, argc, argv, rval, gdImagePngPtr,
+ "gdImagePngPtr()");
+}
+
+static JSBool
+gdimage_m_png_ex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_file_i1(cx, obj, argc, argv, rval, gdImagePngEx);
+}
+
+static JSBool
+gdimage_m_png_ex_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i1(cx, obj, argc, argv, rval,
+ gdImagePngPtrEx, "gdImagePngPtrEx()");
+}
+
+/*
+ * GD is inconsistent and gdImageWBMP() takes int argument before the FILE *.
+ * We however make it consistent in this API.
+ */
+static JSBool
+gdimage_m_wbmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ FILE *fh;
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 1 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageWBMP(img, JSVAL_TO_INT(argv[1]), fh);
+
+ return JS_TRUE;
+}
+
+/*
+ * GD documentation states that gdImageWBMPPtr() does't take an int, but it
+ * does after the FILE *, like gdImageWBMP() but with revesed arguments order.
+ * This function seemed consistent, at least.
+ */
+static JSBool
+gdimage_m_wbmp_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i1(cx, obj, argc, argv, rval, gdImageWBMPPtr,
+ "gdImageWBMPPtr()");
+}
+
+static JSBool
+gdimage_m_gd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImageGd);
+}
+
+static JSBool
+gdimage_m_gd_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_save_str_i0(cx, obj, argc, argv, rval, gdImageGdPtr,
+ "gdImageGdPtr()");
+}
+
+static JSBool
+gdimage_m_gd2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ FILE *fh;
+ gdImagePtr img;
+
+ if (argc != 3) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((fh = file_fh(cx, argv[0])) == NULL) {
+ QUEUE_EXCEPTION("Argument 1 not a File object");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+ if (!JSVAL_IS_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageGd2(img, fh, JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]));
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gd2_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ void *data = NULL;
+ int size;
+ JSString *str;
+
+ if (argc != 2) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ /*
+ * Also an inconsistent GD function as it requires the int pointer
+ * after the other integer arguments.
+ */
+ if ((data = gdImageGd2Ptr(img, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]), &size)) == NULL) {
+ QUEUE_EXCEPTION("gdImageGd2Ptr()");
+ goto err;
+ }
+
+ if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+ *rval = STRING_TO_JSVAL(str);
+ gdFree(data);
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (data != NULL)
+ gdFree(data);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_truecolor_to_palette(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ 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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageTrueColorToPalette(img, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_create_palette_from_truecolor(JSContext *cx, JSObject *obj,
+ uintN argc, jsval *argv, jsval *rval)
+{
+ gdImagePtr img, img2 = NULL;
+ JSObject *o;
+
+ if (argc != 2) {
+ 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_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ if ((img2 = gdImageCreatePaletteFromTrueColor(img,
+ JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]))) == NULL) {
+ QUEUE_EXCEPTION("gdImageCreatePaletteFromTrueColor()");
+ goto err;
+ }
+
+ if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_SetPrivate(cx, o, img2)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+ if (img2 != NULL)
+ gdFree(img2);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_set_pixel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ 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_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSetPixel(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_primitive5_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void (*funcptr)(gdImagePtr, int, int, int, int, int))
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 5) {
+ 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_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, JSVAL_TO_INT(argv[0]), 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_line(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_primitive5_i(cx, obj, argc, argv, rval, gdImageLine);
+}
+
+static JSBool
+gdimage_m_dashed_line(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+ gdImageDashedLine);
+}
+
+/*
+ * Converts a JS array of integer pairs to a C gdPoint array, which must be
+ * freed by the caller on success. On failure, we return NULL and
+ * automatically send an appropriate exception. On success, we return the
+ * gdPoint array pointer and store the number of verticles stored in it via
+ * the provided size pointer.
+ */
+static gdPointPtr
+array_to_gdpoints_i(JSContext *cx, jsval a, int *size)
+{
+ JSObject *o;
+ jsuint len;
+ JSIdArray *ida = NULL;
+ gdPointPtr pts = NULL;
+ int i, i2, i3;
+ jsval id, val;
+
+ if (!JSVAL_IS_OBJECT(a) ||
+ !JS_IsArrayObject(cx, (o = JSVAL_TO_OBJECT(a)))) {
+ QUEUE_EXCEPTION("Argument not an Array object");
+ goto err;
+ }
+ if (!JS_GetArrayLength(cx, o, &len) || ((len & 1) != 0)) {
+ QUEUE_EXCEPTION("Array not holding even pairs");
+ goto err;
+ }
+
+ len /= 2;
+ if ((pts = malloc(sizeof(gdPoint) * len)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+
+ if ((ida = JS_Enumerate(cx, o)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ for (i3 = i2 = i = 0; i < ida->length; i++) {
+ JS_IdToValue(cx, ida->vector[i], &id);
+ if (!JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) ||
+ JSVAL_IS_VOID(val))
+ continue;
+ if (!JSVAL_IS_INT(val)) {
+ QUEUE_EXCEPTION("Array elements not all Integers");
+ goto err;
+ }
+ if ((i2++ & 1) == 0)
+ pts[i3].x = JSVAL_TO_INT(val);
+ else
+ pts[i3++].y = JSVAL_TO_INT(val);
+ }
+ JS_DestroyIdArray(cx, ida);
+ ida = NULL;
+
+ *size = len;
+ return pts;
+
+err:
+ if (ida != NULL)
+ JS_DestroyIdArray(cx, ida);
+ if (pts != NULL)
+ free(pts);
+ *size = 0;
+
+ return NULL;
+}
+
+/*
+ * Converts a JS array of integer pairs to a C int array, which must be
+ * freed by the caller on success. On failure, we return NULL and
+ * automatically send an appropriate exception. On success, we return the
+ * int array pointer and store the number of entries stored in it via
+ * the provided size pointer.
+ */
+static int *
+array_to_ints_i(JSContext *cx, jsval a, int *size)
+{
+ JSObject *o;
+ jsuint len;
+ JSIdArray *ida = NULL;
+ int *pts = NULL;
+ int i, i2;
+ jsval id, val;
+
+ if (!JSVAL_IS_OBJECT(a) ||
+ !JS_IsArrayObject(cx, (o = JSVAL_TO_OBJECT(a)))) {
+ QUEUE_EXCEPTION("Argument not an Array object");
+ goto err;
+ }
+ if (!JS_GetArrayLength(cx, o, &len)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ if ((pts = malloc(sizeof(int) * len)) == NULL) {
+ QUEUE_EXCEPTION("Out of memory!");
+ goto err;
+ }
+
+ if ((ida = JS_Enumerate(cx, o)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ for (i2 = i = 0; i < ida->length; i++) {
+ JS_IdToValue(cx, ida->vector[i], &id);
+ if (!JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) ||
+ JSVAL_IS_VOID(val))
+ continue;
+ if (!JSVAL_IS_INT(val)) {
+ QUEUE_EXCEPTION("Array elements not all Integers");
+ goto err;
+ }
+ pts[i2++] = JSVAL_TO_INT(val);
+ }
+ JS_DestroyIdArray(cx, ida);
+ ida = NULL;
+
+ *size = len;
+ return pts;
+
+err:
+ if (ida != NULL)
+ JS_DestroyIdArray(cx, ida);
+ if (pts != NULL)
+ free(pts);
+ *size = 0;
+
+ return NULL;
+}
+
+static JSBool
+gdimage_m_polygon_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval, void (*funcptr)(gdImagePtr, gdPointPtr, int, int))
+{
+ gdImagePtr img;
+ gdPointPtr pts = NULL;
+ int size;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((pts = array_to_gdpoints_i(cx, argv[0], &size)) == NULL)
+ goto err;
+ if (!JSVAL_IS_INT(argv[1])) {
+ QUEUE_EXCEPTION("Argument 2 not an Integer");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ funcptr(img, pts, size, JSVAL_TO_INT(argv[1]));
+ free(pts);
+
+ return JS_TRUE;
+
+err:
+ if (pts != NULL)
+ free(pts);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_polygon_i(cx, obj, argc, argv, rval, gdImagePolygon);
+}
+
+static JSBool
+gdimage_m_open_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_polygon_i(cx, obj, argc, argv, rval,
+ gdImageOpenPolygon);
+}
+
+static JSBool
+gdimage_m_rectangle(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+ gdImageRectangle);
+}
+
+static JSBool
+gdimage_m_filled_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_polygon_i(cx, obj, argc, argv, rval,
+ gdImageFilledPolygon);
+}
+
+static JSBool
+gdimage_m_filled_rectangle(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+
+ return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+ gdImageFilledRectangle);
+}
+
+static JSBool
+gdimage_m_arc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ int i;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 7) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ for (i = 0; i < 7; i++) {
+ if (!JSVAL_IS_INT(argv[i])) {
+ QUEUE_EXCEPTION("Argument not an Integer");
+ return JS_FALSE;
+ }
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageArc(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+ JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]),
+ JSVAL_TO_INT(argv[6]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_filled_arc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ int i;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 8) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ for (i = 0; i < 8; i++) {
+ if (!JSVAL_IS_INT(argv[i])) {
+ QUEUE_EXCEPTION("Argument not an Integer");
+ return JS_FALSE;
+ }
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageFilledArc(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+ JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]),
+ JSVAL_TO_INT(argv[6]), JSVAL_TO_INT(argv[7]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_filled_ellipse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+
+ return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+ gdImageFilledEllipse);
+}
+
+static JSBool
+gdimage_m_fill_to_border(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 4) {
+ 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_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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageFillToBorder(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_fill(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ 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_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageFill(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_antialiased(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ 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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSetAntiAliased(img, JSVAL_TO_INT(argv[0]));
+
+ return JS_TRUE;
+}
+
+/*
+ * Although documentation specifies that this gdImageSetAntialiasedDontBlend()
+ * requires two parameters, it actually requires three.
+ */
+static JSBool
+gdimage_m_set_antialiaseddontblend(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 2) {
+ 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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSetAntiAliasedDontBlend(img, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_brush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img, img2;
+ JSObject *o;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_OBJECT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+ return JS_FALSE;
+ }
+ o = JSVAL_TO_OBJECT(argv[0]);
+ if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+ QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+ img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+ assert(img2 != NULL);
+
+ /*
+ * Delete any previously associated GDImage property and reassign the
+ * new one so that the JS GC knows the dependency.
+ */
+ (void) JS_DeleteProperty(cx, obj, "gdimage_brush");
+ if (!JS_DefineProperty(cx, obj, "gdimage_brush", argv[0], NULL,
+ NULL, 0)) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+
+ gdImageSetBrush(img, img2);
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_tile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img, img2;
+ JSObject *o;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_OBJECT(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+ return JS_FALSE;
+ }
+ o = JSVAL_TO_OBJECT(argv[0]);
+ if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+ QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+ img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+ assert(img2 != NULL);
+
+ /*
+ * Delete any previously associated GDImage property and reassign the
+ * new one so that the JS GC knows the dependency.
+ */
+ (void) JS_DeleteProperty(cx, obj, "gdimage_tile");
+ if (!JS_DefineProperty(cx, obj, "gdimage_tile", argv[0], NULL, NULL,
+ 0)) {
+ QUEUE_EXCEPTION("Internal error!");
+ return JS_FALSE;
+ }
+
+ gdImageSetTile(img, img2);
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_style(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ int *pts = NULL;
+ int size;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+ if ((pts = array_to_ints_i(cx, argv[0], &size)) == NULL)
+ goto err;
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ /* The supplied array is copied as of gd v1.1.1 and up. */
+ gdImageSetStyle(img, pts, size);
+ free(pts);
+
+ return JS_TRUE;
+
+err:
+ if (pts != NULL)
+ free(pts);
+
+ return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_set_thickness(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ 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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSetThickness(img, JSVAL_TO_INT(argv[0]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_alpha_blending(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_BOOLEAN(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a Boolean");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageAlphaBlending(img, (int)JSVAL_TO_BOOLEAN(argv[0]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_alpha(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 1) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ return JS_FALSE;
+ }
+ if (!JSVAL_IS_BOOLEAN(argv[0])) {
+ QUEUE_EXCEPTION("Argument 1 not a Boolean");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSaveAlpha(img, (int)JSVAL_TO_BOOLEAN(argv[0]));
+
+ return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_clip(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 4) {
+ 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_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;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageSetClip(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+ JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]));
+
+ return JS_TRUE;
+}
+
+/*
+ * Unlike gdImageGetClip() which fills four ints via their supplied pointers,
+ * this method returns an object with x1, y1, x2, y2 properties set.
+ */
+static JSBool
+gdimage_m_get_clip(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ gdImagePtr img;
+ int x1, y1, x2, y2;
+ JSObject *o;
+
+ if (argc != 0) {
+ QUEUE_EXCEPTION("Wrong number of arguments");
+ goto err;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ gdImageGetClip(img, &x1, &y1, &x2, &y2);
+
+ if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+ *rval = OBJECT_TO_JSVAL(o);
+ if (!JS_DefineProperty(cx, o, "x1", INT_TO_JSVAL(x1), NULL, NULL,
+ JSPROP_ENUMERATE) ||
+ !JS_DefineProperty(cx, o, "y1", INT_TO_JSVAL(y1), NULL, NULL,
+ JSPROP_ENUMERATE) ||
+ !JS_DefineProperty(cx, o, "x2", INT_TO_JSVAL(x2), NULL, NULL,
+ JSPROP_ENUMERATE) ||
+ !JS_DefineProperty(cx, o, "y2", INT_TO_JSVAL(y2), NULL, NULL,
+ JSPROP_ENUMERATE)) {
+ QUEUE_EXCEPTION("Internal error!");
+ goto err;
+ }
+
+ return JS_TRUE;
+
+err:
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ return JS_FALSE;
+}
+
+
+static JSBool
+gdimage_m_color_allocate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+ jsval *rval)
+{
+ gdImagePtr img;
+ int col;
+
+ *rval = OBJECT_TO_JSVAL(NULL);
+
+ if (argc != 3) {
+ 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_INT(argv[2])) {
+ QUEUE_EXCEPTION("Argument 3 not an Integer");
+ return JS_FALSE;
+ }
+
+ img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+ assert(img != NULL);
+
+ col = gdImageColorAllocate(img, JSVAL_TO_INT(argv[0]),
+ JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]));
+ *rval = INT_TO_JSVAL(col);
+
+ return JS_TRUE;
+}