]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
fix SV type probing to not break pre perl 5.12
[imager.git] / Imager.xs
index bc9507208a51504bd39085f62ff577d28371a7f9..eaf756e5ea4241c7861cd7a377403cfdf708cc5a 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -21,6 +21,7 @@ extern "C" {
 #include "regmach.h"
 #include "imextdef.h"
 #include "imextpltypes.h"
+#include "imperlio.h"
 #include <float.h>
 
 #if i_int_hlines_testing()
@@ -29,13 +30,73 @@ extern "C" {
 
 #include "imperl.h"
 
-static im_context_t work_context;
+#ifndef SV_COW_DROP_PV
+#define SV_COW_DROP_PV 0
+#endif
+
+/*
+
+Context object management
+
+*/
+
+typedef im_context_t Imager__Context;
+
+#define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY")
+
+#ifdef PERL_IMPLICIT_CONTEXT
+
+#define MY_CXT_KEY "Imager::_context" XS_VERSION
+
+typedef struct {
+  im_context_t ctx;
+} my_cxt_t;
+
+START_MY_CXT
+
+im_context_t fallback_context;
+
+static void
+start_context(pTHX) {
+  dMY_CXT;
+  MY_CXT.ctx = im_context_new();
+  sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
+
+  /* Ideally we'd free this reference, but the error message memory
+     was never released on exit, so the associated memory here is reasonable
+     to keep.
+     With logging enabled we always need at least one context, since
+     objects may be released fairly late and attempt to get the log file.
+  */
+  im_context_refinc(MY_CXT.ctx, "start_context");
+  fallback_context = MY_CXT.ctx;
+}
+
+static im_context_t
+perl_get_context(void) {
+  dTHX;
+  dMY_CXT;
+  
+  return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
+}
+
+#else
+
+static im_context_t perl_context;
+
+static void
+start_context(pTHX) {
+  perl_context = im_context_new();
+  im_context_refinc(perl_context, "start_context");
+}
 
 static im_context_t
 perl_get_context(void) {
-  return work_context;
+  return perl_context;
 }
 
+#endif
+
 /* used to represent channel lists parameters */
 typedef struct i_channel_list_tag {
   int *channels;
@@ -65,6 +126,36 @@ malloc_temp(pTHX_ size_t size) {
   return SvPVX(sv);
 }
 
+static void *
+calloc_temp(pTHX_ size_t size) {
+  void *result = malloc_temp(aTHX_ size);
+  memset(result, 0, size);
+
+  return result;
+}
+
+/* for use with the T_AVARRAY typemap */
+#define doublePtr(size) ((double *)calloc_temp(aTHX_ sizeof(double) * (size)))
+#define SvDouble(sv, pname) (SvNV(sv))
+
+#define intPtr(size) ((int *)calloc_temp(aTHX_ sizeof(int) * (size)))
+#define SvInt(sv, pname) (SvIV(sv))
+
+#define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size)))
+#define SvI_img_dim(sv, pname) (SvIV(sv))
+
+#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size)))
+
+#define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname)
+
+static i_color
+S_sv_to_i_color(pTHX_ SV *sv, const char *pname) {
+  if (!sv_derived_from(sv, "Imager::Color")) {
+    croak("%s: not a color object", pname);
+  }
+  return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
+}
+
 /* These functions are all shared - then comes platform dependant code */
 static int getstr(void *hv_t,char *key,char **store) {
   dTHX;
@@ -147,9 +238,9 @@ static int getobj(void *hv_t,char *key,char *type,void **store) {
 
 UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
 
-void my_SvREFCNT_dec(void *p) {
-  dTHX;
-  SvREFCNT_dec((SV*)p);
+static void
+free_buffer(void *p) {
+  myfree(p);
 }
 
 
@@ -324,7 +415,6 @@ static int io_closer(void *p) {
   if (SvOK(cbd->closecb)) {
     dSP;
     I32 count;
-    SV *sv;
 
     ENTER;
     SAVETMPS;
@@ -335,8 +425,12 @@ static int io_closer(void *p) {
 
     SPAGAIN;
     
-    sv = POPs;
-    success = SvTRUE(sv);
+    if (count) {
+      SV *sv = POPs;
+      success = SvTRUE(sv);
+    }
+    else
+      success = 0;
 
     PUTBACK;
     FREETMPS;
@@ -357,14 +451,26 @@ static void io_destroyer(void *p) {
   myfree(cbd);
 }
 
-static i_io_glue_t *
-do_io_new_buffer(pTHX_ SV *data_sv) {
-  const char *data;
-  STRLEN length;
+static bool
+im_SvREFSCALAR(SV *sv) {
+  svtype type = SvTYPE(sv);
+
+  switch (type) {
+  case SVt_PV:
+  case SVt_PVIV:
+  case SVt_PVNV:
+  case SVt_PVMG:
+  case SVt_IV:
+  case SVt_NV:
+  case SVt_PVLV:
+#if PERL_VERSION > 10
+  case SVt_REGEXP:
+#endif
+    return 1;
 
-  data = SvPVbyte(data_sv, length);
-  SvREFCNT_inc(data_sv);
-  return io_new_buffer(data, length, my_SvREFCNT_dec, data_sv);
+  default:
+    return 0;
+  }
 }
 
 static const char *
@@ -388,6 +494,35 @@ describe_sv(SV *sv) {
   }
 }
 
+static i_io_glue_t *
+do_io_new_buffer(pTHX_ SV *data_sv) {
+  const char *data;
+  char *data_copy;
+  STRLEN length;
+  SV *sv;
+
+  SvGETMAGIC(data_sv);
+  if (SvROK(data_sv)) {
+    if (im_SvREFSCALAR(SvRV(data_sv))) {
+      sv = SvRV(data_sv);
+    }
+    else {
+      i_push_errorf(0, "data is not a scalar or a reference to scalar");
+      return NULL;
+    }
+  }
+  else {
+    sv = data_sv;
+  }
+
+  /* previously this would keep the SV around, but this is unsafe in
+     many ways, so always copy the bytes */
+  data = SvPVbyte(sv, length);
+  data_copy = mymalloc(length);
+  memcpy(data_copy, data, length);
+  return io_new_buffer(data_copy, length, free_buffer, data_copy);
+}
+
 static i_io_glue_t *
 do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
   struct cbdata *cbd;
@@ -734,7 +869,6 @@ validate_i_ppal(i_img *im, i_palidx const *indexes, int count) {
   }
 }
 
-
 /* I don't think ICLF_* names belong at the C interface
    this makes the XS code think we have them, to let us avoid 
    putting function bodies in the XS code
@@ -844,6 +978,7 @@ static im_pl_ext_funcs im_perl_funcs =
 
 #define IIM_new i_img_8_new
 #define IIM_DESTROY i_img_destroy
+typedef int SysRet;
 
 #ifdef IMEXIF_ENABLE
 #define i_exif_enabled() 1
@@ -898,10 +1033,10 @@ ICL_rgba(cl)
              Imager::Color     cl
            PPCODE:
                EXTEND(SP, 4);
-               PUSHs(sv_2mortal(newSVnv(cl->rgba.r)));
-               PUSHs(sv_2mortal(newSVnv(cl->rgba.g)));
-               PUSHs(sv_2mortal(newSVnv(cl->rgba.b)));
-               PUSHs(sv_2mortal(newSVnv(cl->rgba.a)));
+               PUSHs(sv_2mortal(newSViv(cl->rgba.r)));
+               PUSHs(sv_2mortal(newSViv(cl->rgba.g)));
+               PUSHs(sv_2mortal(newSViv(cl->rgba.b)));
+               PUSHs(sv_2mortal(newSViv(cl->rgba.a)));
 
 Imager::Color
 i_hsv_to_rgb(c)
@@ -1016,7 +1151,10 @@ Imager::IO
 io_new_buffer(data_sv)
          SV   *data_sv
        CODE:
+         i_clear_error();
          RETVAL = do_io_new_buffer(aTHX_ data_sv);
+         if (!RETVAL)
+           XSRETURN(0);
         OUTPUT:
           RETVAL
 
@@ -1026,7 +1164,6 @@ io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
         SV *readcb;
         SV *seekcb;
         SV *closecb;
-        int maxwrite;
       CODE:
         RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
       OUTPUT:
@@ -1088,7 +1225,10 @@ Imager::IO
 io_new_buffer(class, data_sv)
        SV *data_sv
     CODE:
+        i_clear_error();
         RETVAL = do_io_new_buffer(aTHX_ data_sv);
+       if (!RETVAL)
+         XSRETURN(0);
     OUTPUT:
         RETVAL
 
@@ -1110,6 +1250,14 @@ io_new_bufchain(class)
     OUTPUT:
         RETVAL
 
+Imager::IO
+io__new_perlio(class, io)
+       PerlIO *io
+  CODE:
+        RETVAL = im_io_new_perlio(aTHX_ io);
+  OUTPUT:
+       RETVAL
+
 SV *
 io_slurp(class, ig)
         Imager::IO     ig
@@ -1134,14 +1282,7 @@ i_io_raw_write(ig, data_sv)
         void *data;
        STRLEN size;
       CODE:
-#ifdef SvUTF8
-        if (SvUTF8(data_sv)) {
-         data_sv = sv_2mortal(newSVsv(data_sv));
-          /* yes, we want this to croak() if the SV can't be downgraded */
-         sv_utf8_downgrade(data_sv, FALSE);
-       }
-#endif        
-       data = SvPV(data_sv, size);
+       data = SvPVbyte(data_sv, size);
         RETVAL = i_io_raw_write(ig, data, size);
       OUTPUT:
        RETVAL
@@ -1157,15 +1298,9 @@ i_io_raw_read(ig, buffer_sv, size)
       PPCODE:
         if (size <= 0)
          croak("size negative in call to i_io_raw_read()");
-        /* prevent an undefined value warning if they supplied an 
-          undef buffer.
-           Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
-#ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
-          sv_utf8_downgrade(buffer_sv, FALSE);
-#endif
+       if (SvTHINKFIRST(buffer_sv))
+         sv_force_normal_flags(buffer_sv, SV_COW_DROP_PV);
+       SvUPGRADE(buffer_sv, SVt_PV);
        buffer = SvGROW(buffer_sv, size+1);
         result = i_io_raw_read(ig, buffer, size);
         if (result >= 0) {
@@ -1288,15 +1423,9 @@ i_io_read(ig, buffer_sv, size)
       PPCODE:
         if (size <= 0)
          croak("size negative in call to i_io_read()");
-        /* prevent an undefined value warning if they supplied an 
-          undef buffer.
-           Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
-#ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
-          sv_utf8_downgrade(buffer_sv, FALSE);
-#endif
+       if (SvTHINKFIRST(buffer_sv))
+         sv_force_normal_flags(buffer_sv, SV_COW_DROP_PV);
+       SvUPGRADE(buffer_sv, SVt_PV);
        buffer = SvGROW(buffer_sv, size+1);
         result = i_io_read(ig, buffer, size);
         if (result >= 0) {
@@ -1366,14 +1495,7 @@ i_io_write(ig, data_sv)
         void *data;
        STRLEN size;
       CODE:
-#ifdef SvUTF8
-        if (SvUTF8(data_sv)) {
-         data_sv = sv_2mortal(newSVsv(data_sv));
-          /* yes, we want this to croak() if the SV can't be downgraded */
-         sv_utf8_downgrade(data_sv, FALSE);
-       }
-#endif        
-       data = SvPV(data_sv, size);
+       data = SvPVbyte(data_sv, size);
         RETVAL = i_io_write(ig, data, size);
       OUTPUT:
        RETVAL
@@ -1658,112 +1780,50 @@ i_arc_out_aa(im,x,y,rad,d1,d2,val)
 
 
 void
-i_bezier_multi(im,xc,yc,val)
+i_bezier_multi(im,x,y,val)
     Imager::ImgRaw     im
-             Imager::Color  val
-            PREINIT:
-            double   *x,*y;
-            int       len;
-            AV       *av1;
-            AV       *av2;
-            SV       *sv1;
-            SV       *sv2;
-            int i;
-            PPCODE:
-            ICL_info(val);
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            av1=(AV*)SvRV(ST(1));
-            av2=(AV*)SvRV(ST(2));
-            if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
-            len=av_len(av1)+1;
-            x=mymalloc( len*sizeof(double) );
-            y=mymalloc( len*sizeof(double) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av1,i,0)));
-              sv2=(*(av_fetch(av2,i,0)));
-              x[i]=(double)SvNV(sv1);
-              y[i]=(double)SvNV(sv2);
-            }
-             i_bezier_multi(im,len,x,y,val);
-             myfree(x);
-             myfree(y);
-
+    double *x
+    double *y
+    Imager::Color  val
+  PREINIT:
+    STRLEN size_x;
+    STRLEN size_y;
+  PPCODE:
+    if (size_x != size_y)
+      croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
+    i_bezier_multi(im,size_x,x,y,val);
 
 int
-i_poly_aa(im,xc,yc,val)
+i_poly_aa(im,x,y,val)
     Imager::ImgRaw     im
-             Imager::Color  val
-            PREINIT:
-            double   *x,*y;
-            int       len;
-            AV       *av1;
-            AV       *av2;
-            SV       *sv1;
-            SV       *sv2;
-            int i;
-            CODE:
-            ICL_info(val);
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
-            if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n");
-            av1=(AV*)SvRV(ST(1));
-            av2=(AV*)SvRV(ST(2));
-            if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
-            len=av_len(av1)+1;
-            x=mymalloc( len*sizeof(double) );
-            y=mymalloc( len*sizeof(double) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av1,i,0)));
-              sv2=(*(av_fetch(av2,i,0)));
-              x[i]=(double)SvNV(sv1);
-              y[i]=(double)SvNV(sv2);
-            }
-             RETVAL = i_poly_aa(im,len,x,y,val);
-             myfree(x);
-             myfree(y);
-            OUTPUT:
-              RETVAL
+    double *x
+    double *y
+    Imager::Color  val
+  PREINIT:
+    STRLEN   size_x;
+    STRLEN   size_y;
+  CODE:
+    if (size_x != size_y)
+      croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
+    RETVAL = i_poly_aa(im, size_x, x, y, val);
+  OUTPUT:
+    RETVAL
 
 int
