From xemacs-m  Tue Mar 18 01:35:02 1997
Received: from GS213.SP.CS.CMU.EDU (GS213.SP.CS.CMU.EDU [128.2.209.183])
	by xemacs.org (8.8.5/8.8.5) with SMTP id BAA04339
	for <xemacs-beta@xemacs.org>; Tue, 18 Mar 1997 01:35:02 -0600 (CST)
Received: by GS213.SP.CS.CMU.EDU (AIX 3.2/UCB 5.64/4.03)
          id AA30471; Tue, 18 Mar 1997 02:34:58 -0500
Date: Tue, 18 Mar 1997 02:34:58 -0500
Message-Id: <9703180734.AA30471@GS213.SP.CS.CMU.EDU>
From: Darrell Kindred <dkindred@cmu.edu>
To: xemacs-beta@xemacs.org
Subject: GIF-handling patch
Organization: Carnegie Mellon University School of Computer Science

David Moore's fix for the GIF crashes will almost certainly
work, and it's nice and small, but I think the one below may
be preferable.  Here's the deal, as I see it:

The our_own_dgif_slurp_from_gif2x11_c() function makes an
attempt to deal with multi-image GIF files, and with the
`Top' & `Left' specs that images after the first can have.
It does so in a pretty weird way though, and winds up
writing outside the allocated area when Top or Left is
non-zero.  Since XEmacs doesn't yet support multi-frame
gifs, we can just ignore all but the first image, and this
is what David's patch does.

My patch scraps our_own_dgif_slurp_from_gif2x11_c() entirely,
and reverts to using the regular DGifSlurp().  The reason
for the existence of the former function was that DGifSlurp() 
"doesn't handle interlaced files."  This isn't quite true
though--it sets the `Interlace' flag properly, but the bits
are stored in interlaced order.  My patch undoes the
interlacing when the corresponding X image is created.

The net effect is that we drop about 80 lines of code, which
seems like a good thing. :)

Oh, I also patched dgif_slurp to ignore GIF "extension"
records, since XEmacs doesn't use them and the dgif code
fails otherwise if the first record read is an extension
record.

Finally, I'll second the motion that we try to find a decent
GIF support library that doesn't use temp files.  Now that
this bug is squashed, though, perhaps it could wait until
after 19.15.

- Darrell

--- src/glyphs-x.c.orig	Mon Mar 17 20:36:17 1997
+++ src/glyphs-x.c	Tue Mar 18 02:27:48 1997
@@ -1604,6 +1604,7 @@
   return Qnil;
 }
 
+#if 0
 /* We provide our own version of DGifSlurp() because the standardly
    provided one doesn't handle interlaced GIFs.  This is based on
    code in gif2x11.c. */
@@ -1710,6 +1711,7 @@
 
   return GIF_OK;
 }
+#endif
 
 static void
 gif_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
@@ -1759,10 +1761,12 @@
 	signal_simple_error ("Unable to decode GIF",
 			     build_string (EmacsPrintGifError ()));
       }
-#if 1
+#if 0
     if (our_own_dgif_slurp_from_gif2x11_c(unwind.giffile) != GIF_OK)
 #else
-      /* DGifSlurp() doesn't handle interlaced files. */
+    /* DGifSlurp() doesn't handle interlaced files. */
+    /* Actually, it does, sort of.  It just sets the Interlace flag 
+       and stores RasterBits in interlaced order.  We handle that below. */
     if (DGifSlurp (unwind.giffile) != GIF_OK)
 #endif
       goto gif_decode_error;
@@ -1801,7 +1805,12 @@
     int width = unwind.giffile->SWidth;
     int depth;
     int bitmap_pad;
-    int i, j;
+    int i, j, row, pass, interlace;
+    /* interlaced gifs have rows in this order:
+       0, 8, 16, ..., 4, 12, 20, ..., 2, 6, 10, ..., 1, 3, 5, ...  */
+    static int InterlacedOffset[] = { 0, 4, 2, 1 };
+    static int InterlacedJumps[] = { 8, 8, 4, 2 };
+
     
     depth = DefaultDepthOfScreen (scr);
     
@@ -1834,14 +1843,35 @@
        optimization routines from XPM (they're in turn mostly
        copied from the Xlib source code). */
     
+    /* Note: We just use the first image in the file and ignore the rest. 
+             We check here that that image covers the full "screen" size.
+	     I don't know whether that's always the case.
+             -dkindred@cs.cmu.edu  */
+    if (unwind.giffile->SavedImages[0].ImageDesc.Height != height
+	|| unwind.giffile->SavedImages[0].ImageDesc.Width != width
+	|| unwind.giffile->SavedImages[0].ImageDesc.Left != 0
+	|| unwind.giffile->SavedImages[0].ImageDesc.Top != 0)
+      signal_simple_error ("First image in GIF file is not full size",
+			   instantiator);
+
+    interlace = unwind.giffile->SavedImages[0].ImageDesc.Interlace;
+    pass = 0;
+    row = interlace ? InterlacedOffset[pass] : 0;
     for (i = 0; i < height; i++)
-      for (j = 0; j < width; j++)
-	XPutPixel (unwind.ximage, j, i,
-		   unwind.pixels[(unsigned char)
-				 /* incorrect signed declaration
-				    of RasterBits[] */
-				 (unwind.giffile->SavedImages->
-				  RasterBits[i * width + j])]);
+      {
+	if (interlace && row >= height)
+	  row = InterlacedOffset[++pass];
+
+	for (j = 0; j < width; j++)
+	  XPutPixel (unwind.ximage, j, row,
+		     unwind.pixels[(unsigned char)
+				  /* incorrect signed declaration
+				     of RasterBits[] */
+				  (unwind.giffile->SavedImages[0].
+				   RasterBits[i * width + j])]);
+
+	row += interlace ? InterlacedJumps[pass] : 1;
+      }
   }
 
   /* 4. Now create the pixmap and set up the image instance */
--- src/dgif_lib.c.orig	Sun Feb  2 00:07:07 1997
+++ src/dgif_lib.c	Tue Mar 18 02:27:51 1997
@@ -915,6 +915,7 @@
     SavedImage *sp;
     ExtensionBlock *ep;
     GifByteType *ExtData;
+    int ExtCode;
 
     /* Some versions of malloc dislike 0-length requests */
     GifFile->SavedImages = (SavedImage *)xmalloc(sizeof(SavedImage));
@@ -941,7 +942,12 @@
 		break;
 
 	    case EXTENSION_RECORD_TYPE:
-
+	        /* This code fails if no image_desc record has been read
+		   yet.  I don't know if that's legal, but I've seen GIFs
+		   that start with an extension record.  XEmacs doesn't use
+		   the extension records anyway, so we'll just ignore them.
+		   - dkindred@cs.cmu.edu */
+#if 0
 		if (DGifGetExtension(GifFile,&sp->Function,&ExtData)==GIF_ERROR)
 		    return(GIF_ERROR);
 		else
@@ -965,6 +971,17 @@
 			memcpy(ep->Bytes,ExtData,ep->ByteCount * sizeof(char));
 		    }
 		}
+#else
+	        /* Skip any extension blocks in the file. */
+	        if (DGifGetExtension (GifFile, &ExtCode, &ExtData) 
+		    == GIF_ERROR)
+		    return GIF_ERROR;
+
+		while (ExtData != NULL) {
+		    if (DGifGetExtensionNext (GifFile, &ExtData) == GIF_ERROR)
+		        return GIF_ERROR;
+		}
+#endif
 		break;
 
 	    case TERMINATE_RECORD_TYPE:

