]> git.imager.perl.org - imager.git/blobdiff - draw.c
nearest_color filter: was leaking malloc()ed buffers
[imager.git] / draw.c
diff --git a/draw.c b/draw.c
index 1c04efbf9be2861ef18011470ea3dfa031e3d17d..e66af53123393445e24c62771f46ff13a44891b3 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -1,9 +1,12 @@
+#define IMAGER_NO_CONTEXT
 #include "imager.h"
 #include "draw.h"
 #include "log.h"
 #include "imageri.h"
 #include "imrender.h"
 #include <limits.h>
 #include "imager.h"
 #include "draw.h"
 #include "log.h"
 #include "imageri.h"
 #include "imrender.h"
 #include <limits.h>
+#define NDEBUG
+#include <assert.h>
 
 int
 i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
 
 int
 i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
@@ -29,6 +32,7 @@ i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
     work = *col;
     i_adapt_colors(2, 4, &work, 1);
     i_gpix(im, x, y, &src);
     work = *col;
     i_adapt_colors(2, 4, &work, 1);
     i_gpix(im, x, y, &src);
+    remains = 255 - work.channel[1];
     dest_alpha = work.channel[1] + remains * src.channel[1] / 255;
     if (work.channel[1] == 255) {
       return i_ppix(im, x, y, &work);
     dest_alpha = work.channel[1] + remains * src.channel[1] / 255;
     if (work.channel[1] == 255) {
       return i_ppix(im, x, y, &work);
@@ -55,6 +59,7 @@ i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
   case 4:
     work = *col;
     i_gpix(im, x, y, &src);
   case 4:
     work = *col;
     i_gpix(im, x, y, &src);
+    remains = 255 - work.channel[3];
     dest_alpha = work.channel[3] + remains * src.channel[3] / 255;
     if (work.channel[3] == 255) {
       return i_ppix(im, x, y, &work);
     dest_alpha = work.channel[3] + remains * src.channel[3] / 255;
     if (work.channel[3] == 255) {
       return i_ppix(im, x, y, &work);
@@ -75,12 +80,12 @@ i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
 
 static void
 cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, 
 
 static void
 cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, 
-              int bxmin, int bxmax, int bymin, int bymax);
+              i_img_dim bxmin, i_img_dim bxmax, i_img_dim bymin, i_img_dim bymax);
 
 void
 
 void
-i_mmarray_cr(i_mmarray *ar,int l) {
-  int i;
-  int alloc_size;
+i_mmarray_cr(i_mmarray *ar,i_img_dim l) {
+  i_img_dim i;
+  size_t alloc_size;
 
   ar->lines=l;
   alloc_size = sizeof(minmax) * l;
 
   ar->lines=l;
   alloc_size = sizeof(minmax) * l;
@@ -90,7 +95,10 @@ i_mmarray_cr(i_mmarray *ar,int l) {
     exit(3);
   }
   ar->data=mymalloc(alloc_size); /* checked 5jul05 tonyc */
     exit(3);
   }
   ar->data=mymalloc(alloc_size); /* checked 5jul05 tonyc */
-  for(i=0;i<l;i++) { ar->data[i].max=-1; ar->data[i].min=MAXINT; }
+  for(i=0;i<l;i++) {
+    ar->data[i].max = -1;
+    ar->data[i].min = i_img_dim_MAX;
+  }
 }
 
 void
 }
 
 void
@@ -100,7 +108,7 @@ i_mmarray_dst(i_mmarray *ar) {
 }
 
 void
 }
 
 void
-i_mmarray_add(i_mmarray *ar,int x,int y) {
+i_mmarray_add(i_mmarray *ar,i_img_dim x,i_img_dim y) {
   if (y>-1 && y<ar->lines)
     {
       if (x<ar->data[y].min) ar->data[y].min=x;
   if (y>-1 && y<ar->lines)
     {
       if (x<ar->data[y].min) ar->data[y].min=x;
@@ -108,30 +116,35 @@ i_mmarray_add(i_mmarray *ar,int x,int y) {
     }
 }
 
     }
 }
 
-int
-i_mmarray_gmin(i_mmarray *ar,int y) {
+i_img_dim
+i_mmarray_gmin(i_mmarray *ar,i_img_dim y) {
   if (y>-1 && y<ar->lines) return ar->data[y].min;
   else return -1;
 }
 
   if (y>-1 && y<ar->lines) return ar->data[y].min;
   else return -1;
 }
 
-int
-i_mmarray_getm(i_mmarray *ar,int y) {
-  if (y>-1 && y<ar->lines) return ar->data[y].max;
-  else return MAXINT;
+i_img_dim
+i_mmarray_getm(i_mmarray *ar,i_img_dim y) {
+  if (y>-1 && y<ar->lines)
+    return ar->data[y].max;
+  else
+    return i_img_dim_MAX;
 }
 
 }
 
+#if 0
+/* unused? */
 void
 i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) {
 void
 i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) {
-  int i,x;
+  i_img_dim i,x;
   for(i=0;i<ar->lines;i++) if (ar->data[i].max!=-1) for(x=ar->data[i].min;x<ar->data[i].max;x++) i_ppix(im,x,i,val);
 }
   for(i=0;i<ar->lines;i++) if (ar->data[i].max!=-1) for(x=ar->data[i].min;x<ar->data[i].max;x++) i_ppix(im,x,i,val);
 }
+#endif
 
 static
 void
 
 static
 void