-i_poly_aa_cfill(im,xc,yc,fill)
+i_poly_aa_cfill(im, x, y, fill)
     Imager::ImgRaw     im
-     Imager::FillHandle     fill
-            PREINIT:
-            double   *x,*y;
-            int       len;
-            AV       *av1;
-            AV       *av2;
-            SV       *sv1;
-            SV       *sv2;
-            int i;
-            CODE:
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
-            if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n");
-            av1=(AV*)SvRV(ST(1));
-            av2=(AV*)SvRV(ST(2));
-            if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
-            len=av_len(av1)+1;
-            x=mymalloc( len*sizeof(double) );
-            y=mymalloc( len*sizeof(double) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av1,i,0)));
-              sv2=(*(av_fetch(av2,i,0)));
-              x[i]=(double)SvNV(sv1);
-              y[i]=(double)SvNV(sv2);
-            }
-             RETVAL = i_poly_aa_cfill(im,len,x,y,fill);
-             myfree(x);
-             myfree(y);
-            OUTPUT:
-              RETVAL
-
-
+    double *x
+    double *y
+    Imager::FillHandle     fill
+  PREINIT:
+    STRLEN size_x;
+    STRLEN size_y;
+  CODE:
+    if (size_x != size_y)
+      croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
+    RETVAL = i_poly_aa_cfill(im, size_x, x, y, fill);
+  OUTPUT:
+    RETVAL
 
 undef_int
 i_flood_fill(im,seedx,seedy,dcol)
@@ -1944,47 +2004,44 @@ i_rotate_exact(im, amount, ...)
        RETVAL
 
 Imager::ImgRaw
-i_matrix_transform(im, xsize, ysize, matrix, ...)
+i_matrix_transform(im, xsize, ysize, matrix_av, ...)
     Imager::ImgRaw      im
-               i_img_dim      xsize
-               i_img_dim      ysize
-      PREINIT:
-        double matrix[9];
-        AV *av;
-        IV len;
-        SV *sv1;
-        int i;
-       i_color *backp = NULL;
-       i_fcolor *fbackp = NULL;
-      CODE:
-        if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV)
-          croak("i_matrix_transform: parameter 4 must be an array ref\n");
-       av=(AV*)SvRV(ST(3));
-       len=av_len(av)+1;
-        if (len > 9)
-          len = 9;
-        for (i = 0; i < len; ++i) {
-         sv1=(*(av_fetch(av,i,0)));
-         matrix[i] = SvNV(sv1);
-        }
-        for (; i < 9; ++i)
-          matrix[i] = 0;
-       /* extract the bg colors if any */
-       /* yes, this is kind of strange */
-       for (i = 4; i < items; ++i) {
-          sv1 = ST(i);
-          if (sv_derived_from(sv1, "Imager::Color")) {
-           IV tmp = SvIV((SV*)SvRV(sv1));
-           backp = INT2PTR(i_color *, tmp);
-         }
-         else if (sv_derived_from(sv1, "Imager::Color::Float")) {
-           IV tmp = SvIV((SV*)SvRV(sv1));
-           fbackp = INT2PTR(i_fcolor *, tmp);
-         }
-       }
-        RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
-      OUTPUT:
-        RETVAL
+    i_img_dim      xsize
+    i_img_dim      ysize
+    AV *matrix_av
+  PREINIT:
+    double matrix[9];
+    STRLEN len;
+    SV *sv1;
+    int i;
+    i_color *backp = NULL;
+    i_fcolor *fbackp = NULL;
+  CODE:
+    len=av_len(matrix_av)+1;
+    if (len > 9)
+      len = 9;
+    for (i = 0; i < len; ++i) {
+      sv1=(*(av_fetch(matrix_av,i,0)));
+      matrix[i] = SvNV(sv1);
+    }
+    for (; i < 9; ++i)
+      matrix[i] = 0;
+    /* extract the bg colors if any */
+    /* yes, this is kind of strange */
+    for (i = 4; i < items; ++i) {
+      sv1 = ST(i);
+      if (sv_derived_from(sv1, "Imager::Color")) {
+        IV tmp = SvIV((SV*)SvRV(sv1));
+       backp = INT2PTR(i_color *, tmp);
+      }
+      else if (sv_derived_from(sv1, "Imager::Color::Float")) {
+        IV tmp = SvIV((SV*)SvRV(sv1));
+        fbackp = INT2PTR(i_fcolor *, tmp);
+      }
+    }
+    RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
+  OUTPUT:
+    RETVAL
 
 undef_int
 i_gaussian(im,stdev)