-i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
+i_arcdraw(i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_mmarray *ar) {
   double alpha;
   double dsec;
   double alpha;
   double dsec;
-  int temp;
+  i_img_dim temp;
   alpha=(double)(y2-y1)/(double)(x2-x1);
   if (fabs(alpha) <= 1) 
     {
   alpha=(double)(y2-y1)/(double)(x2-x1);
   if (fabs(alpha) <= 1) 
     {
@@ -139,7 +152,7 @@ i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
       dsec=y1;
       while(x1<=x2)
        {
       dsec=y1;
       while(x1<=x2)
        {
-         i_mmarray_add(ar,x1,(int)(dsec+0.5));
+         i_mmarray_add(ar,x1,(i_img_dim)(dsec+0.5));
          dsec+=alpha;
          x1++;
        }
          dsec+=alpha;
          x1++;
        }
@@ -151,7 +164,7 @@ i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
       dsec=x1;
       while(y1<=y2)
        {
       dsec=x1;
       while(y1<=y2)
        {
-         i_mmarray_add(ar,(int)(dsec+0.5),y1);
+         i_mmarray_add(ar,(i_img_dim)(dsec+0.5),y1);
          dsec+=alpha;
          y1++;
        }
          dsec+=alpha;
          y1++;
        }
@@ -160,32 +173,32 @@ i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
 
 void
 i_mmarray_info(i_mmarray *ar) {
 
 void
 i_mmarray_info(i_mmarray *ar) {
-  int i;
+  i_img_dim i;
   for(i=0;i<ar->lines;i++)
   for(i=0;i<ar->lines;i++)
-  if (ar->data[i].max!=-1) printf("line %d: min=%d, max=%d.\n",i,ar->data[i].min,ar->data[i].max);
+  if (ar->data[i].max!=-1)
+    printf("line %"i_DF ": min=%" i_DF ", max=%" i_DF ".\n",
+          i_DFc(i), i_DFc(ar->data[i].min), i_DFc(ar->data[i].max));
 }
 
 static void
 }
 
 static void
-i_arc_minmax(i_int_hlines *hlines,int x,int y,float rad,float d1,float d2) {
+i_arc_minmax(i_int_hlines *hlines,i_img_dim x,i_img_dim y, double rad,float d1,float d2) {
   i_mmarray dot;
   i_mmarray dot;
-  float f,fx,fy;
-  int x1,y1;
-
-  /*mm_log((1,"i_arc(im* 0x%x,x %d,y %d,rad %.2f,d1 %.2f,d2 %.2f,val 0x%x)\n",im,x,y,rad,d1,d2,val));*/
+  double f;
+  i_img_dim x1,y1;
 
   i_mmarray_cr(&dot, hlines->limit_y);
 
 
   i_mmarray_cr(&dot, hlines->limit_y);
 
-  x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
-  y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
-  fx=(float)x1; fy=(float)y1;
+  x1=(i_img_dim)(x+0.5+rad*cos(d1*PI/180.0));
+  y1=(i_img_dim)(y+0.5+rad*sin(d1*PI/180.0));
 
   /*  printf("x1: %d.\ny1: %d.\n",x1,y1); */
   i_arcdraw(x, y, x1, y1, &dot);
 
 
   /*  printf("x1: %d.\ny1: %d.\n",x1,y1); */
   i_arcdraw(x, y, x1, y1, &dot);
 
-  x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
-  y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
+  x1=(i_img_dim)(x+0.5+rad*cos(d2*PI/180.0));
+  y1=(i_img_dim)(y+0.5+rad*sin(d2*PI/180.0));
 
 
-  for(f=d1;f<=d2;f+=0.01) i_mmarray_add(&dot,(int)(x+0.5+rad*cos(f*PI/180.0)),(int)(y+0.5+rad*sin(f*PI/180.0)));
+  for(f=d1;f<=d2;f+=0.01)
+    i_mmarray_add(&dot,(i_img_dim)(x+0.5+rad*cos(f*PI/180.0)),(i_img_dim)(y+0.5+rad*sin(f*PI/180.0)));
   
   /*  printf("x1: %d.\ny1: %d.\n",x1,y1); */
   i_arcdraw(x, y, x1, y1, &dot);
   
   /*  printf("x1: %d.\ny1: %d.\n",x1,y1); */
   i_arcdraw(x, y, x1, y1, &dot);
@@ -193,7 +206,7 @@ i_arc_minmax(i_int_hlines *hlines,int x,int y,float rad,float d1,float d2) {
   /* render the minmax values onto the hlines */
   for (y = 0; y < dot.lines; y++) {
     if (dot.data[y].max!=-1) {
   /* render the minmax values onto the hlines */
   for (y = 0; y < dot.lines; y++) {
     if (dot.data[y].max!=-1) {
-      int minx, width;
+      i_img_dim minx, width;
       minx = dot.data[y].min;
       width = dot.data[y].max - dot.data[y].min + 1;
       i_int_hlines_add(hlines, y, minx, width);
       minx = dot.data[y].min;
       width = dot.data[y].max - dot.data[y].min + 1;
       i_int_hlines_add(hlines, y, minx, width);
@@ -205,7 +218,7 @@ i_arc_minmax(i_int_hlines *hlines,int x,int y,float rad,float d1,float d2) {
 }
 
 static void
 }
 
 static void
-i_arc_hlines(i_int_hlines *hlines,int x,int y,float rad,float d1,float d2) {
+i_arc_hlines(i_int_hlines *hlines,i_img_dim x,i_img_dim y,double rad,float d1,float d2) {
   if (d1 <= d2) {
     i_arc_minmax(hlines, x, y, rad, d1, d2);
   }
   if (d1 <= d2) {
     i_arc_minmax(hlines, x, y, rad, d1, d2);
   }
@@ -228,8 +241,12 @@ of angles in degrees from d1 to d2, with the color.
 */
 
 void
 */
 
 void
-i_arc(i_img *im,int x,int y,float rad,float d1,float d2,const i_color *val) {
+i_arc(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,const i_color *val) {
   i_int_hlines hlines;
   i_int_hlines hlines;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, col %p)",
+         im, i_DFcp(x, y), rad, d1, d2, val));
 
   i_int_init_hlines_img(&hlines, im);
 
 
   i_int_init_hlines_img(&hlines, im);
 
@@ -256,8 +273,12 @@ of angles in degrees from d1 to d2, with the fill object.
 #define MAX_CIRCLE_STEPS 360
 
 void
 #define MAX_CIRCLE_STEPS 360
 
 void
-i_arc_cfill(i_img *im,int x,int y,float rad,float d1,float d2,i_fill_t *fill) {
+i_arc_cfill(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,i_fill_t *fill) {
   i_int_hlines hlines;
   i_int_hlines hlines;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc_cfill(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, fill %p)",
+         im, i_DFcp(x, y), rad, d1, d2, fill));
 
   i_int_init_hlines_img(&hlines, im);
 
 
   i_int_init_hlines_img(&hlines, im);
 
@@ -273,7 +294,7 @@ arc_poly(int *count, double **xvals, double **yvals,
         double x, double y, double rad, double d1, double d2) {
   double d1_rad, d2_rad;
   double circum;
         double x, double y, double rad, double d1, double d2) {
   double d1_rad, d2_rad;
   double circum;
-  int steps, point_count;
+  i_img_dim steps, point_count;
   double angle_inc;
 
   /* normalize the angles */
   double angle_inc;
 
   /* normalize the angles */
@@ -357,6 +378,10 @@ i_arc_aa(i_img *im, double x, double y, double rad, double d1, double d2,
         const i_color *val) {
   double *xvals, *yvals;
   int count;
         const i_color *val) {
   double *xvals, *yvals;
   int count;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc_aa(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, col %p)",
+         im, x, y, rad, d1, d2, val));
 
   arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
 
 
   arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
 
@@ -383,6 +408,10 @@ i_arc_aa_cfill(i_img *im, double x, double y, double rad, double d1, double d2,
               i_fill_t *fill) {
   double *xvals, *yvals;
   int count;
               i_fill_t *fill) {
   double *xvals, *yvals;
   int count;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc_aa_cfill(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, fill %p)",
+         im, x, y, rad, d1, d2, fill));
 
   arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
 
 
   arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
 
@@ -392,140 +421,212 @@ i_arc_aa_cfill(i_img *im, double x, double y, double rad, double d1, double d2,
   myfree(yvals);
 }
 
   myfree(yvals);
 }
 
-/* Temporary AA HACK */
+typedef i_img_dim frac;
+static  frac float_to_frac(double x) { return (frac)(0.5+x*16.0); }
 
 
+typedef void
+(*flush_render_t)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *cover, void *ctx);
 
 
-typedef int frac;
-static  frac float_to_frac(float x) { return (frac)(0.5+x*16.0); }
+static void
+i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r, void *ctx);
 
 
-static 
-void
-polar_to_plane(float cx, float cy, float angle, float radius, frac *x, frac *y) {
-  *x = float_to_frac(cx+radius*cos(angle));
-  *y = float_to_frac(cy+radius*sin(angle));
-}
+static void
+scanline_flush_color(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx);
 
 
-static
-void
-make_minmax_list(i_mmarray *dot, float x, float y, float radius) {
-  float angle = 0.0;
-  float astep = radius>0.1 ? .5/radius : 10;
-  frac cx, cy, lx, ly, sx, sy;
+static void
+scanline_flush_fill(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx);
 
 
-  mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
+typedef struct {
+  i_render r;
+  i_color c;
+} flush_color_t;
 
 
-  polar_to_plane(x, y, angle, radius, &sx, &sy);
-  
-  for(angle = 0.0; angle<361; angle +=astep) {
-    lx = sx; ly = sy;
-    polar_to_plane(x, y, angle, radius, &cx, &cy);
-    sx = cx; sy = cy;
-
-    if (fabs(cx-lx) > fabs(cy-ly)) {
-      int ccx, ccy;
-      if (lx>cx) { 
-       ccx = lx; lx = cx; cx = ccx; 
-       ccy = ly; ly = cy; cy = ccy; 
-      }
+typedef struct {
+  i_render r;
+  i_fill_t *fill;
+} flush_fill_t;
 
 
-      for(ccx=lx; ccx<=cx; ccx++) {
-       ccy = ly + ((cy-ly)*(ccx-lx))/(cx-lx);
-       i_mmarray_add(dot, ccx, ccy);
-      }
-    } else {
-      int ccx, ccy;
+/*
+=item i_circle_aa(im, x, y, rad, color)
 
 
-      if (ly>cy) { 
-       ccy = ly; ly = cy; cy = ccy; 
-       ccx = lx; lx = cx; cx = ccx; 
-      }
-      
-      for(ccy=ly; ccy<=cy; ccy++) {
-       if (cy-ly) ccx = lx + ((cx-lx)*(ccy-ly))/(cy-ly); else ccx = lx;
-       i_mmarray_add(dot, ccx, ccy);
-      }
-    }
-  }
-}
+=category Drawing
+=synopsis i_circle_aa(im, 50, 50, 45, &color);
 
 
-/* Get the number of subpixels covered */
+Anti-alias fills a circle centered at (x,y) for radius I<rad> with
+color.
 
 
-static
-int
-i_pixel_coverage(i_mmarray *dot, int x, int y) {
-  frac minx = x*16;
-  frac maxx = minx+15;
-  frac cy;
-  int cnt = 0;
-  
-  for(cy=y*16; cy<(y+1)*16; cy++) {
-    frac tmin = dot->data[cy].min;
-    frac tmax = dot->data[cy].max;
+=cut
+*/
 
 
-    if (tmax == -1 || tmin > maxx || tmax < minx) continue;
-    
-    if (tmin < minx) tmin = minx;
-    if (tmax > maxx) tmax = maxx;
-    
-    cnt+=1+tmax-tmin;
-  }
-  return cnt;
+void
+i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) {
+  flush_color_t fc;
+
+  fc.c = *val;
+  i_render_init(&fc.r, im, rad * 2 + 1);
+
+  i_circle_aa_low(im, x, y, rad, scanline_flush_color, &fc);
+
+  i_render_done(&fc.r);
 }
 
 /*
 }
 
 /*
-=item i_circle_aa(im, x, y, rad, color)
+=item i_circle_aa_fill(im, x, y, rad, fill)
 
 =category Drawing
 
 =category Drawing
-=synopsis i_circle_aa(im, 50, 50, 45, &color);
+=synopsis i_circle_aa_fill(im, 50, 50, 45, fill);
 
 Anti-alias fills a circle centered at (x,y) for radius I<rad> with
 
 Anti-alias fills a circle centered at (x,y) for radius I<rad> with
-color.
+fill.
 
 =cut
 */
 
 =cut
 */
+
 void
 void
-i_circle_aa(i_img *im, float x, float y, float rad, const i_color *val) {
-  i_mmarray dot;
-  i_color temp;
-  int ly;
+i_circle_aa_fill(i_img *im, double x, double y, double rad, i_fill_t *fill) {
+  flush_fill_t ff;
 
 
-  mm_log((1, "i_circle_aa(im %p, x %d, y %d, rad %.2f, val %p)\n", im, x, y, rad, val));
+  ff.fill = fill;
+  i_render_init(&ff.r, im, rad * 2 + 1);
 
 
-  i_mmarray_cr(&dot,16*im->ysize);
-  make_minmax_list(&dot, x, y, rad);
+  i_circle_aa_low(im, x, y, rad, scanline_flush_fill, &ff);
 
 
-  for(ly = 0; ly<im->ysize; ly++) {
-    int ix, cy, minx = INT_MAX, maxx = INT_MIN;
+  i_render_done(&ff.r);
+}
 
 
-    /* Find the left/rightmost set subpixels */
-    for(cy = 0; cy<16; cy++) {
-      frac tmin = dot.data[ly*16+cy].min;
-      frac tmax = dot.data[ly*16+cy].max;
-      if (tmax == -1) continue;
+static void
+i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
+               void *ctx) {
+  i_color temp;
+  i_img_dim ly;
+  dIMCTXim(im);
+  i_img_dim first_row = floor(y) - ceil(rad);
+  i_img_dim last_row = ceil(y) + ceil(rad);
+  double r_sqr = rad * rad;
+  i_img_dim max_width = 2 * ceil(rad) + 1;
+  unsigned char *coverage = NULL;
+  size_t coverage_size;
+  int sub;
+
+  im_log((aIMCTX, 1, "i_circle_aa_low(im %p, centre(" i_DFp "), rad %.2f, r %p, ctx %p)\n",
+         im, i_DFcp(x, y), rad, r, ctx));
+
+  if (first_row < 0)
+    first_row = 0;
+  if (last_row > im->ysize-1)
+    last_row = im->ysize - 1;
+
+  if (rad <= 0 || last_row < first_row) {
+    /* outside the image */
+    return;
+  }
 
 
-      if (minx > tmin) minx = tmin;
-      if (maxx < tmax) maxx = tmax;
+  coverage_size = max_width;
+  coverage = mymalloc(coverage_size);
+
+  for(ly = first_row; ly < last_row; ly++) {
+    frac min_frac_x[16];
+    frac max_frac_x[16];
+    i_img_dim min_frac_left_x = im->xsize * 16;
+    i_img_dim max_frac_left_x = -1;
+    i_img_dim min_frac_right_x = im->xsize * 16;
+    i_img_dim max_frac_right_x = -1;
+    /* reset work_y each row so the error doesn't build up */
+    double work_y = ly;
+    double dy, dy_sqr;
+      
+    for (sub = 0; sub < 16; ++sub) {
+      work_y += 1.0 / 16.0;
+      dy = work_y - y;
+      dy_sqr = dy * dy;
+
+      if (dy_sqr < r_sqr) {
+       double dx = sqrt(r_sqr - dy_sqr);
+       double left_x = x - dx;
+       double right_x = x + dx;
+       frac frac_left_x = float_to_frac(left_x);
+       frac frac_right_x = float_to_frac(right_x);
+
+       if (frac_left_x < min_frac_left_x)
+         min_frac_left_x = frac_left_x;
+       if (frac_left_x > max_frac_left_x)
+         max_frac_left_x = frac_left_x;
+       if (frac_right_x < min_frac_right_x)
+         min_frac_right_x = frac_right_x;
+       if (frac_right_x > max_frac_right_x)
+         max_frac_right_x = frac_right_x;
+       min_frac_x[sub] = frac_left_x;
+       max_frac_x[sub] = frac_right_x;
+      }
+      else {
+       min_frac_x[sub] = max_frac_x[sub] = 0;
+       max_frac_left_x = im->xsize * 16;
+       min_frac_right_x = -1;
+      }
     }
 
     }
 
-    if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */
-
-    minx /= 16;
-    maxx /= 16;
-    for(ix=minx; ix<=maxx; ix++) {
-      int cnt = i_pixel_coverage(&dot, ix, ly);
-      if (cnt>255) cnt = 255;
-      if (cnt) { /* should never be true */
-       int ch;
-       float ratio = (float)cnt/255.0;
-       i_gpix(im, ix, ly, &temp);
-       for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
-       i_ppix(im, ix, ly, &temp);
+    if (min_frac_left_x != -1) {
+      /* something to draw on this line */
+      i_img_dim min_x = (min_frac_left_x / 16);
+      i_img_dim max_x = (max_frac_right_x + 15) / 16;
+      i_img_dim left_solid = (max_frac_left_x + 15) / 16;
+      i_img_dim right_solid = min_frac_right_x / 16;
+      i_img_dim work_x;
+      i_img_dim frac_work_x;
+      i_sample_t *cout = coverage;
+
+      for (work_x = min_x, frac_work_x = min_x * 16;
+          work_x <= max_x;
+          ++work_x, frac_work_x += 16) {
+       if (work_x <= left_solid || work_x >= right_solid) {
+         int pix_coverage = 0;
+         int ch;
+         double ratio;
+         i_img_dim frac_work_right = frac_work_x + 16;
+         for (sub = 0; sub < 16; ++sub) {
+           frac pix_left = min_frac_x[sub];
+           frac pix_right = max_frac_x[sub];
+           if (pix_left < pix_right
+               && pix_left < frac_work_right
+               && pix_right >= frac_work_x) {
+             if (pix_left < frac_work_x)
+               pix_left = frac_work_x;
+             if (pix_right > frac_work_right)
+               pix_right = frac_work_right;
+             pix_coverage += pix_right - pix_left;
+           }
+         }
+
+         assert(pix_coverage <= 256);
+         *cout++ = pix_coverage * 255 / 256;
+       }
+       else {
+         /* full coverage */
+         *cout++ = 255;
+       }
       }
       }
+      r(im, min_x, ly, max_x - min_x + 1, coverage, ctx);
     }
   }
     }
   }
-  i_mmarray_dst(&dot);
+
+  myfree(coverage);
+}
+
+static void
+scanline_flush_color(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) {
+  flush_color_t *fc = ctx;
+
+  i_render_color(&fc->r, x, y, width, cover, &fc->c);
+}
+
+static void
+scanline_flush_fill(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) {
+  flush_fill_t *ff = ctx;
+
+  i_render_fill(&ff->r, x, y, width, cover, ff->fill);
 }
 
 }
 
+
 /*
 =item i_circle_out(im, x, y, r, col)
 
 /*
 =item i_circle_out(im, x, y, r, col)
 
@@ -562,11 +663,15 @@ i_circle_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
   i_img_dim x, y;
   i_img_dim dx, dy;
   int error;
   i_img_dim x, y;
   i_img_dim dx, dy;
   int error;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1, "i_circle_out(im %p, centre(" i_DFp "), rad %" i_DF ", col %p)\n",
+         im, i_DFcp(xc, yc), i_DFc(r), col));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
 
   if (r < 0) {
 
   if (r < 0) {
-    i_push_error(0, "circle: radius must be non-negative");
+    im_push_error(aIMCTX, 0, "circle: radius must be non-negative");
     return 0;
   }
 
     return 0;
   }
 
@@ -611,14 +716,13 @@ i_circle_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
 Convert an angle in degrees into an angle measure we can generate
 simply from the numbers we have when drawing the circle.
 
 Convert an angle in degrees into an angle measure we can generate
 simply from the numbers we have when drawing the circle.
 
-=back
+=cut
 */
 
 static i_img_dim
 arc_seg(double angle, int scale) {
   i_img_dim seg = (angle + 45) / 90;
   double remains = angle - seg * 90; /* should be in the range [-45,45] */
 */
 
 static i_img_dim
 arc_seg(double angle, int scale) {
   i_img_dim seg = (angle + 45) / 90;
   double remains = angle - seg * 90; /* should be in the range [-45,45] */
-  int sign = remains < 0 ? -1 : remains ? 1 : 0;
 
   while (seg > 4)
     seg -= 4;
 
   while (seg > 4)
     seg -= 4;
@@ -664,7 +768,7 @@ Implementation:
 
 int
 i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
 
 int
 i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
-         float d1, float d2, const i_color *col) {
+         double d1, double d2, const i_color *col) {
   i_img_dim x, y;
   i_img_dim dx, dy;
   int error;
   i_img_dim x, y;
   i_img_dim dx, dy;
   int error;
@@ -673,17 +777,20 @@ i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
   i_img_dim sin_th;
   i_img_dim seg_d1, seg_d2;
   int seg_num;
   i_img_dim sin_th;
   i_img_dim seg_d1, seg_d2;
   int seg_num;
-  double inv_r;
   i_img_dim scale = r + 1;
   i_img_dim seg1 = scale * 2;
   i_img_dim seg2 = scale * 4;
   i_img_dim seg3 = scale * 6;
   i_img_dim seg4 = scale * 8;
   i_img_dim scale = r + 1;
   i_img_dim seg1 = scale * 2;
   i_img_dim seg2 = scale * 4;
   i_img_dim seg3 = scale * 6;
   i_img_dim seg4 = scale * 8;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc_out(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)",
+         im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
 
   if (r <= 0) {
 
   if (r <= 0) {
-    i_push_error(0, "arc: radius must be non-negative");
+    im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
     return 0;
   }
   if (d1 + 360 <= d2)
     return 0;
   }
   if (d1 + 360 <= d2)
@@ -766,7 +873,7 @@ i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
 
 static double
 cover(i_img_dim r, i_img_dim j) {
 
 static double
 cover(i_img_dim r, i_img_dim j) {
-  float rjsqrt = sqrt(r*r - j*j);
+  double rjsqrt = sqrt(r*r - j*j);
 
   return ceil(rjsqrt) - rjsqrt;
 }
 
   return ceil(rjsqrt) - rjsqrt;
 }
@@ -815,10 +922,14 @@ i_circle_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_colo
   double t;
   i_color workc = *col;
   int orig_alpha = col->channel[3];
   double t;
   i_color workc = *col;
   int orig_alpha = col->channel[3];
+  dIMCTXim(im);
 
 
-  i_clear_error();
+  im_log((aIMCTX,1,"i_circle_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", col %p)",
+         im, i_DFcp(xc, yc), i_DFc(r), col));
+
+  im_clear_error(aIMCTX);
   if (r <= 0) {
   if (r <= 0) {
-    i_push_error(0, "arc: radius must be non-negative");
+    im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
     return 0;
   }
   i = r;
     return 0;
   }
   i = r;
@@ -832,8 +943,6 @@ i_circle_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_colo
   while (i > j+1) {
     double d;
     int cv, inv_cv;
   while (i > j+1) {
     double d;
     int cv, inv_cv;
-    i_color p;
-    int ch;
     j++;
     d = cover(r, j);
     cv = (int)(d * 255 + 0.5);
     j++;
     d = cover(r, j);
     cv = (int)(d * 255 + 0.5);
@@ -912,7 +1021,7 @@ Gems.
 */
 
 int
 */
 
 int
-i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, float d1, float d2, const i_color *col) {
+i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, double d1, double d2, const i_color *col) {
   i_img_dim i, j;
   double t;
   i_color workc = *col;
   i_img_dim i, j;
   double t;
   i_color workc = *col;
@@ -927,10 +1036,14 @@ i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, float d1, float
   i_img_dim seg2 = scale * 4;
   i_img_dim seg3 = scale * 6;
   i_img_dim seg4 = scale * 8;
   i_img_dim seg2 = scale * 4;
   i_img_dim seg3 = scale * 6;
   i_img_dim seg4 = scale * 8;
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_arc_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)",
+         im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
   if (r <= 0) {
   if (r <= 0) {
-    i_push_error(0, "arc: radius must be non-negative");
+    im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
     return 0;
   }
   if (d1 + 360 <= d2)
     return 0;
   }
   if (d1 + 360 <= d2)
@@ -977,8 +1090,6 @@ i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, float d1, float
     
     while (i > j+1) {
       int cv, inv_cv;
     
     while (i > j+1) {
       int cv, inv_cv;
-      i_color p;
-      int ch;
       double d;
       j++;
       d = cover(r, j);
       double d;
       j++;
       d = cover(r, j);
@@ -1050,9 +1161,12 @@ Outlines the box from (x1,y1) to (x2,y2) inclusive with I<color>.
 */
 
 void
 */
 
 void
-i_box(i_img *im,int x1,int y1,int x2,int y2,const i_color *val) {
-  int x,y;
-  mm_log((1,"i_box(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
+i_box(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val) {
+  i_img_dim x,y;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1,"i_box(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+         im, i_DFcp(x1,y1), i_DFcp(x2,y2), val));
   for(x=x1;x<x2+1;x++) {
     i_ppix(im,x,y1,val);
     i_ppix(im,x,y2,val);
   for(x=x1;x<x2+1;x++) {
     i_ppix(im,x,y1,val);
     i_ppix(im,x,y2,val);
@@ -1075,11 +1189,13 @@ Fills the box from (x1,y1) to (x2,y2) inclusive with color.
 */
 
 void
 */
 
 void
-i_box_filled(i_img *im,int x1,int y1,int x2,int y2, const i_color *val) {
+i_box_filled(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_color *val) {
   i_img_dim x, y, width;
   i_palidx index;
   i_img_dim x, y, width;
   i_palidx index;
+  dIMCTXim(im);
 
 
-  mm_log((1,"i_box_filled(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
+  im_log((aIMCTX,1,"i_box_filled(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+         im, i_DFcp(x1, y1), i_DFcp(x2,y2) ,val));
 
   if (x1 > x2 || y1 > y2
       || x2 < 0 || y2 < 0
 
   if (x1 > x2 || y1 > y2
       || x2 < 0 || y2 < 0
@@ -1122,6 +1238,66 @@ i_box_filled(i_img *im,int x1,int y1,int x2,int y2, const i_color *val) {
   }
 }
 
   }
 }
 
+/*
+=item i_box_filledf(im, x1, y1, x2, y2, color)
+
+=category Drawing
+=synopsis i_box_filledf(im, 0, 0, im->xsize-1, im->ysize-1, &fcolor);
+
+Fills the box from (x1,y1) to (x2,y2) inclusive with a floating point
+color.
+
+=cut
+*/
+
+int
+i_box_filledf(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_fcolor *val) {
+  i_img_dim x, y, width;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1,"i_box_filledf(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+         im, i_DFcp(x1, y1), i_DFcp(x2, y2), val));
+
+  if (x1 > x2 || y1 > y2
+      || x2 < 0 || y2 < 0
+      || x1 >= im->xsize || y1 > im->ysize)
+    return 0;
+
+  if (x1 < 0)
+    x1 = 0;
+  if (x2 >= im->xsize)
+    x2 = im->xsize - 1;
+  if (y1 < 0)
+    y1 = 0;
+  if (y2 >= im->ysize)
+    y2 = im->ysize - 1;
+
+  width = x2 - x1 + 1;
+
+  if (im->bits <= 8) {
+    i_color c;
+    c.rgba.r = SampleFTo8(val->rgba.r);
+    c.rgba.g = SampleFTo8(val->rgba.g);
+    c.rgba.b = SampleFTo8(val->rgba.b);
+    c.rgba.a = SampleFTo8(val->rgba.a);
+
+    i_box_filled(im, x1, y1, x2, y2, &c);
+  }
+  else {
+    i_fcolor *line = mymalloc(sizeof(i_fcolor) * width);
+    
+    for (x = 0; x < width; ++x)
+      line[x] = *val;
+    
+    for (y = y1; y <= y2; ++y)
+      i_plinf(im, x1, x2+1, y, line);
+    
+    myfree(line);
+  }
+  
+  return 1;
+}
+
 /*
 =item i_box_cfill(im, x1, y1, x2, y2, fill)
 
 /*
 =item i_box_cfill(im, x1, y1, x2, y2, fill)
 
@@ -1134,9 +1310,12 @@ Fills the box from (x1,y1) to (x2,y2) inclusive with fill.
 */
 
 void
 */
 
 void
-i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) {
+i_box_cfill(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_fill_t *fill) {
   i_render r;
   i_render r;
-  mm_log((1,"i_box_cfill(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,fill 0x%x)\n",im,x1,y1,x2,y2,fill));
+  dIMCTXim(im);
+
+  im_log((aIMCTX,1,"i_box_cfill(im* %p, p1(" i_DFp "), p2(" i_DFp "), fill %p)\n",
+         im, i_DFcp(x1, y1), i_DFcp(x2,y2), fill));
 
   ++x2;
   if (x1 < 0)
 
   ++x2;
   if (x1 < 0)
@@ -1179,27 +1358,27 @@ Draw a line to image using Bresenham's line drawing algorithm
 */
 
 void
 */
 
 void
-i_line(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int endp) {
-  int x, y;
-  int dx, dy;
-  int p;
+i_line(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp) {
+  i_img_dim x, y;
+  i_img_dim dx, dy;
+  i_img_dim p;
 
   dx = x2 - x1;
   dy = y2 - y1;
 
 
   /* choose variable to iterate on */
 
   dx = x2 - x1;
   dy = y2 - y1;
 
 
   /* choose variable to iterate on */
-  if (abs(dx)>abs(dy)) {
-    int dx2, dy2, cpy;
+  if (i_abs(dx) > i_abs(dy)) {
+    i_img_dim dx2, dy2, cpy;
 
     /* sort by x */
     if (x1 > x2) {
 
     /* sort by x */
     if (x1 > x2) {
-      int t;
+      i_img_dim t;
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
-    dx = abs(dx);
+    dx = i_abs(dx);
     dx2 = dx*2;
     dy = y2 - y1;
 
     dx2 = dx*2;
     dy = y2 - y1;
 
@@ -1224,16 +1403,16 @@ i_line(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int endp)
       i_ppix(im, x+1, y, val);
     }
   } else {
       i_ppix(im, x+1, y, val);
     }
   } else {
-    int dy2, dx2, cpx;
+    i_img_dim dy2, dx2, cpx;
 
     /* sort bx y */
     if (y1 > y2) {
 
     /* sort bx y */
     if (y1 > y2) {
-      int t;
+      i_img_dim t;
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
-    dy = abs(dy);
+    dy = i_abs(dy);
     dx = x2 - x1;
     dy2 = dy*2;
 
     dx = x2 - x1;
     dy2 = dy*2;
 
@@ -1269,14 +1448,14 @@ i_line(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int endp)
 
 
 void
 
 
 void
-i_line_dda(i_img *im, int x1, int y1, int x2, int y2, i_color *val) {
+i_line_dda(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_color *val) {
 
 
-  float dy;
-  int x;
+  double dy;
+  i_img_dim x;
   
   for(x=x1; x<=x2; x++) {
   
   for(x=x1; x<=x2; x++) {
-    dy = y1+ (x-x1)/(float)(x2-x1)*(y2-y1);
-    i_ppix(im, x, (int)(dy+0.5), val);
+    dy = y1+ (x-x1)/(double)(x2-x1)*(y2-y1);
+    i_ppix(im, x, (i_img_dim)(dy+0.5), val);
   }
 }
 
   }
 }
 
@@ -1293,26 +1472,26 @@ The point (x2, y2) is drawn only if C<endp> is set.
 */
 
 void
 */
 
 void
-i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int endp) {
-  int x, y;
-  int dx, dy;
-  int p;
+i_line_aa(i_img *im, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, const i_color *val, int endp) {
+  i_img_dim x, y;
+  i_img_dim dx, dy;
+  i_img_dim p;
 
   dx = x2 - x1;
   dy = y2 - y1;
 
   /* choose variable to iterate on */
 
   dx = x2 - x1;
   dy = y2 - y1;
 
   /* choose variable to iterate on */
-  if (abs(dx)>abs(dy)) {
-    int dx2, dy2, cpy;
+  if (i_abs(dx) > i_abs(dy)) {
+    i_img_dim dx2, dy2, cpy;
     
     /* sort by x */
     if (x1 > x2) {
     
     /* sort by x */
     if (x1 > x2) {
-      int t;
+      i_img_dim t;
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
-    dx = abs(dx);
+    dx = i_abs(dx);
     dx2 = dx*2;
     dy = y2 - y1;
 
     dx2 = dx*2;
     dy = y2 - y1;
 
@@ -1330,8 +1509,8 @@ i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int end
     for(x=x1; x<x2-1; x++) {
       int ch;
       i_color tval;
     for(x=x1; x<x2-1; x++) {
       int ch;
       i_color tval;
-      float t = (dy) ? -(float)(p)/(float)(dx2) : 1;
-      float t1, t2;
+      double t = (dy) ? -(float)(p)/(float)(dx2) : 1;
+      double t1, t2;
 
       if (t<0) t = 0;
       t1 = 1-t;
 
       if (t<0) t = 0;
       t1 = 1-t;
@@ -1355,16 +1534,16 @@ i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int end
       }
     }
   } else {
       }
     }
   } else {
-    int dy2, dx2, cpx;
+    i_img_dim dy2, dx2, cpx;
 
     /* sort bx y */
     if (y1 > y2) {
 
     /* sort bx y */
     if (y1 > y2) {
-      int t;
+      i_img_dim t;
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
       t = x1; x1 = x2; x2 = t;
       t = y1; y1 = y2; y2 = t;
     }
     
-    dy = abs(dy);
+    dy = i_abs(dy);
     dx = x2 - x1;
     dy2 = dy*2;
 
     dx = x2 - x1;
     dy2 = dy*2;
 
@@ -1382,8 +1561,8 @@ i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int end
     for(y=y1; y<y2-1; y++) {
       int ch;
       i_color tval;
     for(y=y1; y<y2-1; y++) {
       int ch;
       i_color tval;
-      float t = (dx) ? -(float)(p)/(float)(dy2) : 1;
-      float t1, t2;
+      double t = (dx) ? -(double)(p)/(double)(dy2) : 1;
+      double t1, t2;
       
       if (t<0) t = 0;
       t1 = 1-t;
       
       if (t<0) t = 0;
       t1 = 1-t;
@@ -1391,12 +1570,12 @@ i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int end
 
       i_gpix(im,x,y+1,&tval);
       for(ch=0;ch<im->channels;ch++)
 
       i_gpix(im,x,y+1,&tval);
       for(ch=0;ch<im->channels;ch++)
-       tval.channel[ch]=(unsigned char)(t1*(float)tval.channel[ch]+t2*(float)val->channel[ch]);
+       tval.channel[ch]=(unsigned char)(t1*(double)tval.channel[ch]+t2*(double)val->channel[ch]);
       i_ppix(im,x,y+1,&tval);
 
       i_gpix(im,x+cpx,y+1,&tval);
       for(ch=0;ch<im->channels;ch++)
       i_ppix(im,x,y+1,&tval);
 
       i_gpix(im,x+cpx,y+1,&tval);
       for(ch=0;ch<im->channels;ch++)
-       tval.channel[ch]=(unsigned char)(t2*(float)tval.channel[ch]+t1*(float)val->channel[ch]);
+       tval.channel[ch]=(unsigned char)(t2*(double)tval.channel[ch]+t1*(double)val->channel[ch]);
       i_ppix(im,x+cpx,y+1,&tval);
 
       if (p<0) {
       i_ppix(im,x+cpx,y+1,&tval);
 
       if (p<0) {
@@ -1421,9 +1600,9 @@ i_line_aa(i_img *im, int x1, int y1, int x2, int y2, const i_color *val, int end
 
 
 static double
 
 
 static double
-perm(int n,int k) {
+perm(i_img_dim n,i_img_dim k) {
   double r;
   double r;
-  int i;
+  i_img_dim i;
   r=1;
   for(i=k+1;i<=n;i++) r*=i;
   for(i=1;i<=(n-k);i++) r/=i;
   r=1;
   for(i=k+1;i<=n;i++) r*=i;
   for(i=1;i<=(n-k);i++) r/=i;
@@ -1441,7 +1620,7 @@ i_bezier_multi(i_img *im,int l,const double *x,const double *y, const i_color *v
   double *bzcoef;
   double t,cx,cy;
   int k,i;
   double *bzcoef;
   double t,cx,cy;
   int k,i;
-  int lx = 0,ly = 0;
+  i_img_dim lx = 0,ly = 0;
   int n=l-1;
   double itr,ccoef;
 
   int n=l-1;
   double itr,ccoef;
 
@@ -1467,11 +1646,11 @@ i_bezier_multi(i_img *im,int l,const double *x,const double *y, const i_color *v
     }
     /*    printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
     if (i++) { 
     }
     /*    printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
     if (i++) { 
-      i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val, 1);
+      i_line_aa(im,lx,ly,(i_img_dim)(0.5+cx),(i_img_dim)(0.5+cy),val, 1);
     }
     }
-      /*     i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
-    lx=(int)(0.5+cx);
-    ly=(int)(0.5+cy);
+      /*     i_ppix(im,(i_img_dim)(0.5+cx),(i_img_dim)(0.5+cy),val); */
+    lx=(i_img_dim)(0.5+cx);
+    ly=(i_img_dim)(0.5+cy);
   }
   ICL_info(val);
   myfree(bzcoef);
   }
   ICL_info(val);
   myfree(bzcoef);
@@ -1500,9 +1679,9 @@ i_bezier_multi(i_img *im,int l,const double *x,const double *y, const i_color *v
 
 /*
 struct stc {
 
 /*
 struct stc {
-  int mylx,myrx; 
-  int dadlx,dadrx;
-  int myy;
+  i_img_dim mylx,myrx; 
+  i_img_dim dadlx,dadrx;
+  i_img_dim myy;
   int mydirection;
 };
 
   int mydirection;
 };
 
@@ -1511,9 +1690,9 @@ Not used code???
 
 
 struct stack_element {
 
 
 struct stack_element {
-  int myLx,myRx;
-  int dadLx,dadRx;
-  int myY;
+  i_img_dim myLx,myRx;
+  i_img_dim dadLx,dadRx;
+  i_img_dim myY;
   int myDirection;
 };
 
   int myDirection;
 };
 
@@ -1522,7 +1701,7 @@ struct stack_element {
 
 static
 struct stack_element*
 
 static
 struct stack_element*
-crdata(int left,int right,int dadl,int dadr,int y, int dir) {
+crdata(i_img_dim left,i_img_dim right,i_img_dim dadl,i_img_dim dadr,i_img_dim y, int dir) {
   struct stack_element *ste;
   ste              = mymalloc(sizeof(struct stack_element)); /* checked 5jul05 tonyc */
   ste->myLx        = left;
   struct stack_element *ste;
   ste              = mymalloc(sizeof(struct stack_element)); /* checked 5jul05 tonyc */
   ste->myLx        = left;
@@ -1557,7 +1736,7 @@ i_ccomp_border(i_color const *val1, i_color const *val2, int ch) {
 }
 
 static int
 }
 
 static int
-i_lspan(i_img *im, int seedx, int seedy, i_color const *val, ff_cmpfunc cmpfunc) {
+i_lspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpfunc cmpfunc) {
   i_color cval;
   while(1) {
     if (seedx-1 < 0) break;
   i_color cval;
   while(1) {
     if (seedx-1 < 0) break;
@@ -1570,7 +1749,7 @@ i_lspan(i_img *im, int seedx, int seedy, i_color const *val, ff_cmpfunc cmpfunc)
 }
 
 static int
 }
 
 static int
-i_rspan(i_img *im, int seedx, int seedy, i_color const *val, ff_cmpfunc cmpfunc) {
+i_rspan(i_img *im, i_img_dim seedx, i_img_dim seedy, i_color const *val, ff_cmpfunc cmpfunc) {
   i_color cval;
   while(1) {
     if (seedx+1 > im->xsize-1) break;
   i_color cval;
   while(1) {
     if (seedx+1 > im->xsize-1) break;
@@ -1581,10 +1760,36 @@ i_rspan(i_img *im, int seedx, int seedy, i_color const *val, ff_cmpfunc cmpfunc)
   return seedx;
 }
 
   return seedx;
 }
 
+#ifdef DEBUG_FLOOD_FILL
+
+#define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir) \
+  fprintf(stderr, "push(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#define ST_POP_NOTE(left, right, dadl, dadr, y, dir) \
+  fprintf(stderr, "popped(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#define ST_STACK_NOTE(dadl, dadr, left, right, y, dir)                 \
+  fprintf(stderr, "stack(left %" i_DF ", right %" i_DF ", dadleft %" i_DF  ", dadright %" i_DF ", y %" i_DF ", dir %d, line %d)\n", \
+         i_DFc(left), i_DFc(right), i_DFc(dadl), i_DFc(dadr), i_DFc(y), (dir), __LINE__)
+
+#else
+
+#define ST_PUSH_NOTE(left, right, dadl, dadr, y, dir)
+
+#define ST_POP_NOTE(left, right, dadl, dadr, y, dir)
+
+#define ST_STACK_NOTE(dadl, dadr, left, right, y, dir)
+
+#endif
+
+
 /* Macro to create a link and push on to the list */
 
 #define ST_PUSH(left,right,dadl,dadr,y,dir) do {                 \
   struct stack_element *s = crdata(left,right,dadl,dadr,y,dir);  \
 /* Macro to create a link and push on to the list */
 
 #define ST_PUSH(left,right,dadl,dadr,y,dir) do {                 \
   struct stack_element *s = crdata(left,right,dadl,dadr,y,dir);  \
+  ST_PUSH_NOTE(left, right, dadl, dadr, y, dir);                \
   llist_push(st,&s);                                             \
 } while (0)
 
   llist_push(st,&s);                                             \
 } while (0)
 
@@ -1600,44 +1805,49 @@ i_rspan(i_img *im, int seedx, int seedy, i_color const *val, ff_cmpfunc cmpfunc)
   dadRx     = s->dadRx;       \
   y         = s->myY;         \
   direction = s->myDirection; \
   dadRx     = s->dadRx;       \
   y         = s->myY;         \
   direction = s->myDirection; \
+  ST_POP_NOTE(lx, rx, dadLx, dadRx, y, direction);     \
   myfree(s);                  \
 } while (0)
 
 #define ST_STACK(dir,dadLx,dadRx,lx,rx,y) do {                    \
   myfree(s);                  \
 } while (0)
 
 #define ST_STACK(dir,dadLx,dadRx,lx,rx,y) do {                    \
-  int pushrx = rx+1;                                              \
-  int pushlx = lx-1;                                              \
+  i_img_dim pushrx = rx+1;                                              \
+  i_img_dim pushlx = lx-1;                                              \
+  ST_STACK_NOTE(lx, rx, dadLx, dadRx, y, dir);          \
   ST_PUSH(lx,rx,pushlx,pushrx,y+dir,dir);                         \
   if (rx > dadRx)                                                 \
     ST_PUSH(dadRx+1,rx,pushlx,pushrx,y-dir,-dir);                 \
   ST_PUSH(lx,rx,pushlx,pushrx,y+dir,dir);                         \
   if (rx > dadRx)                                                 \
     ST_PUSH(dadRx+1,rx,pushlx,pushrx,y-dir,-dir);                 \
-  if (lx < dadLx) ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir);   \
+  if (lx < dadLx)                                              \
+    ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir);   \
 } while (0)
 
 #define SET(x,y) btm_set(btm,x,y)
 
 /* INSIDE returns true if pixel is correct color and we haven't set it before. */
 } while (0)
 
 #define SET(x,y) btm_set(btm,x,y)
 
 /* INSIDE returns true if pixel is correct color and we haven't set it before. */
-#define INSIDE(x,y, seed) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),cmpfunc(seed,&cval,channels)  ) ))
-
-
+#define INSIDE(x,y, seed) \
+  (assert((x) >= 0 && (x) < (im)->xsize && (y) >= 0 && (y) < (im)->ysize), \
+   (!btm_test(btm,x,y) && \
+     ( i_gpix(im,x,y,&cval),cmpfunc(seed,&cval,channels)  ) ))
 
 /* The function that does all the real work */
 
 static struct i_bitmap *
 
 /* The function that does all the real work */
 
 static struct i_bitmap *
-i_flood_fill_low(i_img *im,int seedx,int seedy,
-                 int *bxminp, int *bxmaxp, int *byminp, int *bymaxp,
+i_flood_fill_low(i_img *im,i_img_dim seedx,i_img_dim seedy,
+                 i_img_dim *bxminp, i_img_dim *bxmaxp, i_img_dim *byminp, i_img_dim *bymaxp,
                 i_color const *seed, ff_cmpfunc cmpfunc) {
                 i_color const *seed, ff_cmpfunc cmpfunc) {
-  int ltx, rtx;
-  int tx = 0;
+  i_img_dim ltx, rtx;
+  i_img_dim tx = 0;
 
 
-  int bxmin = seedx;
-  int bxmax = seedx;
-  int bymin = seedy;
-  int bymax = seedy;
+  i_img_dim bxmin = seedx;
+  i_img_dim bxmax = seedx;
+  i_img_dim bymin = seedy;
+  i_img_dim bymax = seedy;
 
   struct llist *st;
   struct i_bitmap *btm;
 
 
   struct llist *st;
   struct i_bitmap *btm;
 
-  int channels,xsize,ysize;
-  i_color cval;
+  int channels;
+  i_img_dim xsize,ysize;
+  i_color cval; /* used by the INSIDE() macro */
 
   channels = im->channels;
   xsize    = im->xsize;
 
   channels = im->channels;
   xsize    = im->xsize;
@@ -1658,12 +1868,12 @@ i_flood_fill_low(i_img *im,int seedx,int seedy,
 
   while(st->count) {
     /* Stack variables */
 
   while(st->count) {
     /* Stack variables */
-    int lx,rx;
-    int dadLx,dadRx;
-    int y;
+    i_img_dim lx,rx;
+    i_img_dim dadLx,dadRx;
+    i_img_dim y;
     int direction;
 
     int direction;
 
-    int x;
+    i_img_dim x;
     int wasIn=0;
 
     ST_POP(); /* sets lx, rx, dadLx, dadRx, y, direction */
     int wasIn=0;
 
     ST_POP(); /* sets lx, rx, dadLx, dadRx, y, direction */
@@ -1682,6 +1892,8 @@ i_flood_fill_low(i_img *im,int seedx,int seedy,
        SET(lx,y);
        lx--;
       }
        SET(lx,y);
        lx--;
       }
+      /* lx should point at the left-most INSIDE() pixel */
+      ++lx;
     }
 
     if (bxmin > lx) bxmin = lx;
     }
 
     if (bxmin > lx) bxmin = lx;
@@ -1746,16 +1958,20 @@ Returns false if (C<seedx>, C<seedy>) are outside the image.
 */
 
 undef_int
 */
 
 undef_int
-i_flood_fill(i_img *im, int seedx, int seedy, const i_color *dcol) {
-  int bxmin, bxmax, bymin, bymax;
+i_flood_fill(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol) {
+  i_img_dim bxmin, bxmax, bymin, bymax;
   struct i_bitmap *btm;
   struct i_bitmap *btm;
-  int x, y;
+  i_img_dim x, y;
   i_color val;
   i_color val;
+  dIMCTXim(im);
 
 
-  i_clear_error();
+  im_log((aIMCTX, 1, "i_flood_fill(im %p, seed(" i_DFp "), col %p)",
+          im, i_DFcp(seedx, seedy), dcol));
+
+  im_clear_error(aIMCTX);
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
-    i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
+    im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
     return 0;
   }
 
     return 0;
   }
 
@@ -1788,16 +2004,20 @@ Returns false if (C<seedx>, C<seedy>) are outside the image.
 */
 
 undef_int
 */
 
 undef_int
-i_flood_cfill(i_img *im, int seedx, int seedy, i_fill_t *fill) {
-  int bxmin, bxmax, bymin, bymax;
+i_flood_cfill(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill) {
+  i_img_dim bxmin, bxmax, bymin, bymax;
   struct i_bitmap *btm;
   i_color val;
   struct i_bitmap *btm;
   i_color val;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), fill %p)",
+          im, i_DFcp(seedx, seedy), fill));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
   
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
   
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
-    i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
+    im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
     return 0;
   }
 
     return 0;
   }
 
@@ -1829,16 +2049,20 @@ Returns false if (C<seedx>, C<seedy>) are outside the image.
 */
 
 undef_int
 */
 
 undef_int
-i_flood_fill_border(i_img *im, int seedx, int seedy, const i_color *dcol,
+i_flood_fill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol,
                    const i_color *border) {
                    const i_color *border) {
-  int bxmin, bxmax, bymin, bymax;
+  i_img_dim bxmin, bxmax, bymin, bymax;
   struct i_bitmap *btm;
   struct i_bitmap *btm;
-  int x, y;
+  i_img_dim x, y;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), dcol %p, border %p)",
+          im, i_DFcp(seedx, seedy), dcol, border));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
-    i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
+    im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
     return 0;
   }
 
     return 0;
   }
 
@@ -1869,16 +2093,20 @@ Returns false if (C<seedx>, C<seedy>) are outside the image.
 */
 
 undef_int
 */
 
 undef_int
-i_flood_cfill_border(i_img *im, int seedx, int seedy, i_fill_t *fill,
+i_flood_cfill_border(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill,
                     const i_color *border) {
                     const i_color *border) {
-  int bxmin, bxmax, bymin, bymax;
+  i_img_dim bxmin, bxmax, bymin, bymax;
   struct i_bitmap *btm;
   struct i_bitmap *btm;
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1, "i_flood_cfill_border(im %p, seed(" i_DFp "), fill %p, border %p)",
+          im, i_DFcp(seedx, seedy), fill, border));
 
 
-  i_clear_error();
+  im_clear_error(aIMCTX);
   
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
   
   if (seedx < 0 || seedx >= im->xsize ||
       seedy < 0 || seedy >= im->ysize) {
-    i_push_error(0, "i_flood_cfill_border: Seed pixel outside of image");
+    im_push_error(aIMCTX, 0, "i_flood_cfill_border: Seed pixel outside of image");
     return 0;
   }
 
     return 0;
   }
 
@@ -1894,9 +2122,9 @@ i_flood_cfill_border(i_img *im, int seedx, int seedy, i_fill_t *fill,
 
 static void
 cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, 
 
 static void
 cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, 
-              int bxmin, int bxmax, int bymin, int bymax) {
-  int x, y;
-  int start;
+              i_img_dim bxmin, i_img_dim bxmax, i_img_dim bymin, i_img_dim bymax) {
+  i_img_dim x, y;
+  i_img_dim start;
 
   i_render r;
 
 
   i_render r;
 
@@ -1919,3 +2147,9 @@ cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm,
   }
   i_render_done(&r);
 }
   }
   i_render_done(&r);
 }
+
+/*
+=back
+
+=cut
+*/