@@ -2067,46 +2124,44 @@ i_convert(src, avmain)
          RETVAL
 
 
-void
-i_map(im, pmaps)
+undef_int
+i_map(im, pmaps_av)
     Imager::ImgRaw     im
-       PREINIT:
-         unsigned int mask = 0;
-         AV *avmain;
-         AV *avsub;
-          SV **temp;
-         int len;
-         int i, j;
-         unsigned char (*maps)[256];
-        CODE:
-         if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-           croak("i_map: parameter 2 must be an arrayref\n");
-          avmain = (AV*)SvRV(ST(1));
-         len = av_len(avmain)+1;
-         if (im->channels < len) len = im->channels;
-
-         maps = mymalloc( len * sizeof(unsigned char [256]) );
-
-         for (j=0; j<len ; j++) {
-           temp = av_fetch(avmain, j, 0);
-           if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
-             avsub = (AV*)SvRV(*temp);
-             if(av_len(avsub) != 255) continue;
-             mask |= 1<<j;
-              for (i=0; i<256 ; i++) {
-               int val;
-               temp = av_fetch(avsub, i, 0);
-               val = temp ? SvIV(*temp) : 0;
-               if (val<0) val = 0;
-               if (val>255) val = 255;
-               maps[j][i] = val;
-             }
-            }
-          }
-          i_map(im, maps, mask);
-         myfree(maps);
-
-
+    AV *pmaps_av
+  PREINIT:
+    unsigned int mask = 0;
+    AV *avsub;
+    SV **temp;
+    int len;
+    int i, j;
+    unsigned char (*maps)[256];
+  CODE:
+    len = av_len(pmaps_av)+1;
+    if (im->channels < len)
+      len = im->channels;
+    maps = mymalloc( len * sizeof(unsigned char [256]) );
+    for (j=0; j<len ; j++) {
+      temp = av_fetch(pmaps_av, j, 0);
+      if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
+        avsub = (AV*)SvRV(*temp);
+        if(av_len(avsub) != 255)
+          continue;
+        mask |= 1<<j;
+        for (i=0; i<256 ; i++) {
+          int val;
+          temp = av_fetch(avsub, i, 0);
+          val = temp ? SvIV(*temp) : 0;
+          if (val<0) val = 0;
+          if (val>255) val = 255;
+          maps[j][i] = val;
+        }
+      }
+    }
+    i_map(im, maps, mask);
+    myfree(maps);
+    RETVAL = 1;
+  OUTPUT:
+    RETVAL
 
 float
 i_img_diff(im1,im2)
@@ -2168,7 +2223,7 @@ MODULE = Imager         PACKAGE = Imager
 
 
 undef_int
-i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
+i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1)
   Imager::Font::TT     handle
     Imager::ImgRaw     im
               i_img_dim     xb
@@ -2183,11 +2238,11 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
                char *str;
                STRLEN len;
              CODE:
+               str = SvPV(str_sv, len);
 #ifdef SvUTF8
                if (SvUTF8(str_sv))
                  utf8 = 1;
 #endif
-               str = SvPV(str_sv, len);
                RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, 
                                   len, smooth, utf8, align);
              OUTPUT:
@@ -2195,7 +2250,7 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1)
 
 
 undef_int
-i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
+i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
   Imager::Font::TT     handle
     Imager::ImgRaw     im
               i_img_dim     xb
@@ -2210,11 +2265,11 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
                char *str;
                STRLEN len;
              CODE:
+               str = SvPV(str_sv, len);
 #ifdef SvUTF8
                if (SvUTF8(str_sv))
                  utf8 = 1;
 #endif
-               str = SvPV(str_sv, len);
                RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
                                 smooth, utf8, align);
              OUTPUT:
@@ -2222,7 +2277,7 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1)
 
 
 void
-i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
+i_tt_bbox(handle,point,str_sv,utf8)
   Imager::Font::TT     handle
             double     point
               SV*    str_sv
@@ -2234,11 +2289,11 @@ i_tt_bbox(handle,point,str_sv,len_ignored, utf8)
                STRLEN len;
                int i;
             PPCODE:
+               str = SvPV(str_sv, len);
 #ifdef SvUTF8
                if (SvUTF8(ST(2)))
                  utf8 = 1;
 #endif
-               str = SvPV(str_sv, len);
               if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
                  EXTEND(SP, rc);
                  for (i = 0; i < rc; ++i) {
@@ -2258,11 +2313,12 @@ i_tt_has_chars(handle, text_sv, utf8)
         size_t count;
         size_t i;
       PPCODE:
+        i_clear_error();
+        text = SvPV(text_sv, len);
 #ifdef SvUTF8
         if (SvUTF8(text_sv))
           utf8 = 1;
 #endif
-        text = SvPV(text_sv, len);
         work = mymalloc(len);
         count = i_tt_has_chars(handle, text, len, utf8, work);
         if (GIMME_V == G_ARRAY) {
@@ -2305,12 +2361,14 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
         size_t len;
         size_t outsize;
         char name[255];
+       SSize_t count = 0;
       PPCODE:
+        i_clear_error();
+        text = SvPV(text_sv, work_len);
 #ifdef SvUTF8
         if (SvUTF8(text_sv))
           utf8 = 1;
 #endif
-        text = SvPV(text_sv, work_len);
         len = work_len;
         while (len) {
           unsigned long ch;
@@ -2318,21 +2376,23 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
             ch = i_utf8_advance(&text, &len);
             if (ch == ~0UL) {
               i_push_error(0, "invalid UTF8 character");
-              break;
+              XSRETURN_EMPTY;
             }
           }
           else {
             ch = *text++;
             --len;
           }
-          EXTEND(SP, 1);
+          EXTEND(SP, count+1);
           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
-            PUSHs(sv_2mortal(newSVpv(name, 0)));
+           ST(count) = sv_2mortal(newSVpv(name, 0));
           }
           else {
-            PUSHs(&PL_sv_undef);
-          } 
+           ST(count) = &PL_sv_undef;
+          }
+          ++count;
         }
+       XSRETURN(count);
 
 #endif 
 
@@ -2471,51 +2531,16 @@ i_get_anonymous_color_histo(im, maxc = 0x40000000)
 
 
 void
-i_transform(im,opx,opy,parm)
+i_transform(im, opx, opy, parm)
     Imager::ImgRaw     im
+    int *opx
+    int *opy
+    double *parm
              PREINIT:
-             double* parm;
-             int *opx;
-             int *opy;
-             int     opxl;
-             int     opyl;
-             int     parmlen;
-             AV* av;
-             SV* sv1;
-             int i;
+            STRLEN size_opx, size_opy, size_parm;
             i_img *result;
              PPCODE:
-             if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n");
-             if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n");
-             if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n");
-             if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n");
-             if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n");
-             if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n");
-             av=(AV*)SvRV(ST(1));
-             opxl=av_len(av)+1;
-             opx=mymalloc( opxl*sizeof(int) );
-             for(i=0;i<opxl;i++) {
-               sv1=(*(av_fetch(av,i,0)));
-               opx[i]=(int)SvIV(sv1);
-             }
-             av=(AV*)SvRV(ST(2));
-             opyl=av_len(av)+1;
-             opy=mymalloc( opyl*sizeof(int) );
-             for(i=0;i<opyl;i++) {
-               sv1=(*(av_fetch(av,i,0)));
-               opy[i]=(int)SvIV(sv1);
-             }
-             av=(AV*)SvRV(ST(3));
-             parmlen=av_len(av)+1;
-             parm=mymalloc( parmlen*sizeof(double) );
-             for(i=0;i<parmlen;i++) { /* FIXME: Bug? */
-               sv1=(*(av_fetch(av,i,0)));
-               parm[i]=(double)SvNV(sv1);
-             }
-             result=i_transform(im,opx,opxl,opy,opyl,parm,parmlen);
-             myfree(parm);
-             myfree(opy);
-             myfree(opx);
+             result=i_transform(im,opx,size_opx,opy,size_opy,parm,size_parm);
             if (result) {
               SV *result_sv = sv_newmortal();
               EXTEND(SP, 1);
@@ -2692,6 +2717,12 @@ i_autolevels(im,lsat,usat,skew)
              float     usat
              float     skew
 
+void
+i_autolevels_mono(im,lsat,usat)
+    Imager::ImgRaw     im
+             float     lsat
+             float     usat
+
 void
 i_radnoise(im,xo,yo,rscale,ascale)
     Imager::ImgRaw     im
@@ -2709,54 +2740,22 @@ i_turbnoise(im, xo, yo, scale)
 
 
 void
-i_gradgen(im, ...)
+i_gradgen(im, xo, yo, ac, dmeasure)
     Imager::ImgRaw     im
+    i_img_dim *xo
+    i_img_dim *yo
+    i_color *ac
+    int dmeasure
       PREINIT:
-       int num;
-       i_img_dim *xo;
-       i_img_dim *yo;
-        i_color *ival;
-       int dmeasure;
-       int i;
-       SV *sv;
-       AV *axx;
-       AV *ayy;
-       AV *ac;
+       STRLEN size_xo;
+       STRLEN size_yo;
+        STRLEN size_ac;
       CODE:
-       if (items != 5)
-           croak("Usage: i_gradgen(im, xo, yo, ival, dmeasure)");
-       if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
-           croak("i_gradgen: Second argument must be an array ref");
-       if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
-           croak("i_gradgen: Third argument must be an array ref");
-       if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
-           croak("i_gradgen: Fourth argument must be an array ref");
-       axx = (AV *)SvRV(ST(1));
-       ayy = (AV *)SvRV(ST(2));
-       ac  = (AV *)SvRV(ST(3));
-       dmeasure = (int)SvIV(ST(4));
-       
-        num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
-       num = num <= av_len(ac) ? num : av_len(ac);
-       num++; 
-       if (num < 2) croak("Usage: i_gradgen array refs must have more than 1 entry each");
-       xo = mymalloc( sizeof(i_img_dim) * num );
-       yo = mymalloc( sizeof(i_img_dim) * num );
-       ival = mymalloc( sizeof(i_color) * num );
-       for(i = 0; i<num; i++) {
-         xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
-         yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
-          sv = *av_fetch(ac, i, 0);
-         if ( !sv_derived_from(sv, "Imager::Color") ) {
-           free(axx); free(ayy); free(ac);
-            croak("i_gradgen: Element of fourth argument is not derived from Imager::Color");
-         }
-         ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
-       }
-        i_gradgen(im, num, xo, yo, ival, dmeasure);
-        myfree(xo);
-        myfree(yo);
-        myfree(ival);
+        if (size_xo != size_yo || size_xo != size_ac)
+         croak("i_gradgen: x, y and color arrays must be the same size");
+       if (size_xo < 2)
+          croak("Usage: i_gradgen array refs must have more than 1 entry each");
+        i_gradgen(im, size_xo, xo, yo, ac, dmeasure);
 
 Imager::ImgRaw
 i_diff_image(im, im2, mindist=0)
@@ -2954,30 +2953,20 @@ void
 DSO_call(handle,func_index,hv)
               void*  handle
               int    func_index
-            PREINIT:
-              HV* hv;
+              HV *hv
             PPCODE:
-              if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to a hash\n");        
-              hv=(HV*)SvRV(ST(2));
-              if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n");
               DSO_call( (DSO_handle *)handle,func_index,hv);
 
-SV *
+Imager::Color
 i_get_pixel(im, x, y)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y;
-      PREINIT:
-        i_color *color;
       CODE:
-       color = (i_color *)mymalloc(sizeof(i_color));
-       if (i_gpix(im, x, y, color) == 0) {
-          RETVAL = NEWSV(0, 0);
-          sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
-        }
-        else {
-          myfree(color);
-          RETVAL = &PL_sv_undef;
+       RETVAL = (i_color *)mymalloc(sizeof(i_color));
+       if (i_gpix(im, x, y, RETVAL) != 0) {
+          myfree(RETVAL);
+         XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3134,11 +3123,10 @@ i_ppal_p(im, l, y, data)
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_addcolors(im, ...)
         Imager::ImgRaw  im
       PREINIT:
-        int index;
         i_color *colors;
         int i;
       CODE:
@@ -3156,17 +3144,7 @@ i_addcolors(im, ...)
             croak("i_addcolor: pixels must be Imager::Color objects");
           }
         }
-        index = i_addcolors(im, colors, items-1);
-        myfree(colors);
-        if (index == 0) {
-          RETVAL = newSVpv("0 but true", 0);
-        }
-        else if (index == -1) {
-          RETVAL = &PL_sv_undef;
-        }
-        else {
-          RETVAL = newSViv(index);
-        }
+        RETVAL = i_addcolors(im, colors, items-1);
       OUTPUT:
         RETVAL
 
@@ -3198,29 +3176,24 @@ i_setcolors(im, index, ...)
        RETVAL
 
 void
-i_getcolors(im, index, ...)
+i_getcolors(im, index, count=1)
         Imager::ImgRaw im
         int index
+       int count
       PREINIT:
         i_color *colors;
-        int count = 1;
         int i;
       PPCODE:
-        if (items > 3)
-          croak("i_getcolors: too many arguments");
-        if (items == 3)
-          count = SvIV(ST(2));
         if (count < 1)
           croak("i_getcolors: count must be positive");
-        colors = mymalloc(sizeof(i_color) * count);
+        colors = malloc_temp(aTHX_ sizeof(i_color) * count);
         if (i_getcolors(im, index, colors, count)) {
+         EXTEND(SP, count);
           for (i = 0; i < count; ++i) {
             SV *sv = make_i_color_sv(aTHX_ colors+i);
             PUSHs(sv);
           }
         }
-        myfree(colors);
-
 
 undef_neg_int
 i_colorcount(im)
@@ -3230,18 +3203,13 @@ undef_neg_int
 i_maxcolors(im)
         Imager::ImgRaw im
 
-SV *
+i_palidx
 i_findcolor(im, color)
         Imager::ImgRaw im
         Imager::Color color
-      PREINIT:
-        i_palidx index;
       CODE:
-        if (i_findcolor(im, color, &index)) {
-          RETVAL = newSViv(index);
-        }
-        else {
-          RETVAL = &PL_sv_undef;
+        if (!i_findcolor(im, color, &RETVAL)) {
+         XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3270,7 +3238,7 @@ i_gsamp(im, l, r, y, channels)
         i_img_dim count, i;
       PPCODE:
         if (l < r) {
-          data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); /* XXX: memleak? */
+          data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
           if (GIMME_V == G_ARRAY) {
             EXTEND(SP, count);
@@ -3285,8 +3253,7 @@ i_gsamp(im, l, r, y, channels)
         }
         else {
           if (GIMME_V != G_ARRAY) {
-            EXTEND(SP, 1);
-            PUSHs(&PL_sv_undef);
+           XSRETURN_UNDEF;
           }
         }
 
@@ -3534,8 +3501,7 @@ i_gsampf(im, l, r, y, channels)
         }
         else {
           if (GIMME_V != G_ARRAY) {
-            EXTEND(SP, 1);
-            PUSHs(&PL_sv_undef);
+           XSRETURN_UNDEF;
           }
         }
 
@@ -3584,22 +3550,16 @@ i_plinf(im, l, y, ...)
       OUTPUT:
         RETVAL
 
-SV *
+Imager::Color::Float
 i_gpixf(im, x, y)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y;
-      PREINIT:
-        i_fcolor *color;
       CODE:
-       color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
-       if (i_gpixf(im, x, y, color) == 0) {
-          RETVAL = NEWSV(0,0);
-          sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
-        }
-        else {
-          myfree(color);
-          RETVAL = &PL_sv_undef;
+       RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
+       if (i_gpixf(im, x, y, RETVAL) != 0) {
+          myfree(RETVAL);
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3695,16 +3655,18 @@ i_img_to_drgb(im)
        Imager::ImgRaw im
 
 undef_int
-i_tags_addn(im, name, code, idata)
+i_tags_addn(im, name_sv, code, idata)
         Imager::ImgRaw im
+       SV *name_sv
         int     code
         int     idata
       PREINIT:
         char *name;
         STRLEN len;
       CODE:
-        if (SvOK(ST(1)))
-          name = SvPV(ST(1), len);
+        SvGETMAGIC(name_sv);
+        if (SvOK(name_sv))
+          name = SvPV_nomg(name_sv, len);
         else
           name = NULL;
         RETVAL = i_tags_addn(&im->tags, name, code, idata);
@@ -3712,21 +3674,25 @@ i_tags_addn(im, name, code, idata)
         RETVAL
 
 undef_int
-i_tags_add(im, name, code, data, idata)
+i_tags_add(im, name_sv, code, data_sv, idata)
         Imager::ImgRaw  im
+       SV *name_sv
         int code
+       SV *data_sv
         int idata
       PREINIT:
         char *name;
         char *data;
         STRLEN len;
       CODE:
-        if (SvOK(ST(1)))
-          name = SvPV(ST(1), len);
+        SvGETMAGIC(name_sv);
+        if (SvOK(name_sv))
+          name = SvPV_nomg(name_sv, len);
         else
           name = NULL;
-        if (SvOK(ST(3)))
-          data = SvPV(ST(3), len);
+       SvGETMAGIC(data_sv);
+        if (SvOK(data_sv))
+          data = SvPV(data_sv, len);
         else {
           data = NULL;
           len = 0;
@@ -3735,7 +3701,7 @@ i_tags_add(im, name, code, data, idata)
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_find(im, name, start)
         Imager::ImgRaw  im
         char *name
@@ -3744,17 +3710,14 @@ i_tags_find(im, name, start)
         int entry;
       CODE:
         if (i_tags_find(&im->tags, name, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+         RETVAL = entry;
         } else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_findn(im, code, start)
         Imager::ImgRaw  im
         int             code
@@ -3763,13 +3726,10 @@ i_tags_findn(im, code, start)
         int entry;
       CODE:
         if (i_tags_findn(&im->tags, code, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+          RETVAL = entry;
         }
         else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3883,19 +3843,21 @@ i_new_fill_solidf(cl, combine)
         int combine
 
 Imager::FillHandle
-i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color fg
         Imager::Color bg
         int combine
         int hatch
+       SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3904,19 +3866,21 @@ i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color::Float fg
         Imager::Color::Float bg
         int combine
         int hatch
+        SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3925,8 +3889,9 @@ i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_image(src, matrix, xoff, yoff, combine)
+i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
         Imager::ImgRaw src
+       SV *matrix_sv
         i_img_dim xoff
         i_img_dim yoff
         int combine
@@ -3938,13 +3903,14 @@ i_new_fill_image(src, matrix, xoff, yoff, combine)
         SV *sv1;
         int i;
       CODE:
-        if (!SvOK(ST(1))) {
+        SvGETMAGIC(matrix_sv);
+        if (!SvOK(matrix_sv)) {
           matrixp = NULL;
         }
         else {
-          if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-            croak("i_new_fill_image: parameter must be an arrayref");
-         av=(AV*)SvRV(ST(1));
+          if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
+            croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
+         av=(AV*)SvRV(matrix_sv);
          len=av_len(av)+1;
           if (len > 9)
             len = 9;
@@ -4000,8 +3966,37 @@ i_int_hlines_CLONE_SKIP(cls)
 
 #endif
 
+MODULE = Imager  PACKAGE = Imager::Context PREFIX=im_context_
+
+void
+im_context_DESTROY(ctx)
+   Imager::Context ctx
+
+#ifdef PERL_IMPLICIT_CONTEXT
+
+void
+im_context_CLONE(...)
+    CODE:
+      MY_CXT_CLONE;
+      (void)items;
+      /* the following sv_setref_pv() will free this inc */
+      im_context_refinc(MY_CXT.ctx, "CLONE");
+      MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
+      sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
+
+#endif
+
 BOOT:
         PERL_SET_GLOBAL_CALLBACKS;
        PERL_PL_SET_GLOBAL_CALLBACKS;
-       work_context = im_context_new();
+#ifdef PERL_IMPLICIT_CONTEXT
+       {
+          MY_CXT_INIT;
+         (void)MY_CXT;
+       }
+#endif
+       start_context(aTHX);
        im_get_context = perl_get_context;
+#ifdef HAVE_LIBTT
+        i_tt_start();
+#endif