Backing out Bug 513681 and Bug 587371 for timeouts.
authorKyle Huey <me@kylehuey.com>
Sun, 22 Aug 2010 10:13:09 -0400
changeset 51215 3542b2bfa001604d2e0cbda82e8d588bb4e1331e
parent 51208 1d913becdd1a297f10b39b4d4e8e4d8eecab5dae
child 51216 7cc686f3317387f0f80b5f8d5f29949dc795dec9
push idunknown
push userunknown
push dateunknown
bugs513681, 587371
milestone2.0b5pre
Backing out Bug 513681 and Bug 587371 for timeouts.
config/autoconf.mk.in
configure.in
js/src/config/autoconf.mk.in
modules/libimg/png/Makefile.in
modules/libpr0n/Makefile.in
modules/libpr0n/build/Makefile.in
modules/libpr0n/build/nsImageModule.cpp
modules/libpr0n/decoders/GIF2.h
modules/libpr0n/decoders/Makefile.in
modules/libpr0n/decoders/bmp/Makefile.in
modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
modules/libpr0n/decoders/bmp/nsBMPDecoder.h
modules/libpr0n/decoders/bmp/nsICODecoder.cpp
modules/libpr0n/decoders/bmp/nsICODecoder.h
modules/libpr0n/decoders/bmp/nsIconDecoder.cpp
modules/libpr0n/decoders/bmp/nsIconDecoder.h
modules/libpr0n/decoders/gif/GIF2.h
modules/libpr0n/decoders/gif/Makefile.in
modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
modules/libpr0n/decoders/gif/nsGIFDecoder2.h
modules/libpr0n/decoders/iccjpeg.c
modules/libpr0n/decoders/iccjpeg.h
modules/libpr0n/decoders/jpeg/Makefile.in
modules/libpr0n/decoders/jpeg/iccjpeg.c
modules/libpr0n/decoders/jpeg/iccjpeg.h
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
modules/libpr0n/decoders/nsBMPDecoder.cpp
modules/libpr0n/decoders/nsBMPDecoder.h
modules/libpr0n/decoders/nsGIFDecoder2.cpp
modules/libpr0n/decoders/nsGIFDecoder2.h
modules/libpr0n/decoders/nsICODecoder.cpp
modules/libpr0n/decoders/nsICODecoder.h
modules/libpr0n/decoders/nsIconDecoder.cpp
modules/libpr0n/decoders/nsIconDecoder.h
modules/libpr0n/decoders/nsJPEGDecoder.cpp
modules/libpr0n/decoders/nsJPEGDecoder.h
modules/libpr0n/decoders/nsPNGDecoder.cpp
modules/libpr0n/decoders/nsPNGDecoder.h
modules/libpr0n/decoders/png/Makefile.in
modules/libpr0n/decoders/png/nsPNGDecoder.cpp
modules/libpr0n/decoders/png/nsPNGDecoder.h
modules/libpr0n/encoders/png/Makefile.in
modules/libpr0n/public/Makefile.in
modules/libpr0n/public/imgIDecoder.idl
modules/libpr0n/src/Decoder.cpp
modules/libpr0n/src/Decoder.h
modules/libpr0n/src/Image.cpp
modules/libpr0n/src/Image.h
modules/libpr0n/src/Makefile.in
modules/libpr0n/src/RasterImage.cpp
modules/libpr0n/src/RasterImage.h
modules/libpr0n/src/imgLoader.cpp
modules/libpr0n/src/imgRequest.cpp
modules/libpr0n/src/imgRequest.h
modules/libpr0n/src/imgRequestProxy.h
modules/libpr0n/src/imgStatusTracker.cpp
modules/libpr0n/src/imgTools.cpp
toolkit/library/Makefile.in
toolkit/library/libxul-config.mk
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -94,16 +94,17 @@ MOZ_JS_LIBS		   = @MOZ_JS_LIBS@
 
 MOZ_DEBUG	= @MOZ_DEBUG@
 MOZ_DEBUG_SYMBOLS = @MOZ_DEBUG_SYMBOLS@
 MOZ_DEBUG_ENABLE_DEFS		= @MOZ_DEBUG_ENABLE_DEFS@
 MOZ_DEBUG_DISABLE_DEFS	= @MOZ_DEBUG_DISABLE_DEFS@
 MOZ_DEBUG_FLAGS	= @MOZ_DEBUG_FLAGS@
 MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
 MOZ_EXTENSIONS  = @MOZ_EXTENSIONS@
+MOZ_IMG_DECODERS= @MOZ_IMG_DECODERS@
 MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@
 MOZ_JSDEBUGGER  = @MOZ_JSDEBUGGER@
 MOZ_IPC 	= @MOZ_IPC@
 MOZ_IPDL_TESTS 	= @MOZ_IPDL_TESTS@
 MOZ_LEAKY	= @MOZ_LEAKY@
 MOZ_MEMORY      = @MOZ_MEMORY@
 MOZ_JPROF       = @MOZ_JPROF@
 MOZ_SHARK       = @MOZ_SHARK@
--- a/configure.in
+++ b/configure.in
@@ -4871,16 +4871,17 @@ dnl ====================================
 MOZ_ARG_HEADER(Application)
 
 BUILD_STATIC_LIBS=
 ENABLE_TESTS=1
 MOZ_ACTIVEX_SCRIPTING_SUPPORT=
 MOZ_BRANDING_DIRECTORY=
 MOZ_OFFICIAL_BRANDING=
 MOZ_FEEDS=1
+MOZ_IMG_DECODERS_DEFAULT="png gif jpeg bmp icon"
 MOZ_IMG_ENCODERS_DEFAULT="png jpeg"
 MOZ_INSTALLER=1
 MOZ_IPC=1
 MOZ_JAVAXPCOM=
 MOZ_JSDEBUGGER=1
 MOZ_JSLOADER=1
 MOZ_MATHML=1
 MOZ_MORK=
@@ -6303,16 +6304,51 @@ MOZ_EXTENSIONS=`${PERL} ${srcdir}/build/
 dnl Ensure every extension exists, to avoid mostly-inscrutable error messages
 dnl when trying to build a nonexistent extension.
 for extension in $MOZ_EXTENSIONS; do
     if test ! -d "${srcdir}/extensions/${extension}"; then
         AC_MSG_ERROR([Unrecognized extension provided to --enable-extensions: ${extension}.])
     fi
 done
 
+
+dnl ========================================================
+dnl Image decoders
+dnl ========================================================
+case "$MOZ_WIDGET_TOOLKIT" in
+beos|windows|os2|mac|cocoa)
+    ;;
+*)
+    if test -z "$MOZ_ENABLE_GTK2" -a -z "$MOZ_ENABLE_QT"; then
+       MOZ_IMG_DECODERS_DEFAULT=`echo $MOZ_IMG_DECODERS_DEFAULT | sed -e 's|icon||'`
+    fi
+    ;;
+esac
+
+MOZ_ARG_ENABLE_STRING(image-decoders,
+[  --enable-image-decoders[={mod1,mod2,default,all,none}]
+                          Enable specific image decoders],
+[ for option in `echo $enableval | sed 's/,/ /g'`; do
+    if test "$option" = "yes" -o "$option" = "all"; then
+        MOZ_IMG_DECODERS="$MOZ_IMG_DECODERS $MOZ_IMG_DECODERS_DEFAULT"
+    elif test "$option" = "no" -o "$option" = "none"; then
+        MOZ_IMG_DECODERS=""
+    elif test "$option" = "default"; then
+        MOZ_IMG_DECODERS="$MOZ_IMG_DECODERS $MOZ_IMG_DECODERS_DEFAULT"
+    elif test `echo "$option" | grep -c \^-` != 0; then
+        option=`echo $option | sed 's/^-//'`
+        MOZ_IMG_DECODERS=`echo "$MOZ_IMG_DECODERS" | sed "s/ ${option}//"`
+    else
+        MOZ_IMG_DECODERS="$MOZ_IMG_DECODERS $option"
+    fi
+done],
+    MOZ_IMG_DECODERS="$MOZ_IMG_DECODERS_DEFAULT")
+
+dnl Dupes are removed in the encoder section because it will also add decoders
+
 dnl ========================================================
 dnl Image encoders
 dnl ========================================================
 MOZ_ARG_ENABLE_STRING(image-encoders,
 [  --enable-image-encoders[={mod1,mod2,default,all,none}]
                           Enable specific image encoders],
 [ for option in `echo $enableval | sed 's/,/ /g'`; do
     if test "$option" = "yes" -o "$option" = "all"; then
@@ -6328,16 +6364,17 @@ MOZ_ARG_ENABLE_STRING(image-encoders,
     else
         addencoder="$option"
     fi
     MOZ_IMG_ENCODERS="$MOZ_IMG_ENCODERS $addencoder"
 done],
     MOZ_IMG_ENCODERS="$MOZ_IMG_ENCODERS_DEFAULT")
 
 dnl Remove dupes
+MOZ_IMG_DECODERS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_IMG_DECODERS}`
 MOZ_IMG_ENCODERS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_IMG_ENCODERS}`
 
 dnl ========================================================
 dnl MathML on by default
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(mathml,
 [  --disable-mathml        Disable MathML support],
     MOZ_MATHML=,
@@ -8684,16 +8721,17 @@ AC_SUBST(MOZ_PSM)
 AC_SUBST(MOZ_DEBUG)
 AC_SUBST(MOZ_DEBUG_SYMBOLS)
 AC_SUBST(MOZ_DEBUG_ENABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_FLAGS)
 AC_SUBST(MOZ_DEBUG_LDFLAGS)
 AC_SUBST(WARNINGS_AS_ERRORS)
 AC_SUBST(MOZ_EXTENSIONS)
+AC_SUBST(MOZ_IMG_DECODERS)
 AC_SUBST(MOZ_IMG_ENCODERS)
 AC_SUBST(MOZ_JSDEBUGGER)
 AC_SUBST(MOZ_PLUGINS)
 AC_SUBST(MOZ_LOG_REFCNT)
 AC_SUBST(MOZ_LEAKY)
 AC_SUBST(MOZ_JPROF)
 AC_SUBST(MOZ_SHARK)
 AC_SUBST(MOZ_CALLGRIND)
--- a/js/src/config/autoconf.mk.in
+++ b/js/src/config/autoconf.mk.in
@@ -78,16 +78,17 @@ MOZ_SYNC_BUILD_FILES = @MOZ_SYNC_BUILD_F
 MOZ_DEBUG	= @MOZ_DEBUG@
 MOZ_DEBUG_SYMBOLS = @MOZ_DEBUG_SYMBOLS@
 MOZ_PROFILE_MODULES = @MOZ_PROFILE_MODULES@
 MOZ_DEBUG_ENABLE_DEFS		= @MOZ_DEBUG_ENABLE_DEFS@
 MOZ_DEBUG_DISABLE_DEFS	= @MOZ_DEBUG_DISABLE_DEFS@
 MOZ_DEBUG_FLAGS	= @MOZ_DEBUG_FLAGS@
 MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
 MOZ_EXTENSIONS  = @MOZ_EXTENSIONS@
+MOZ_IMG_DECODERS= @MOZ_IMG_DECODERS@
 MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@
 MOZ_JSDEBUGGER  = @MOZ_JSDEBUGGER@
 MOZ_LEAKY	= @MOZ_LEAKY@
 MOZ_MEMORY      = @MOZ_MEMORY@
 MOZ_JPROF       = @MOZ_JPROF@
 MOZ_SHARK       = @MOZ_SHARK@
 MOZ_CALLGRIND   = @MOZ_CALLGRIND@
 MOZ_VTUNE       = @MOZ_VTUNE@
--- a/modules/libimg/png/Makefile.in
+++ b/modules/libimg/png/Makefile.in
@@ -62,25 +62,27 @@ CSRCS		= \
 		pngerror.c \
 		pngget.c \
 		pngmem.c \
 		pngset.c \
 		pngtrans.c \
 		$(NULL)
 
 # These files enable support for reading PNGs
+ifneq (,$(filter png,$(MOZ_IMG_DECODERS)))
 CSRCS		+= \
 		pngpread.c \
 		pngread.c \
 		pngrio.c \
 		pngrtran.c \
 		pngrutil.c \
 		$(NULL)
 
 DEFINES		+= -DMOZ_PNG_READ
+endif
 
 # These files enable support for writing PNGs
 ifneq (,$(filter png,$(MOZ_IMG_ENCODERS)))
 CSRCS		+= \
 		pngwio.c \
 		pngwrite.c \
 		pngwtran.c \
 		pngwutil.c \
--- a/modules/libpr0n/Makefile.in
+++ b/modules/libpr0n/Makefile.in
@@ -39,17 +39,21 @@ DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= imglib2
 
-DIRS		= public src decoders
+DIRS		= public src 
+
+ifdef MOZ_IMG_DECODERS
+DIRS		+= decoders
+endif
 
 ifdef MOZ_IMG_ENCODERS
 DIRS		+= encoders
 endif
 
 ifdef ENABLE_TESTS
 DIRS  += test
 endif
--- a/modules/libpr0n/build/Makefile.in
+++ b/modules/libpr0n/build/Makefile.in
@@ -45,30 +45,34 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= imglib2
 LIBRARY_NAME	= imglib2
 EXPORT_LIBRARY = 1
 IS_COMPONENT	= 1
 MODULE_NAME	= nsImageLib2Module
 GRE_MODULE	= 1
 LIBXUL_LIBRARY = 1
 
+
 CPPSRCS = \
 		nsImageModule.cpp \
 		$(NULL)
 
 LOCAL_INCLUDES	= \
 		-I. \
 		-I$(srcdir)/../src \
+		$(foreach d,$(filter-out icon,$(MOZ_IMG_DECODERS)), \
+			-I$(srcdir)/../decoders/${d}) \
 		$(foreach d,$(MOZ_IMG_ENCODERS), \
 			-I$(srcdir)/../encoders/${d}) \
 		$(NULL)
 
 SHARED_LIBRARY_LIBS = \
 		../src/$(LIB_PREFIX)imglib2_s.$(LIB_SUFFIX) \
-		../decoders/$(LIB_PREFIX)imgdecoders_s.$(LIB_SUFFIX) \
+		$(foreach d,$(filter-out icon,$(MOZ_IMG_DECODERS)), \
+			../decoders/${d}/$(LIB_PREFIX)img${d}_s.$(LIB_SUFFIX))\
 		$(foreach d,$(MOZ_IMG_ENCODERS), \
 			../encoders/${d}/$(LIB_PREFIX)img${d}e_s.$(LIB_SUFFIX))\
 		$(NULL)
 
 EXTRA_DSO_LIBS	= \
 		gkgfx \
 		thebes \
 		$(NULL)
@@ -83,16 +87,18 @@ EXTRA_DSO_LDOPTS = \
 		$(NULL)
 
 # Force a rebuild of nsImageModule when either of MOZ_IMG_{DE,EN}CODERS changes
 
 GARBAGE += _img_list nsImgBuildDefines.h
 
 export::
 	{ \
+	$(foreach d,$(filter-out icon,$(MOZ_IMG_DECODERS)), \
+		echo "#define IMG_BUILD_DECODER_${d}" ; ) \
 	$(foreach d,$(MOZ_IMG_ENCODERS), \
 		echo "#define IMG_BUILD_ENCODER_${d}" ; ) \
 	} > nsImgBuildDefines.tmp
 	@if `cmp -s nsImgBuildDefines.h nsImgBuildDefines.tmp`; then \
 		rm -f nsImgBuildDefines.tmp; \
 	else \
 		rm -f nsImgBuildDefines.h; \
 		mv nsImgBuildDefines.tmp nsImgBuildDefines.h; \
--- a/modules/libpr0n/build/nsImageModule.cpp
+++ b/modules/libpr0n/build/nsImageModule.cpp
@@ -34,16 +34,23 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsImgBuildDefines.h"
 
+#ifdef XP_MAC
+#define IMG_BUILD_gif 1
+#define IMG_BUILD_bmp 1
+#define IMG_BUILD_png 1
+#define IMG_BUILD_jpeg 1
+#endif
+
 #include "nsIDeviceContext.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsXPCOMCID.h"
 #include "nsServiceManagerUtils.h"
 
 #include "RasterImage.h"
 
 /* We end up pulling in windows.h because we eventually hit gfxWindowsSurface;
@@ -55,16 +62,38 @@
 #undef LoadImage
 
 #include "imgLoader.h"
 #include "imgRequest.h"
 #include "imgRequestProxy.h"
 #include "imgTools.h"
 #include "DiscardTracker.h"
 
+#ifdef IMG_BUILD_DECODER_gif
+// gif
+#include "nsGIFDecoder2.h"
+#endif
+
+#ifdef IMG_BUILD_DECODER_bmp
+// bmp/ico
+#include "nsBMPDecoder.h"
+#include "nsICODecoder.h"
+#include "nsIconDecoder.h"
+#endif
+
+#ifdef IMG_BUILD_DECODER_png
+// png
+#include "nsPNGDecoder.h"
+#endif
+
+#ifdef IMG_BUILD_DECODER_jpeg
+// jpeg
+#include "nsJPEGDecoder.h"
+#endif
+
 #ifdef IMG_BUILD_ENCODER_png
 // png
 #include "nsPNGEncoder.h"
 #endif
 #ifdef IMG_BUILD_ENCODER_jpeg
 // jpeg
 #include "nsJPEGEncoder.h"
 #endif
@@ -76,79 +105,154 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(RasterIma
 }
 }
 using namespace mozilla::imagelib;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
 
+#ifdef IMG_BUILD_DECODER_gif
+// gif
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2)
+#endif
+
+#ifdef IMG_BUILD_DECODER_jpeg
+// jpeg
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGDecoder)
+#endif
 #ifdef IMG_BUILD_ENCODER_jpeg
 // jpeg
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGEncoder)
 #endif
 
+#ifdef IMG_BUILD_DECODER_bmp
+// bmp
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsICODecoder)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPDecoder)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconDecoder)
+#endif
+
+#ifdef IMG_BUILD_DECODER_png
+// png
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGDecoder)
+#endif
 #ifdef IMG_BUILD_ENCODER_png
 // png
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGEncoder)
 #endif
 
 NS_DEFINE_NAMED_CID(NS_IMGLOADER_CID);
 NS_DEFINE_NAMED_CID(NS_IMGREQUESTPROXY_CID);
 NS_DEFINE_NAMED_CID(NS_IMGTOOLS_CID);
 NS_DEFINE_NAMED_CID(NS_RASTERIMAGE_CID);
+#ifdef IMG_BUILD_DECODER_gif
+NS_DEFINE_NAMED_CID(NS_GIFDECODER2_CID);
+#endif
+#ifdef IMG_BUILD_DECODER_jpeg
+NS_DEFINE_NAMED_CID(NS_JPEGDECODER_CID);
+#endif
 #ifdef IMG_BUILD_ENCODER_jpeg
 NS_DEFINE_NAMED_CID(NS_JPEGENCODER_CID);
 #endif
+#ifdef IMG_BUILD_DECODER_bmp
+NS_DEFINE_NAMED_CID(NS_ICODECODER_CID);
+NS_DEFINE_NAMED_CID(NS_BMPDECODER_CID);
+NS_DEFINE_NAMED_CID(NS_ICONDECODER_CID);
+#endif
+#ifdef IMG_BUILD_DECODER_png
+NS_DEFINE_NAMED_CID(NS_PNGDECODER_CID);
+#endif
 #ifdef IMG_BUILD_ENCODER_png
 NS_DEFINE_NAMED_CID(NS_PNGENCODER_CID);
 #endif
 
 
 static const mozilla::Module::CIDEntry kImageCIDs[] = {
   { &kNS_IMGLOADER_CID, false, NULL, imgLoaderConstructor, },
   { &kNS_IMGREQUESTPROXY_CID, false, NULL, imgRequestProxyConstructor, },
   { &kNS_IMGTOOLS_CID, false, NULL, imgToolsConstructor, },
   { &kNS_RASTERIMAGE_CID, false, NULL, RasterImageConstructor, },
+#ifdef IMG_BUILD_DECODER_gif
+  { &kNS_GIFDECODER2_CID, false, NULL, nsGIFDecoder2Constructor, },
+#endif
+#ifdef IMG_BUILD_DECODER_jpeg
+  { &kNS_JPEGDECODER_CID, false, NULL, nsJPEGDecoderConstructor, },
+#endif
 #ifdef IMG_BUILD_ENCODER_jpeg
   { &kNS_JPEGENCODER_CID, false, NULL, nsJPEGEncoderConstructor, },
 #endif
+#ifdef IMG_BUILD_DECODER_bmp
+  { &kNS_ICODECODER_CID, false, NULL, nsICODecoderConstructor, },
+  { &kNS_BMPDECODER_CID, false, NULL, nsBMPDecoderConstructor, },
+  { &kNS_ICONDECODER_CID, false, NULL, nsIconDecoderConstructor, },
+#endif
+#ifdef IMG_BUILD_DECODER_png
+  { &kNS_PNGDECODER_CID, false, NULL, nsPNGDecoderConstructor, },
+#endif
 #ifdef IMG_BUILD_ENCODER_png
   { &kNS_PNGENCODER_CID, false, NULL, nsPNGEncoderConstructor, },
 #endif
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kImageContracts[] = {
   { "@mozilla.org/image/cache;1", &kNS_IMGLOADER_CID },
   { "@mozilla.org/image/loader;1", &kNS_IMGLOADER_CID },
   { "@mozilla.org/image/request;1", &kNS_IMGREQUESTPROXY_CID },
   { "@mozilla.org/image/tools;1", &kNS_IMGTOOLS_CID },
   { "@mozilla.org/image/rasterimage;1", &kNS_RASTERIMAGE_CID },
+#ifdef IMG_BUILD_DECODER_gif
+  { "@mozilla.org/image/decoder;3?type=image/gif", &kNS_GIFDECODER2_CID },
+#endif
+#ifdef IMG_BUILD_DECODER_jpeg
+  { "@mozilla.org/image/decoder;3?type=image/jpeg", &kNS_JPEGDECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/pjpeg", &kNS_JPEGDECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/jpg", &kNS_JPEGDECODER_CID },
+#endif
 #ifdef IMG_BUILD_ENCODER_jpeg
   { "@mozilla.org/image/encoder;2?type=image/jpeg", &kNS_JPEGENCODER_CID },
 #endif
+#ifdef IMG_BUILD_DECODER_bmp
+  { "@mozilla.org/image/decoder;3?type=image/x-icon", &kNS_ICODECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/vnd.microsoft.icon", &kNS_ICODECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/bmp", &kNS_BMPDECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/x-ms-bmp", &kNS_BMPDECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/icon", &kNS_ICONDECODER_CID },
+#endif
+#ifdef IMG_BUILD_DECODER_png
+  { "@mozilla.org/image/decoder;3?type=image/png", &kNS_PNGDECODER_CID },
+  { "@mozilla.org/image/decoder;3?type=image/x-png", &kNS_PNGDECODER_CID },
+#endif
 #ifdef IMG_BUILD_ENCODER_png
   { "@mozilla.org/image/encoder;2?type=image/png", &kNS_PNGENCODER_CID },
 #endif
   { NULL }
 };
 
 static const mozilla::Module::CategoryEntry kImageCategories[] = {
+#ifdef IMG_BUILD_DECODER_gif
   { "Gecko-Content-Viewers", "image/gif", "@mozilla.org/content/document-loader-factory;1" },
+#endif
+#ifdef IMG_BUILD_DECODER_jpeg
   { "Gecko-Content-Viewers", "image/jpeg", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/pjpeg", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/jpg", "@mozilla.org/content/document-loader-factory;1" },
+#endif
+#ifdef IMG_BUILD_DECODER_bmp
   { "Gecko-Content-Viewers", "image/x-icon", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/vnd.microsoft.icon", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/bmp", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/x-ms-bmp", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/icon", "@mozilla.org/content/document-loader-factory;1" },
+#endif
+#ifdef IMG_BUILD_DECODER_png
   { "Gecko-Content-Viewers", "image/png", "@mozilla.org/content/document-loader-factory;1" },
   { "Gecko-Content-Viewers", "image/x-png", "@mozilla.org/content/document-loader-factory;1" },
+#endif
   { "content-sniffing-services", "@mozilla.org/image/loader;1", "@mozilla.org/image/loader;1" },
   { NULL }
 };
 
 static nsresult
 imglib_Initialize()
 {
   // Hack: We need the gfx module to be initialized because we use gfxPlatform
deleted file mode 100644
--- a/modules/libpr0n/decoders/GIF2.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-#ifndef _GIF_H_
-#define _GIF_H_
-
-#define MAX_LZW_BITS          12
-#define MAX_BITS            4097 /* 2^MAX_LZW_BITS+1 */
-#define MAX_COLORS           256
-#define MAX_HOLD_SIZE        256
-
-enum { GIF_TRAILER                     = 0x3B }; //';'
-enum { GIF_IMAGE_SEPARATOR             = 0x2C }; //','
-enum { GIF_EXTENSION_INTRODUCER        = 0x21 }; //'!'
-enum { GIF_GRAPHIC_CONTROL_LABEL       = 0xF9 };
-enum { GIF_COMMENT_LABEL               = 0xFE };
-enum { GIF_PLAIN_TEXT_LABEL            = 0x01 };
-enum { GIF_APPLICATION_EXTENSION_LABEL = 0xFF };
-
-/* gif2.h  
-   The interface for the GIF87/89a decoder. 
-*/
-// List of possible parsing states
-typedef enum {
-    gif_type,
-    gif_global_header,
-    gif_global_colormap,
-    gif_image_start,
-    gif_image_header,
-    gif_image_colormap,
-    gif_image_body,
-    gif_lzw_start,
-    gif_lzw,
-    gif_sub_block,
-    gif_extension,
-    gif_control_extension,
-    gif_consume_block,
-    gif_skip_block,
-    gif_done,
-    gif_oom,
-    gif_error,
-    gif_comment_extension,
-    gif_application_extension,
-    gif_netscape_extension_block,
-    gif_consume_netscape_extension,
-    gif_consume_comment
-} gstate;
-
-/* A GIF decoder's state */
-typedef struct gif_struct {
-    /* Parsing state machine */
-    gstate state;                   /* Curent decoder master state */
-    PRUint32 bytes_to_consume;      /* Number of bytes to accumulate */
-    PRUint32 bytes_in_hold;         /* bytes accumulated so far*/
-
-    /* LZW decoder state machine */
-    PRUint8 *stackp;              /* Current stack pointer */
-    int datasize;
-    int codesize;
-    int codemask;
-    int avail;                  /* Index of next available slot in dictionary */
-    int oldcode;
-    PRUint8 firstchar;
-    int count;                  /* Remaining # bytes in sub-block */
-    int bits;                   /* Number of unread bits in "datum" */
-    int32 datum;                /* 32-bit input buffer */
-
-    /* Output state machine */
-    int ipass;                  /* Interlace pass; Ranges 1-4 if interlaced. */
-    PRUintn rows_remaining;        /* Rows remaining to be output */
-    PRUintn irow;                  /* Current output row, starting at zero */
-    PRUint8 *rowp;                 /* Current output pointer */
-
-    /* Parameters for image frame currently being decoded*/
-    PRUintn x_offset, y_offset;    /* With respect to "screen" origin */
-    PRUintn height, width;
-    int tpixel;                 /* Index of transparent pixel */
-    PRInt32 disposal_method;    /* Restore to background, leave in place, etc.*/
-    PRUint32 *local_colormap;   /* Per-image colormap */
-    int local_colormap_size;    /* Size of local colormap array. */
-    PRUint32 delay_time;        /* Display time, in milliseconds,
-                                   for this image in a multi-image GIF */
-
-    /* Global (multi-image) state */
-    int version;                /* Either 89 for GIF89 or 87 for GIF87 */
-    PRUintn screen_width;       /* Logical screen width & height */
-    PRUintn screen_height;
-    PRUint32 global_colormap_depth;  /* Depth of global colormap array. */
-    int images_decoded;         /* Counts images for multi-part GIFs */
-    int loop_count;             /* Netscape specific extension block to control
-                                   the number of animation loops a GIF renders. */
-
-    PRPackedBool progressive_display;    /* If TRUE, do Haeberli interlace hack */
-    PRPackedBool interlaced;             /* TRUE, if scanlines arrive interlaced order */
-    PRPackedBool is_transparent;         /* TRUE, if tpixel is valid */
-
-    PRUint16  prefix[MAX_BITS];          /* LZW decoding tables */
-    PRUint8   hold[MAX_HOLD_SIZE];       /* Accumulation buffer */
-    PRUint32  global_colormap[MAX_COLORS];   /* Default colormap if local not supplied */
-    PRUint8   suffix[MAX_BITS];          /* LZW decoding tables */
-    PRUint8   stack[MAX_BITS];           /* Base of LZW decoder stack */
-
-} gif_struct;
-
-#endif
-
--- a/modules/libpr0n/decoders/Makefile.in
+++ b/modules/libpr0n/decoders/Makefile.in
@@ -37,42 +37,17 @@
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-MODULE = imgdecoders
-LIBRARY_NAME = imgdecoders_s
-FORCE_STATIC_LIB = 1
-MODULE_NAME = nsDecodersModule
-LIBXUL_LIBRARY  = 1
-
-
-CPPSRCS = nsPNGDecoder.cpp nsJPEGDecoder.cpp nsGIFDecoder2.cpp \
-          nsBMPDecoder.cpp nsICODecoder.cpp nsIconDecoder.cpp \
-          $(NULL)
-
-CSRCS   = iccjpeg.c \
-          $(NULL)
-
-# Decoders need RasterImage.h
-LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src/
-
-# PNG read/write stuff
-ifneq (,$(filter png,$(MOZ_IMG_ENCODERS)))
-DEFINES		+= -DMOZ_PNG_WRITE
-endif
-DEFINES		+= -DMOZ_PNG_READ
-
-
-# The Icon Channel stuff really shouldn't live in decoders/icon, but we'll
-# fix that another time.
+ifneq (,$(filter icon,$(MOZ_IMG_DECODERS)))
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 DIRS = icon/gtk icon
 endif
 ifneq (,$(filter qt,$(MOZ_WIDGET_TOOLKIT)))
 DIRS = icon/qt icon
 endif
 ifeq (,$(filter-out WINNT WINCE, $(OS_ARCH)))
 DIRS = icon/win icon
@@ -81,11 +56,14 @@ ifeq ($(OS_ARCH),OS2)
 DIRS = icon/os2 icon
 endif
 ifeq ($(OS_ARCH),BeOS)
 DIRS = icon/beos icon
 endif
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 DIRS = icon/mac icon
 endif
+endif # icon
+
+DIRS += $(filter-out icon,$(MOZ_IMG_DECODERS))
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/Makefile.in
@@ -0,0 +1,58 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Christian Biesinger <cbiesinger@web.de>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= imgbmp
+LIBRARY_NAME	= imgbmp_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME	= nsBMPModule
+LIBXUL_LIBRARY  = 1
+
+
+CPPSRCS        = nsBMPDecoder.cpp nsICODecoder.cpp nsIconDecoder.cpp
+
+# ns[BMP,ICO,Icon]Decoder.cpp all include RasterImage.h
+LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src/
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
@@ -0,0 +1,675 @@
+/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla BMP Decoder.
+ *
+ * The Initial Developer of the Original Code is
+ * Christian Biesinger <cbiesinger@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Neil Rashbrook <neil@parkwaycc.co.uk>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* I got the format description from http://www.daubnet.com/formats/BMP.html */
+
+/* This is a Cross-Platform BMP Decoder, which should work everywhere, including
+ * Big-Endian machines like the PowerPC. */
+
+#include <stdlib.h>
+
+#include "nsBMPDecoder.h"
+
+#include "nsIInputStream.h"
+#include "nsIComponentManager.h"
+#include "RasterImage.h"
+#include "imgIContainerObserver.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+#include "prlog.h"
+
+using namespace mozilla::imagelib;
+
+#ifdef PR_LOGGING
+PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
+#endif
+
+// Convert from row (1..height) to absolute line (0..height-1)
+#define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
+#define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
+
+NS_IMPL_ISUPPORTS1(nsBMPDecoder, imgIDecoder)
+
+nsBMPDecoder::nsBMPDecoder()
+{
+    mColors = nsnull;
+    mRow = nsnull;
+    mCurPos = mPos = mNumColors = mRowBytes = 0;
+    mOldLine = mCurLine = 1; // Otherwise decoder will never start
+    mState = eRLEStateInitial;
+    mStateData = 0;
+    mLOH = WIN_HEADER_LENGTH;
+    mError = PR_FALSE;
+}
+
+nsBMPDecoder::~nsBMPDecoder()
+{
+  delete[] mColors;
+  if (mRow)
+      free(mRow);
+}
+
+NS_IMETHODIMP nsBMPDecoder::Init(imgIContainer *aImage,
+                                 imgIDecoderObserver *aObserver,
+                                 PRUint32 aFlags)
+{
+    NS_ABORT_IF_FALSE(aImage->GetType() == imgIContainer::TYPE_RASTER,
+                      "wrong type of imgIContainer for decoding into");
+
+    PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aImage));
+
+    mImage = static_cast<RasterImage*>(aImage);
+    mObserver = aObserver;
+    mFlags = aFlags;
+
+    // Fire OnStartDecode at init time to support bug 512435
+    if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
+        mObserver->OnStartDecode(nsnull);
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP nsBMPDecoder::Close(PRUint32 aFlags)
+{
+    PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
+
+    // Send notifications if appropriate
+    if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
+        !mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
+        if (mObserver)
+            mObserver->OnStopFrame(nsnull, 0);
+        mImage->DecodingComplete();
+        if (mObserver) {
+            mObserver->OnStopContainer(nsnull, mImage);
+            mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
+        }
+    }
+    return NS_OK;
+}
+
+NS_IMETHODIMP nsBMPDecoder::Flush()
+{
+    return NS_OK;
+}
+
+// ----------------------------------------
+// Actual Data Processing
+// ----------------------------------------
+
+static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
+{
+    // find the rightmost 1
+    PRUint8 pos;
+    PRBool started = PR_FALSE;
+    aBegin = aLength = 0;
+    for (pos = 0; pos <= 31; pos++) {
+        if (!started && (aMask & (1 << pos))) {
+            aBegin = pos;
+            started = PR_TRUE;
+        }
+        else if (started && !(aMask & (1 << pos))) {
+            aLength = pos - aBegin;
+            break;
+        }
+    }
+}
+
+NS_METHOD nsBMPDecoder::CalcBitShift()
+{
+    PRUint8 begin, length;
+    // red
+    calcBitmask(mBitFields.red, begin, length);
+    mBitFields.redRightShift = begin;
+    mBitFields.redLeftShift = 8 - length;
+    // green
+    calcBitmask(mBitFields.green, begin, length);
+    mBitFields.greenRightShift = begin;
+    mBitFields.greenLeftShift = 8 - length;
+    // blue
+    calcBitmask(mBitFields.blue, begin, length);
+    mBitFields.blueRightShift = begin;
+    mBitFields.blueLeftShift = 8 - length;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBMPDecoder::Write(const char* aBuffer, PRUint32 aCount)
+{
+    // No forgiveness
+    if (mError)
+      return NS_ERROR_FAILURE;
+
+    // aCount=0 means EOF, mCurLine=0 means we're past end of image
+    if (!aCount || !mCurLine)
+        return NS_OK;
+
+    nsresult rv;
+    if (mPos < BFH_LENGTH) { /* In BITMAPFILEHEADER */
+        PRUint32 toCopy = BFH_LENGTH - mPos;
+        if (toCopy > aCount)
+            toCopy = aCount;
+        memcpy(mRawBuf + mPos, aBuffer, toCopy);
+        mPos += toCopy;
+        aCount -= toCopy;
+        aBuffer += toCopy;
+    }
+    if (mPos == BFH_LENGTH) {
+        ProcessFileHeader();
+        if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
+            mError = PR_TRUE;
+            return NS_ERROR_FAILURE;
+        }
+        if (mBFH.bihsize == OS2_BIH_LENGTH)
+            mLOH = OS2_HEADER_LENGTH;
+    }
+    if (mPos >= BFH_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
+        PRUint32 toCopy = mLOH - mPos;
+        if (toCopy > aCount)
+            toCopy = aCount;
+        memcpy(mRawBuf + (mPos - BFH_LENGTH), aBuffer, toCopy);
+        mPos += toCopy;
+        aCount -= toCopy;
+        aBuffer += toCopy;
+    }
+    if (mPos == mLOH) {
+        ProcessInfoHeader();
+        PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lix%lix%lu. compression=%lu\n",
+            mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
+        // Verify we support this bit depth
+        if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
+            mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
+          mError = PR_TRUE;
+          return NS_ERROR_UNEXPECTED;
+        }
+
+        // BMPs with negative width are invalid
+        // Reject extremely wide images to keep the math sane
+        const PRInt32 k64KWidth = 0x0000FFFF;
+        if (mBIH.width < 0 || mBIH.width > k64KWidth) {
+            mError = PR_TRUE;
+            return NS_ERROR_FAILURE;
+        }
+
+        PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
+
+        // Set the size and notify
+        rv = mImage->SetSize(mBIH.width, real_height);
+        NS_ENSURE_SUCCESS(rv, rv);
+        if (mObserver) {
+            rv = mObserver->OnStartContainer(nsnull, mImage);
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
+
+        // We have the size. If we're doing a header-only decode, we got what
+        // we came for.
+        if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
+            return NS_OK;
+
+        // We're doing a real decode.
+        mOldLine = mCurLine = real_height;
+
+        if (mBIH.bpp <= 8) {
+            mNumColors = 1 << mBIH.bpp;
+            if (mBIH.colors && mBIH.colors < mNumColors)
+                mNumColors = mBIH.colors;
+
+            // Always allocate 256 even though mNumColors might be smaller
+            mColors = new colorTable[256];
+            if (!mColors) {
+                mError = PR_TRUE;
+                return NS_ERROR_OUT_OF_MEMORY;
+            }
+
+            memset(mColors, 0, 256 * sizeof(colorTable));
+        }
+        else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
+            // Use default 5-5-5 format
+            mBitFields.red   = 0x7C00;
+            mBitFields.green = 0x03E0;
+            mBitFields.blue  = 0x001F;
+            CalcBitShift();
+        }
+
+        PRUint32 imageLength;
+        if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
+            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatARGB32,
+                                     (PRUint8**)&mImageData, &imageLength);
+        } else {
+            // mRow is not used for RLE encoded images
+            mRow = (PRUint8*)malloc((mBIH.width * mBIH.bpp)/8 + 4);
+            // +4 because the line is padded to a 4 bit boundary, but I don't want
+            // to make exact calculations here, that's unnecessary.
+            // Also, it compensates rounding error.
+            if (!mRow) {
+                mError = PR_TRUE;
+                return NS_ERROR_OUT_OF_MEMORY;
+            }
+            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatRGB24,
+                                     (PRUint8**)&mImageData, &imageLength);
+        }
+        NS_ENSURE_SUCCESS(rv, rv);
+        if (!mImageData) {
+            mError = PR_TRUE;
+            return NS_ERROR_FAILURE;
+        }
+
+        // Prepare for transparancy
+        if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
+            if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) 
+             || ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
+                PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
+                mError = PR_TRUE;
+                return NS_ERROR_FAILURE;
+            }
+            // Clear the image, as the RLE may jump over areas
+            memset(mImageData, 0, imageLength);
+        }
+
+        if (mObserver) {
+            mObserver->OnStartFrame(nsnull, 0);
+            NS_ENSURE_SUCCESS(rv, rv);
+        }
+    }
+    PRUint8 bpc; // bytes per color
+    bpc = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4; // OS/2 Bitmaps have no padding byte
+    if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
+        // We will receive (mNumColors * bpc) bytes of color data
+        PRUint32 colorBytes = mPos - mLOH; // Number of bytes already received
+        PRUint8 colorNum = colorBytes / bpc; // Color which is currently received
+        PRUint8 at = colorBytes % bpc;
+        while (aCount && (mPos < (mLOH + mNumColors * bpc))) {
+            switch (at) {
+                case 0:
+                    mColors[colorNum].blue = *aBuffer;
+                    break;
+                case 1:
+                    mColors[colorNum].green = *aBuffer;
+                    break;
+                case 2:
+                    mColors[colorNum].red = *aBuffer;
+                    colorNum++;
+                    break;
+                case 3:
+                    // This is a padding byte
+                    break;
+            }
+            mPos++; aBuffer++; aCount--;
+            at = (at + 1) % bpc;
+        }
+    }
+    else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_HEADER_LENGTH + BITFIELD_LENGTH)) {
+        // If compression is used, this is a windows bitmap, hence we can
+        // use WIN_HEADER_LENGTH instead of mLOH
+        PRUint32 toCopy = (WIN_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
+        if (toCopy > aCount)
+            toCopy = aCount;
+        memcpy(mRawBuf + (mPos - WIN_HEADER_LENGTH), aBuffer, toCopy);
+        mPos += toCopy;
+        aBuffer += toCopy;
+        aCount -= toCopy;
+    }
+    if (mBIH.compression == BI_BITFIELDS && mPos == WIN_HEADER_LENGTH + BITFIELD_LENGTH) {
+        mBitFields.red = LITTLE_TO_NATIVE32(*(PRUint32*)mRawBuf);
+        mBitFields.green = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 4));
+        mBitFields.blue = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 8));
+        CalcBitShift();
+    }
+    while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
+        mPos++; aBuffer++; aCount--;
+    }
+    if (aCount && ++mPos >= mBFH.dataoffset) {
+        // Need to increment mPos, else we might get to mPos==mLOH again
+        // From now on, mPos is irrelevant
+        if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
+            PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
+            if (rowSize % 4)
+                rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
+            PRUint32 toCopy;
+            do {
+                toCopy = rowSize - mRowBytes;
+                if (toCopy) {
+                    if (toCopy > aCount)
+                        toCopy = aCount;
+                    memcpy(mRow + mRowBytes, aBuffer, toCopy);
+                    aCount -= toCopy;
+                    aBuffer += toCopy;
+                    mRowBytes += toCopy;
+                }
+                if (rowSize == mRowBytes) {
+                    // Collected a whole row into mRow, process it
+                    PRUint8* p = mRow;
+                    PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, 0);
+                    PRUint32 lpos = mBIH.width;
+                    switch (mBIH.bpp) {
+                      case 1:
+                        while (lpos > 0) {
+                          PRInt8 bit;
+                          PRUint8 idx;
+                          for (bit = 7; bit >= 0 && lpos > 0; bit--) {
+                              idx = (*p >> bit) & 1;
+                              SetPixel(d, idx, mColors);
+                              --lpos;
+                          }
+                          ++p;
+                        }
+                        break;
+                      case 4:
+                        while (lpos > 0) {
+                          Set4BitPixel(d, *p, lpos, mColors);
+                          ++p;
+                        }
+                        break;
+                      case 8:
+                        while (lpos > 0) {
+                          SetPixel(d, *p, mColors);
+                          --lpos;
+                          ++p;
+                        }
+                        break;
+                      case 16:
+                        while (lpos > 0) {
+                          PRUint16 val = LITTLE_TO_NATIVE16(*(PRUint16*)p);
+                          SetPixel(d,
+                                  (val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
+                                  (val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
+                                  (val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
+                          --lpos;
+                          p+=2;
+                        }
+                        break;
+                      case 32:
+                      case 24:
+                        while (lpos > 0) {
+                          SetPixel(d, p[2], p[1], p[0]);
+                          p += 2;
+                          --lpos;
+                          if (mBIH.bpp == 32)
+                            p++; // Padding byte
+                          ++p;
+                        }
+                        break;
+                      default:
+                        NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
+                    }
+                    mCurLine --;
+                    if (mCurLine == 0) { // Finished last line
+                        break;
+                    }
+                    mRowBytes = 0;
+
+                }
+            } while (aCount > 0);
+        } 
+        else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
+            if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) 
+             || ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
+                PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
+                mError = PR_TRUE;
+                return NS_ERROR_FAILURE;
+            }
+
+            while (aCount > 0) {
+                PRUint8 byte;
+
+                switch(mState) {
+                    case eRLEStateInitial:
+                        mStateData = (PRUint8)*aBuffer++;
+                        aCount--;
+
+                        mState = eRLEStateNeedSecondEscapeByte;
+                        continue;
+
+                    case eRLEStateNeedSecondEscapeByte:
+                        byte = *aBuffer++;
+                        aCount--;
+                        if (mStateData != RLE_ESCAPE) { // encoded mode
+                            // Encoded mode consists of two bytes: 
+                            // the first byte (mStateData) specifies the
+                            // number of consecutive pixels to be drawn 
+                            // using the color index contained in
+                            // the second byte
+                            // Work around bitmaps that specify too many pixels
+                            mState = eRLEStateInitial;
+                            PRUint32 pixelsNeeded = PR_MIN((PRUint32)(mBIH.width - mCurPos), mStateData);
+                            if (pixelsNeeded) {
+                                PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
+                                mCurPos += pixelsNeeded;
+                                if (mBIH.compression == BI_RLE8) {
+                                    do {
+                                        SetPixel(d, byte, mColors);
+                                        pixelsNeeded --;
+                                    } while (pixelsNeeded);
+                                } else {
+                                    do {
+                                        Set4BitPixel(d, byte, pixelsNeeded, mColors);
+                                    } while (pixelsNeeded);
+                                }
+                            }
+                            continue;
+                        }
+
+                        switch(byte) {
+                            case RLE_ESCAPE_EOL:
+                                // End of Line: Go to next row
+                                mCurLine --;
+                                mCurPos = 0;
+                                mState = eRLEStateInitial;
+                                break;
+
+                            case RLE_ESCAPE_EOF: // EndOfFile
+                                mCurPos = mCurLine = 0;
+                                break;
+
+                            case RLE_ESCAPE_DELTA:
+                                mState = eRLEStateNeedXDelta;
+                                continue;
+
+                            default : // absolute mode
+                                // Save the number of pixels to read
+                                mStateData = byte;
+                                if (mCurPos + mStateData > (PRUint32)mBIH.width) {
+                                    // We can work around bitmaps that specify one
+                                    // pixel too many, but only if their width is odd.
+                                    mStateData -= mBIH.width & 1;
+                                    if (mCurPos + mStateData > (PRUint32)mBIH.width) {
+                                        mError = PR_TRUE;
+                                        return NS_ERROR_FAILURE;
+                                    }
+                                }
+
+                                // See if we will need to skip a byte
+                                // to word align the pixel data
+                                // mStateData is a number of pixels
+                                // so allow for the RLE compression type
+                                // Pixels RLE8=1 RLE4=2
+                                //    1    Pad    Pad
+                                //    2    No     Pad
+                                //    3    Pad    No
+                                //    4    No     No
+                                if (((mStateData - 1) & mBIH.compression) != 0)
+                                    mState = eRLEStateAbsoluteMode;
+                                else
+                                    mState = eRLEStateAbsoluteModePadded;
+                                continue;
+                        }
+                        break;
+
+                    case eRLEStateNeedXDelta:
+                        // Handle the XDelta and proceed to get Y Delta
+                        byte = *aBuffer++;
+                        aCount--;
+                        mCurPos += byte;
+                        if (mCurPos > mBIH.width)
+                            mCurPos = mBIH.width;
+
+                        mState = eRLEStateNeedYDelta;
+                        continue;
+
+                    case eRLEStateNeedYDelta:
+                        // Get the Y Delta and then "handle" the move
+                        byte = *aBuffer++;
+                        aCount--;
+                        mState = eRLEStateInitial;
+                        mCurLine -= PR_MIN(byte, mCurLine);
+                        break;
+
+                    case eRLEStateAbsoluteMode: // Absolute Mode
+                    case eRLEStateAbsoluteModePadded:
+                        if (mStateData) {
+                            // In absolute mode, the second byte (mStateData)
+                            // represents the number of pixels 
+                            // that follow, each of which contains 
+                            // the color index of a single pixel.
+                            PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
+                            PRUint32* oldPos = d;
+                            if (mBIH.compression == BI_RLE8) {
+                                while (aCount > 0 && mStateData > 0) {
+                                    byte = *aBuffer++;
+                                    aCount--;
+                                    SetPixel(d, byte, mColors);
+                                    mStateData--;
+                                }
+                            } else {
+                                while (aCount > 0 && mStateData > 0) {
+                                    byte = *aBuffer++;
+                                    aCount--;
+                                    Set4BitPixel(d, byte, mStateData, mColors);
+                                }
+                            }
+                            mCurPos += d - oldPos;
+                        }
+
+                        if (mStateData == 0) {
+                            // In absolute mode, each run must 
+                            // be aligned on a word boundary
+
+                            if (mState == eRLEStateAbsoluteMode) { // Word Aligned
+                                mState = eRLEStateInitial;
+                            } else if (aCount > 0) {               // Not word Aligned
+                                // "next" byte is just a padding byte
+                                // so "move" past it and we can continue
+                                aBuffer++;
+                                aCount--;
+                                mState = eRLEStateInitial;
+                            }
+                        }
+                        // else state is still eRLEStateAbsoluteMode
+                        continue;
+
+                    default :
+                        NS_NOTREACHED("BMP RLE decompression: unknown state!");
+                        mError = PR_TRUE;
+                        return NS_ERROR_FAILURE;
+                }
+                // Because of the use of the continue statement
+                // we only get here for eol, eof or y delta
+                if (mCurLine == 0) { // Finished last line
+                    break;
+                }
+            }
+        }
+    }
+    
+    const PRUint32 rows = mOldLine - mCurLine;
+    if (rows) {
+        nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
+                    mBIH.width, rows);
+
+        // Tell the image that its data has been updated
+        rv = mImage->FrameUpdated(0, r); 
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (mObserver)
+            mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
+        mOldLine = mCurLine;
+    }
+
+    return NS_OK;
+}
+
+void nsBMPDecoder::ProcessFileHeader()
+{
+    memset(&mBFH, 0, sizeof(mBFH));
+    memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
+    memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
+    memcpy(&mBFH.reserved, mRawBuf + 6, sizeof(mBFH.reserved));
+    memcpy(&mBFH.dataoffset, mRawBuf + 10, sizeof(mBFH.dataoffset));
+    memcpy(&mBFH.bihsize, mRawBuf + 14, sizeof(mBFH.bihsize));
+
+    // Now correct the endianness of the header
+    mBFH.filesize = LITTLE_TO_NATIVE32(mBFH.filesize);
+    mBFH.dataoffset = LITTLE_TO_NATIVE32(mBFH.dataoffset);
+    mBFH.bihsize = LITTLE_TO_NATIVE32(mBFH.bihsize);
+}
+
+void nsBMPDecoder::ProcessInfoHeader()
+{
+    memset(&mBIH, 0, sizeof(mBIH));
+    if (mBFH.bihsize == 12) { // OS/2 Bitmap
+        memcpy(&mBIH.width, mRawBuf, 2);
+        memcpy(&mBIH.height, mRawBuf + 2, 2);
+        memcpy(&mBIH.planes, mRawBuf + 4, sizeof(mBIH.planes));
+        memcpy(&mBIH.bpp, mRawBuf + 6, sizeof(mBIH.bpp));
+    }
+    else {
+        memcpy(&mBIH.width, mRawBuf, sizeof(mBIH.width));
+        memcpy(&mBIH.height, mRawBuf + 4, sizeof(mBIH.height));
+        memcpy(&mBIH.planes, mRawBuf + 8, sizeof(mBIH.planes));
+        memcpy(&mBIH.bpp, mRawBuf + 10, sizeof(mBIH.bpp));
+        memcpy(&mBIH.compression, mRawBuf + 12, sizeof(mBIH.compression));
+        memcpy(&mBIH.image_size, mRawBuf + 16, sizeof(mBIH.image_size));
+        memcpy(&mBIH.xppm, mRawBuf + 20, sizeof(mBIH.xppm));
+        memcpy(&mBIH.yppm, mRawBuf + 24, sizeof(mBIH.yppm));
+        memcpy(&mBIH.colors, mRawBuf + 28, sizeof(mBIH.colors));
+        memcpy(&mBIH.important_colors, mRawBuf + 32, sizeof(mBIH.important_colors));
+    }
+
+    // Convert endianness
+    mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
+    mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
+    mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
+    mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
+
+    mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
+    mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
+    mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
+    mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
+    mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
+    mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
+}
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.h
@@ -0,0 +1,235 @@
+/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla BMP Decoder.
+ *
+ * The Initial Developer of the Original Code is
+ * Christian Biesinger <cbiesinger@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#ifndef _nsBMPDecoder_h
+#define _nsBMPDecoder_h
+
+#include "nsAutoPtr.h"
+#include "imgIDecoder.h"
+#include "imgIDecoderObserver.h"
+#include "gfxColor.h"
+
+#define NS_BMPDECODER_CID \
+{ /* {78c61626-4d1f-4843-9364-4652d98ff6e1} */ \
+  0x78c61626, \
+  0x4d1f, \
+  0x4843, \
+  { 0x93, 0x64, 0x46, 0x52, 0xd9, 0x8f, 0xf6, 0xe1 } \
+}
+
+struct BMPFILEHEADER {
+    char signature[2]; // String "BM"
+    PRUint32 filesize;
+    PRInt32 reserved; // Zero
+    PRUint32 dataoffset; // Offset to raster data
+
+    PRUint32 bihsize;
+};
+#define BFH_LENGTH 18 // Note: For our purposes, we include bihsize in the BFH
+
+#define OS2_BIH_LENGTH 12 // This is the real BIH size (as contained in the bihsize field of BMPFILEHEADER)
+#define OS2_HEADER_LENGTH (BFH_LENGTH + 8)
+#define WIN_HEADER_LENGTH (BFH_LENGTH + 36)
+
+struct BMPINFOHEADER {
+    PRInt32 width; // Uint16 in OS/2 BMPs
+    PRInt32 height; // Uint16 in OS/2 BMPs
+    PRUint16 planes; // =1
+    PRUint16 bpp; // Bits per pixel.
+    // The rest of the header is not available in OS/2 BMP Files
+    PRUint32 compression; // 0=no compression 1=8bit RLE 2=4bit RLE
+    PRUint32 image_size; // (compressed) image size. Can be 0 if compression==0
+    PRUint32 xppm; // Pixels per meter, horizontal
+    PRUint32 yppm; // Pixels per meter, vertical
+    PRUint32 colors; // Used Colors
+    PRUint32 important_colors; // Number of important colors. 0=all
+};
+
+struct colorTable {
+    PRUint8 red;
+    PRUint8 green;
+    PRUint8 blue;
+};
+
+struct bitFields {
+    PRUint32 red;
+    PRUint32 green;
+    PRUint32 blue;
+    PRUint8 redLeftShift;
+    PRUint8 redRightShift;
+    PRUint8 greenLeftShift;
+    PRUint8 greenRightShift;
+    PRUint8 blueLeftShift;
+    PRUint8 blueRightShift;
+};
+
+#define BITFIELD_LENGTH 12 // Length of the bitfields structure in the bmp file
+
+#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
+// We must ensure that the entity is unsigned
+// otherwise, if it is signed/negative, the MSB will be
+// propagated when we shift
+#define LITTLE_TO_NATIVE16(x) (((((PRUint16) x) & 0xFF) << 8) | \
+                               (((PRUint16) x) >> 8))
+#define LITTLE_TO_NATIVE32(x) (((((PRUint32) x) & 0xFF) << 24) | \
+                               (((((PRUint32) x) >> 8) & 0xFF) << 16) | \
+                               (((((PRUint32) x) >> 16) & 0xFF) << 8) | \
+                               (((PRUint32) x) >> 24))
+#else
+#define LITTLE_TO_NATIVE16(x) x
+#define LITTLE_TO_NATIVE32(x) x
+#endif
+
+#define USE_RGB
+
+// BMPINFOHEADER.compression defines
+#define BI_RLE8 1
+#define BI_RLE4 2
+#define BI_BITFIELDS 3
+
+// RLE Escape codes
+#define RLE_ESCAPE       0
+#define RLE_ESCAPE_EOL   0
+#define RLE_ESCAPE_EOF   1
+#define RLE_ESCAPE_DELTA 2
+
+/// enums for mState
+enum ERLEState {
+    eRLEStateInitial,
+    eRLEStateNeedSecondEscapeByte,
+    eRLEStateNeedXDelta,
+    eRLEStateNeedYDelta,    ///< mStateData will hold x delta
+    eRLEStateAbsoluteMode,  ///< mStateData will hold count of existing data to read
+    eRLEStateAbsoluteModePadded ///< As above, but another byte of data has to be read as padding
+};
+
+namespace mozilla {
+namespace imagelib {
+class RasterImage;
+} // namespace imagelib
+} // namespace mozilla
+
+/**
+ * Decoder for BMP-Files, as used by Windows and OS/2
+ */
+class nsBMPDecoder : public imgIDecoder
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_IMGIDECODER
+    
+    nsBMPDecoder();
+    ~nsBMPDecoder();
+
+private:
+
+    /** Calculates the red-, green- and blueshift in mBitFields using
+     * the bitmasks from mBitFields */
+    NS_METHOD CalcBitShift();
+
+    nsCOMPtr<imgIDecoderObserver> mObserver;
+
+    nsRefPtr<mozilla::imagelib::RasterImage> mImage;
+    PRUint32 mFlags;
+
+    PRUint32 mPos;
+
+    BMPFILEHEADER mBFH;
+    BMPINFOHEADER mBIH;
+    char mRawBuf[36];
+
+    PRUint32 mLOH; ///< Length of the header
+
+    PRUint32 mNumColors; ///< The number of used colors, i.e. the number of entries in mColors
+    colorTable *mColors;
+
+    bitFields mBitFields;
+
+    PRUint32 *mImageData; ///< Pointer to the image data for the frame
+    PRUint8 *mRow;      ///< Holds one raw line of the image
+    PRUint32 mRowBytes; ///< How many bytes of the row were already received
+    PRInt32 mCurLine;   ///< Index of the line of the image that's currently being decoded
+    PRInt32 mOldLine;   ///< Previous index of the line 
+    PRInt32 mCurPos;    ///< Index in the current line of the image
+
+    ERLEState mState;   ///< Maintains the current state of the RLE decoding
+    PRUint32 mStateData;///< Decoding information that is needed depending on mState
+    PRBool mError;      ///< Did we hit an error?
+
+    /** Set mBFH from the raw data in mRawBuf, converting from little-endian
+     * data to native data as necessary */
+    void ProcessFileHeader();
+    /** Set mBIH from the raw data in mRawBuf, converting from little-endian
+     * data to native data as necessary */
+    void ProcessInfoHeader();
+};
+
+/** Sets the pixel data in aDecoded to the given values.
+ * @param aDecoded pointer to pixel to be set, will be incremented to point to the next pixel.
+ */
+static inline void SetPixel(PRUint32*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
+{
+    *aDecoded++ = GFX_PACKED_PIXEL(aAlpha, aRed, aGreen, aBlue);
+}
+
+static inline void SetPixel(PRUint32*& aDecoded, PRUint8 idx, colorTable* aColors)
+{
+    SetPixel(aDecoded, aColors[idx].red, aColors[idx].green, aColors[idx].blue);
+}
+
+/** Sets two (or one if aCount = 1) pixels
+ * @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
+ * depending on whether one or two pixels are written.
+ * @param aData The values for the two pixels
+ * @param aCount Current count. Is decremented by one or two.
+ */
+inline void Set4BitPixel(PRUint32*& aDecoded, PRUint8 aData,
+                         PRUint32& aCount, colorTable* aColors)
+{
+    PRUint8 idx = aData >> 4;
+    SetPixel(aDecoded, idx, aColors);
+    if (--aCount > 0) {
+        idx = aData & 0xF;
+        SetPixel(aDecoded, idx, aColors);
+        --aCount;
+    }
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.cpp
@@ -0,0 +1,557 @@
+/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla ICO Decoder.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Hyatt <hyatt@netscape.com> (Original Author)
+ *   Christian Biesinger <cbiesinger@web.de>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* This is a Cross-Platform ICO Decoder, which should work everywhere, including
+ * Big-Endian machines like the PowerPC. */
+
+#include <stdlib.h>
+
+#include "nsICODecoder.h"
+
+#include "nsIInputStream.h"
+#include "nsIComponentManager.h"
+#include "RasterImage.h"
+#include "imgIContainerObserver.h"
+
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+#include "nsIProperties.h"
+#include "nsISupportsPrimitives.h"
+
+using namespace mozilla::imagelib;
+
+NS_IMPL_ISUPPORTS1(nsICODecoder, imgIDecoder)
+
+#define ICONCOUNTOFFSET 4
+#define DIRENTRYOFFSET 6
+#define BITMAPINFOSIZE 40
+#define PREFICONSIZE 16
+
+// ----------------------------------------
+// Actual Data Processing
+// ----------------------------------------
+
+PRUint32 nsICODecoder::CalcAlphaRowSize()
+{
+  // Calculate rowsize in DWORD's and then return in # of bytes
+  PRUint32 rowSize = (mDirEntry.mWidth + 31) / 32; // +31 to round up
+  return rowSize * 4;        // Return rowSize in bytes
+}
+
+nsICODecoder::nsICODecoder()
+{
+  mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
+  mCurLine = 1; // Otherwise decoder will never start
+  mColors = nsnull;
+  mRow = nsnull;
+  mHaveAlphaData = mDecodingAndMask = PR_FALSE;
+  mError = PR_FALSE;
+}
+
+nsICODecoder::~nsICODecoder()
+{
+}
+
+NS_IMETHODIMP nsICODecoder::Init(imgIContainer *aImage,
+                                 imgIDecoderObserver *aObserver,
+                                 PRUint32 aFlags)
+{
+  NS_ABORT_IF_FALSE(aImage->GetType() == imgIContainer::TYPE_RASTER,
+                    "wrong type of imgIContainer for decoding into");
+
+  // Grab parameters
+  mImage = static_cast<RasterImage*>(aImage);
+  mObserver = aObserver;
+  mFlags = aFlags;
+
+  // Fire OnStartDecode at init time to support bug 512435
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
+    mObserver->OnStartDecode(nsnull);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsICODecoder::Close(PRUint32 aFlags)
+{
+  nsresult rv = NS_OK;
+
+  // Send notifications if appropriate
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
+      !mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
+    // Tell the image that it's data has been updated 
+    nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
+    rv = mImage->FrameUpdated(0, r);
+
+
+    if (mObserver) {
+      mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
+      mObserver->OnStopFrame(nsnull, 0);
+    }
+    mImage->DecodingComplete();
+    if (mObserver) {
+      mObserver->OnStopContainer(nsnull, 0);
+      mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
+    }
+  }
+
+  mPos = 0;
+
+  delete[] mColors;
+
+  mCurLine = 0;
+  mRowBytes = 0;
+  mImageOffset = 0;
+  mCurrIcon = 0;
+  mNumIcons = 0;
+
+  if (mRow) {
+    free(mRow);
+    mRow = nsnull;
+  }
+  mDecodingAndMask = PR_FALSE;
+
+  return rv;
+}
+
+NS_IMETHODIMP nsICODecoder::Flush()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsICODecoder::Write(const char* aBuffer, PRUint32 aCount)
+{
+  // No forgiveness
+  if (mError)
+    return NS_ERROR_FAILURE;
+
+  if (!aCount) // aCount=0 means EOF
+    return NS_OK;
+
+  while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
+    if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
+      if ((*aBuffer != 1) && (*aBuffer != 2)) {
+        mError = PR_TRUE;
+        return NS_ERROR_FAILURE;
+      }
+      mIsCursor = (*aBuffer == 2);
+    }
+    mPos++; aBuffer++; aCount--;
+  }
+
+  if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
+    mNumIcons = LITTLE_TO_NATIVE16(((PRUint16*)aBuffer)[0]);
+    aBuffer += 2;
+    mPos += 2;
+    aCount -= 2;
+  }
+
+  if (mNumIcons == 0)
+    return NS_OK; // Nothing to do.
+
+  PRUint16 colorDepth = 0;
+  while (mCurrIcon < mNumIcons) {
+    if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) && 
+        mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
+      PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
+      if (toCopy > aCount)
+        toCopy = aCount;
+      memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
+      mPos += toCopy;
+      aCount -= toCopy;
+      aBuffer += toCopy;
+    }
+    if (aCount == 0)
+      return NS_OK; // Need more data
+
+    IconDirEntry e;
+    if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
+      mCurrIcon++;
+      ProcessDirEntry(e);
+      if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE && e.mBitCount >= colorDepth)
+           || (mCurrIcon == mNumIcons && mImageOffset == 0)) {
+        mImageOffset = e.mImageOffset;
+
+        // ensure mImageOffset is >= the size of the direntry headers (bug #245631)
+        PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
+        if (mImageOffset < minImageOffset) {
+          mError = PR_TRUE;
+          return NS_ERROR_FAILURE;
+        }
+
+        colorDepth = e.mBitCount;
+        memcpy(&mDirEntry, &e, sizeof(IconDirEntry));
+      }
+    }
+  }
+
+  if (mPos < mImageOffset) {
+    // Skip to (or at least towards) the desired image offset
+    PRUint32 toSkip = mImageOffset - mPos;
+    if (toSkip > aCount)
+      toSkip = aCount;
+
+    mPos    += toSkip;
+    aBuffer += toSkip;
+    aCount  -= toSkip;
+  }
+
+  if (mCurrIcon == mNumIcons && mPos >= mImageOffset && mPos < mImageOffset + BITMAPINFOSIZE) {
+    // We've found the icon.
+    PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
+    if (toCopy > aCount)
+      toCopy = aCount;
+
+    memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
+    mPos += toCopy;
+    aCount -= toCopy;
+    aBuffer += toCopy;
+  }
+
+  nsresult rv;
+
+  if (mPos == mImageOffset + BITMAPINFOSIZE) {
+
+    ProcessInfoHeader();
+    rv = mImage->SetSize(mDirEntry.mWidth, mDirEntry.mHeight);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (mObserver) {
+      rv = mObserver->OnStartContainer(nsnull, mImage);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
+      return NS_OK;
+
+    if (mBIH.bpp <= 8) {
+      switch (mBIH.bpp) {
+        case 1:
+          mNumColors = 2;
+          break;
+        case 4:
+          mNumColors = 16;
+          break;
+        case 8:
+          mNumColors = 256;
+          break;
+        default:
+          mError = PR_TRUE;
+          return NS_ERROR_FAILURE;
+      }
+
+      mColors = new colorTable[mNumColors];
+      if (!mColors) {
+        mError = PR_TRUE;
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+    }
+
+    if (mIsCursor) {
+      nsCOMPtr<nsISupportsPRUint32> intwrapx = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
+      nsCOMPtr<nsISupportsPRUint32> intwrapy = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
+
+      if (intwrapx && intwrapy) {
+        intwrapx->SetData(mDirEntry.mXHotspot);
+        intwrapy->SetData(mDirEntry.mYHotspot);
+
+        mImage->Set("hotspotX", intwrapx);
+        mImage->Set("hotspotY", intwrapy);
+      }
+    }
+
+    mCurLine = mDirEntry.mHeight;
+    mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
+    // +4 because the line is padded to a 4 bit boundary, but I don't want
+    // to make exact calculations here, that's unnecessary.
+    // Also, it compensates rounding error.
+    if (!mRow) {
+      mError = PR_TRUE;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    PRUint32 imageLength;
+    rv = mImage->AppendFrame(0, 0, mDirEntry.mWidth, mDirEntry.mHeight,
+                             gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (mObserver) {
+      mObserver->OnStartFrame(nsnull, 0);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
+  if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) && 
+                 (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
+    // We will receive (mNumColors * 4) bytes of color data
+    PRUint32 colorBytes = mPos - (mImageOffset + 40); // Number of bytes already received
+    PRUint8 colorNum = colorBytes / 4; // Color which is currently received
+    PRUint8 at = colorBytes % 4;
+    while (aCount && (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
+      switch (at) {
+        case 0:
+          mColors[colorNum].blue = *aBuffer;
+          break;
+        case 1:
+          mColors[colorNum].green = *aBuffer;
+          break;
+        case 2:
+          mColors[colorNum].red = *aBuffer;
+          break;
+        case 3:
+          colorNum++; // This is a padding byte
+          break;
+      }
+      mPos++; aBuffer++; aCount--;
+      at = (at + 1) % 4;
+    }
+  }
+
+  if (!mDecodingAndMask && (mPos >= (mImageOffset + BITMAPINFOSIZE + mNumColors*4))) {
+    if (mPos == (mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
+      // Increment mPos to avoid reprocessing the info header.
+      mPos++;
+    }
+
+    // Ensure memory has been allocated before decoding. If we get this far 
+    // without allocated memory, the file is most likely invalid.
+    NS_ASSERTION(mRow, "mRow is null");
+    NS_ASSERTION(mImageData, "mImageData is null");
+    if (!mRow || !mImageData) {
+      mError = PR_TRUE;
+      return NS_ERROR_FAILURE;
+    }
+
+    PRUint32 rowSize = (mBIH.bpp * mDirEntry.mWidth + 7) / 8; // +7 to round up
+    if (rowSize % 4)
+      rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
+    PRUint32 toCopy;
+    do {
+        toCopy = rowSize - mRowBytes;
+        if (toCopy) {
+            if (toCopy > aCount)
+                toCopy = aCount;
+            memcpy(mRow + mRowBytes, aBuffer, toCopy);
+            aCount -= toCopy;
+            aBuffer += toCopy;
+            mRowBytes += toCopy;
+        }
+        if (rowSize == mRowBytes) {
+            mCurLine--;
+            PRUint32* d = mImageData + (mCurLine * mDirEntry.mWidth);
+            PRUint8* p = mRow;
+            PRUint32 lpos = mDirEntry.mWidth;
+            switch (mBIH.bpp) {
+              case 1:
+                while (lpos > 0) {
+                  PRInt8 bit;
+                  PRUint8 idx;
+                  for (bit = 7; bit >= 0 && lpos > 0; bit--) {
+                      idx = (*p >> bit) & 1;
+                      SetPixel(d, idx, mColors);
+                      --lpos;
+                  }
+                  ++p;
+                }
+                break;
+              case 4:
+                while (lpos > 0) {
+                  Set4BitPixel(d, *p, lpos, mColors);
+                  ++p;
+                }
+                break;
+              case 8:
+                while (lpos > 0) {
+                  SetPixel(d, *p, mColors);
+                  --lpos;
+                  ++p;
+                }
+                break;
+              case 16:
+                while (lpos > 0) {
+                  SetPixel(d,
+                          (p[1] & 124) << 1,
+                          ((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
+                          (p[0] & 31) << 3);
+
+                  --lpos;
+                  p+=2;
+                }
+                break;
+              case 24:
+                while (lpos > 0) {
+                  SetPixel(d, p[2], p[1], p[0]);
+                  p += 3;
+                  --lpos;
+                }
+                break;
+              case 32:
+                // We assume that 32bit doesn't have alpha data until we
+                // find a non-zero alpha byte. If we find such a byte, 
+                // it means that all previous pixels are really clear (alphabyte=0).
+                // This working assumption prevents us having to premultiply afterwards.
+                while (lpos > 0) {
+                  if (!mHaveAlphaData && p[3]) {
+                    // Non-zero alpha byte detected! Clear previous pixels from current row to end
+                    memset(mImageData + mCurLine * mDirEntry.mWidth, 0, 
+                           (mDirEntry.mHeight - mCurLine) * mDirEntry.mWidth * sizeof(PRUint32));
+                    mHaveAlphaData = PR_TRUE;
+                  }                        
+                  SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
+                  p += 4;
+                  --lpos;
+                }
+                break;
+              default:
+                // This is probably the wrong place to check this...
+                mError = PR_TRUE;
+                return NS_ERROR_FAILURE;
+            }
+
+            if (mCurLine == 0)
+              mDecodingAndMask = PR_TRUE;
+              
+            mRowBytes = 0;
+        }
+    } while (!mDecodingAndMask && aCount > 0);
+
+  }
+
+  if (mDecodingAndMask && !mHaveAlphaData) {
+    PRUint32 rowSize = CalcAlphaRowSize();
+
+    if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
+      mPos++;
+      mRowBytes = 0;
+      mCurLine = mDirEntry.mHeight;
+      mRow = (PRUint8*)realloc(mRow, rowSize);
+      if (!mRow) {
+        mError = PR_TRUE;
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+    }
+
+    // Ensure memory has been allocated before decoding.
+    NS_ASSERTION(mRow, "mRow is null");
+    NS_ASSERTION(mImageData, "mImageData is null");
+    if (!mRow || !mImageData) {
+      mError = PR_TRUE;
+      return NS_ERROR_FAILURE;
+    }
+
+    while (mCurLine > 0 && aCount > 0) {
+      PRUint32 toCopy = PR_MIN(rowSize - mRowBytes, aCount);
+      if (toCopy) {
+        memcpy(mRow + mRowBytes, aBuffer, toCopy);
+        aCount -= toCopy;
+        aBuffer += toCopy;
+        mRowBytes += toCopy;
+      }
+      if (rowSize == mRowBytes) {
+        mCurLine--;
+        mRowBytes = 0;
+
+        PRUint32* decoded = mImageData + mCurLine * mDirEntry.mWidth;
+        PRUint32* decoded_end = decoded + mDirEntry.mWidth;
+        PRUint8* p = mRow, *p_end = mRow + rowSize; 
+        while (p < p_end) {
+          PRUint8 idx = *p++;
+          for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
+            // Clear pixel completely for transparency.
+            if (idx & bit) *decoded = 0;
+            decoded ++;
+          }
+        }
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+void
+nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
+{
+  memset(&aTarget, 0, sizeof(aTarget));
+  memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
+  memcpy(&aTarget.mHeight, mDirEntryArray+1, sizeof(aTarget.mHeight));
+  memcpy(&aTarget.mColorCount, mDirEntryArray+2, sizeof(aTarget.mColorCount));
+  memcpy(&aTarget.mReserved, mDirEntryArray+3, sizeof(aTarget.mReserved));
+  
+  memcpy(&aTarget.mPlanes, mDirEntryArray+4, sizeof(aTarget.mPlanes));
+  aTarget.mPlanes = LITTLE_TO_NATIVE16(aTarget.mPlanes);
+
+  memcpy(&aTarget.mBitCount, mDirEntryArray+6, sizeof(aTarget.mBitCount));
+  aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);
+
+  memcpy(&aTarget.mBytesInRes, mDirEntryArray+8, sizeof(aTarget.mBytesInRes));
+  aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
+
+  memcpy(&aTarget.mImageOffset, mDirEntryArray+12, sizeof(aTarget.mImageOffset));
+  aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
+}
+
+void nsICODecoder::ProcessInfoHeader() {
+  memset(&mBIH, 0, sizeof(mBIH));
+  // Ignoring the size; it should always be 40 for icons, anyway
+
+  memcpy(&mBIH.width, mBIHraw + 4, sizeof(mBIH.width));
+  memcpy(&mBIH.height, mBIHraw + 8, sizeof(mBIH.height));
+  memcpy(&mBIH.planes, mBIHraw + 12, sizeof(mBIH.planes));
+  memcpy(&mBIH.bpp, mBIHraw + 14, sizeof(mBIH.bpp));
+  memcpy(&mBIH.compression, mBIHraw + 16, sizeof(mBIH.compression));
+  memcpy(&mBIH.image_size, mBIHraw + 20, sizeof(mBIH.image_size));
+  memcpy(&mBIH.xppm, mBIHraw + 24, sizeof(mBIH.xppm));
+  memcpy(&mBIH.yppm, mBIHraw + 28, sizeof(mBIH.yppm));
+  memcpy(&mBIH.colors, mBIHraw + 32, sizeof(mBIH.colors));
+  memcpy(&mBIH.important_colors, mBIHraw + 36, sizeof(mBIH.important_colors));
+
+  // Convert endianness
+  mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
+  mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
+  mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
+  mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
+
+  mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
+  mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
+  mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
+  mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
+  mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
+  mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
+}
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.h
@@ -0,0 +1,128 @@
+/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla ICO Decoder.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Hyatt <hyatt@netscape.com> (Original Author)
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#ifndef _nsICODecoder_h
+#define _nsICODecoder_h
+
+#include "nsAutoPtr.h"
+#include "imgIDecoder.h"
+#include "imgIContainer.h"
+#include "imgIDecoderObserver.h"
+#include "nsBMPDecoder.h"
+
+// {CB3EDE1A-0FA5-4e27-AAFE-0F7801E5A1F1}
+#define NS_ICODECODER_CID \
+{ 0xcb3ede1a, 0xfa5, 0x4e27, { 0xaa, 0xfe, 0xf, 0x78, 0x1, 0xe5, 0xa1, 0xf1 } }
+
+namespace mozilla {
+namespace imagelib {
+class RasterImage;
+} // namespace imagelib
+} // namespace mozilla
+
+struct IconDirEntry
+{
+  PRUint8   mWidth;
+  PRUint8   mHeight;
+  PRUint8   mColorCount;
+  PRUint8   mReserved;
+  union {
+    PRUint16 mPlanes;   // ICO
+    PRUint16 mXHotspot; // CUR
+  };
+  union {
+    PRUint16 mBitCount; // ICO
+    PRUint16 mYHotspot; // CUR
+  };
+  PRUint32  mBytesInRes;
+  PRUint32  mImageOffset;
+};
+
+class nsICODecoder : public imgIDecoder
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGIDECODER
+
+  nsICODecoder();
+  virtual ~nsICODecoder();
+
+private:
+  // Private helper methods
+  void ProcessDirEntry(IconDirEntry& aTarget);
+  void ProcessInfoHeader();
+
+  nsresult SetImageData();
+
+  PRUint32 CalcAlphaRowSize();
+
+private:
+  nsRefPtr<mozilla::imagelib::RasterImage> mImage;
+  nsCOMPtr<imgIDecoderObserver> mObserver;
+  PRUint32 mFlags;
+  
+  PRUint32 mPos;
+  PRUint16 mNumIcons;
+  PRUint16 mCurrIcon;
+  PRUint32 mImageOffset;
+
+  char mDirEntryArray[16];
+  IconDirEntry mDirEntry;
+
+  char mBIHraw[40];
+  BMPINFOHEADER mBIH;
+
+  PRUint32 mNumColors;
+  colorTable* mColors;
+
+  PRUint8* mRow; // Holds one raw line of the image
+  PRUint32 mRowBytes; // How many bytes of the row were already received
+  PRInt32 mCurLine;
+
+  PRUint32* mImageData;
+
+  PRPackedBool mHaveAlphaData;
+  PRPackedBool mIsCursor;
+  PRPackedBool mDecodingAndMask;
+  PRPackedBool mError;
+};
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsIconDecoder.cpp
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Scott MacGregor <mscott@netscape.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIconDecoder.h"
+#include "nsIInputStream.h"
+#include "RasterImage.h"
+#include "imgIContainerObserver.h"
+#include "nspr.h"
+#include "nsIComponentManager.h"
+#include "nsRect.h"
+#include "nsComponentManagerUtils.h"
+
+#include "nsIInterfaceRequestorUtils.h"
+#include "ImageErrors.h"
+
+using namespace mozilla::imagelib;
+
+NS_IMPL_THREADSAFE_ADDREF(nsIconDecoder)
+NS_IMPL_THREADSAFE_RELEASE(nsIconDecoder)
+
+NS_INTERFACE_MAP_BEGIN(nsIconDecoder)
+   NS_INTERFACE_MAP_ENTRY(imgIDecoder)
+NS_INTERFACE_MAP_END_THREADSAFE
+
+
+nsIconDecoder::nsIconDecoder() :
+  mImage(nsnull),
+  mObserver(nsnull),
+  mFlags(imgIDecoder::DECODER_FLAG_NONE),
+  mWidth(-1),
+  mHeight(-1),
+  mPixBytesRead(0),
+  mPixBytesTotal(0),
+  mImageData(nsnull),
+  mState(iconStateStart),
+  mNotifiedDone(PR_FALSE)
+{
+  // Nothing to do
+}
+
+nsIconDecoder::~nsIconDecoder()
+{ }
+
+
+/** imgIDecoder methods **/
+
+NS_IMETHODIMP nsIconDecoder::Init(imgIContainer *aImage,
+                                  imgIDecoderObserver *aObserver,
+                                  PRUint32 aFlags)
+{
+
+  // Grab parameters
+  NS_ABORT_IF_FALSE(aImage->GetType() == imgIContainer::TYPE_RASTER,
+                    "wrong type of imgIContainer for decoding into");
+
+  mImage = static_cast<RasterImage*>(aImage);
+  mObserver = aObserver;
+  mFlags = aFlags;
+
+  // Fire OnStartDecode at init time to support bug 512435
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
+    mObserver->OnStartDecode(nsnull);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsIconDecoder::Close(PRUint32 aFlags)
+{
+  // If we haven't notified of completion yet for a full/success decode, we
+  // didn't finish. Notify in error mode
+  if (!(aFlags & CLOSE_FLAG_DONTNOTIFY) &&
+      !(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
+      !mNotifiedDone)
+    NotifyDone(/* aSuccess = */ PR_FALSE);
+
+  mImage = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsIconDecoder::Flush()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsIconDecoder::Write(const char *aBuffer, PRUint32 aCount)
+{
+  nsresult rv;
+
+  // We put this here to avoid errors about crossing initialization with case
+  // jumps on linux.
+  PRUint32 bytesToRead = 0;
+
+  // Performance isn't critical here, so our update rectangle is 
+  // always the full icon
+  nsIntRect r(0, 0, mWidth, mHeight);
+
+  // Loop until the input data is gone
+  while (aCount > 0) {
+    switch (mState) {
+      case iconStateStart:
+
+        // Grab the width
+        mWidth = (PRUint8)*aBuffer;
+
+        // Book Keeping
+        aBuffer++;
+        aCount--;
+        mState = iconStateHaveHeight;
+        break;
+
+      case iconStateHaveHeight:
+
+        // Grab the Height
+        mHeight = (PRUint8)*aBuffer;
+
+        // Set up the container and signal
+        mImage->SetSize(mWidth, mHeight);
+        if (mObserver)
+          mObserver->OnStartContainer(nsnull, mImage);
+
+        // If We're doing a header-only decode, we're done
+        if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) {
+          mState = iconStateFinished;
+          break;
+        }
+
+        // Add the frame and signal
+        rv = mImage->AppendFrame(0, 0, mWidth, mHeight,
+                                 gfxASurface::ImageFormatARGB32,
+                                 &mImageData, &mPixBytesTotal);
+        if (NS_FAILED(rv)) {
+          mState = iconStateError;
+          return rv;
+        }
+        if (mObserver)
+         mObserver->OnStartFrame(nsnull, 0);
+
+        // Book Keeping
+        aBuffer++;
+        aCount--;
+        mState = iconStateReadPixels;
+        break;
+
+      case iconStateReadPixels:
+
+        // How many bytes are we reading?
+        bytesToRead = PR_MIN(aCount, mPixBytesTotal - mPixBytesRead);
+
+        // Copy the bytes
+        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);
+
+        // Notify
+        rv = mImage->FrameUpdated(0, r);
+        if (NS_FAILED(rv)) {
+          mState = iconStateError;
+          return rv;
+        }
+        if (mObserver)
+          mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
+
+        // Book Keeping
+        aBuffer += bytesToRead;
+        aCount -= bytesToRead;
+        mPixBytesRead += bytesToRead;
+
+        // If we've got all the pixel bytes, we're finished
+        if (mPixBytesRead == mPixBytesTotal) {
+          NotifyDone(/* aSuccess = */ PR_TRUE);
+          mState = iconStateFinished;
+        }
+        break;
+
+      case iconStateFinished:
+
+        // Consume all excess data silently
+        aCount = 0;
+
+        break;
+
+      case iconStateError:
+        return NS_IMAGELIB_ERROR_FAILURE;
+        break;
+    }
+  }
+
+  return NS_OK;
+}
+
+void
+nsIconDecoder::NotifyDone(PRBool aSuccess)
+{
+  // We should only call this once
+  NS_ABORT_IF_FALSE(!mNotifiedDone, "Calling NotifyDone twice");
+
+  // Notify
+  if (mObserver)
+    mObserver->OnStopFrame(nsnull, 0);
+  if (aSuccess)
+    mImage->DecodingComplete();
+  if (mObserver) {
+    mObserver->OnStopContainer(nsnull, mImage);
+    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
+                            nsnull);
+  }
+
+  // Flag that we've notified
+  mNotifiedDone = PR_TRUE;
+}
+
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/bmp/nsIconDecoder.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Scott MacGregor <mscott@netscape.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsIconDecoder_h__
+#define nsIconDecoder_h__
+
+#include "imgIDecoder.h"
+
+#include "nsCOMPtr.h"
+
+#include "imgIContainer.h"
+#include "imgIDecoderObserver.h"
+
+#define NS_ICONDECODER_CID                           \
+{ /* FFC08380-256C-11d5-9905-001083010E9B */         \
+     0xffc08380,                                     \
+     0x256c,                                         \
+     0x11d5,                                         \
+    { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b }   \
+}
+
+namespace mozilla {
+namespace imagelib {
+class RasterImage;
+} // namespace imagelib
+} // namespace mozilla
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// The icon decoder is a decoder specifically tailored for loading icons 
+// from the OS. We've defined our own little format to represent these icons
+// and this decoder takes that format and converts it into 24-bit RGB with alpha channel
+// support. It was modeled a bit off the PPM decoder.
+//
+// Assumptions about the decoder:
+// (1) We receive ALL of the data from the icon channel in one OnDataAvailable call. We don't
+//     support multiple ODA calls yet.
+// (2) the format of the incoming data is as follows:
+//     The first two bytes contain the width and the height of the icon. 
+//     The remaining bytes contain the icon data, 4 bytes per pixel, in
+//       ARGB order (platform endianness, A in highest bits, B in lowest
+//       bits), row-primary, top-to-bottom, left-to-right, with
+//       premultiplied alpha.
+//
+//
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+class nsIconDecoder : public imgIDecoder
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGIDECODER
+
+  nsIconDecoder();
+  virtual ~nsIconDecoder();
+
+  nsRefPtr<mozilla::imagelib::RasterImage> mImage;
+  nsCOMPtr<imgIDecoderObserver> mObserver;
+  PRUint32 mFlags;
+  PRUint8 mWidth;
+  PRUint8 mHeight;
+  PRUint32 mPixBytesRead;
+  PRUint32 mPixBytesTotal;
+  PRUint8* mImageData;
+  PRUint32 mState;
+
+  PRBool mNotifiedDone;
+  void NotifyDone(PRBool aSuccess);
+};
+
+enum {
+  iconStateStart      = 0,
+  iconStateHaveHeight = 1,
+  iconStateReadPixels = 2,
+  iconStateFinished   = 3,
+  iconStateError      = 4
+};
+
+
+#endif // nsIconDecoder_h__
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/gif/GIF2.h
@@ -0,0 +1,139 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef _GIF_H_
+#define _GIF_H_
+
+#define MAX_LZW_BITS          12
+#define MAX_BITS            4097 /* 2^MAX_LZW_BITS+1 */
+#define MAX_COLORS           256
+#define MAX_HOLD_SIZE        256
+
+enum { GIF_TRAILER                     = 0x3B }; //';'
+enum { GIF_IMAGE_SEPARATOR             = 0x2C }; //','
+enum { GIF_EXTENSION_INTRODUCER        = 0x21 }; //'!'
+enum { GIF_GRAPHIC_CONTROL_LABEL       = 0xF9 };
+enum { GIF_COMMENT_LABEL               = 0xFE };
+enum { GIF_PLAIN_TEXT_LABEL            = 0x01 };
+enum { GIF_APPLICATION_EXTENSION_LABEL = 0xFF };
+
+/* gif2.h  
+   The interface for the GIF87/89a decoder. 
+*/
+// List of possible parsing states
+typedef enum {
+    gif_type,
+    gif_global_header,
+    gif_global_colormap,
+    gif_image_start,
+    gif_image_header,
+    gif_image_colormap,
+    gif_image_body,
+    gif_lzw_start,
+    gif_lzw,
+    gif_sub_block,
+    gif_extension,
+    gif_control_extension,
+    gif_consume_block,
+    gif_skip_block,
+    gif_done,
+    gif_oom,
+    gif_error,
+    gif_comment_extension,
+    gif_application_extension,
+    gif_netscape_extension_block,
+    gif_consume_netscape_extension,
+    gif_consume_comment
+} gstate;
+
+/* A GIF decoder's state */
+typedef struct gif_struct {
+    /* Parsing state machine */
+    gstate state;                   /* Curent decoder master state */
+    PRUint32 bytes_to_consume;      /* Number of bytes to accumulate */
+    PRUint32 bytes_in_hold;         /* bytes accumulated so far*/
+
+    /* LZW decoder state machine */
+    PRUint8 *stackp;              /* Current stack pointer */
+    int datasize;
+    int codesize;
+    int codemask;
+    int avail;                  /* Index of next available slot in dictionary */
+    int oldcode;
+    PRUint8 firstchar;
+    int count;                  /* Remaining # bytes in sub-block */
+    int bits;                   /* Number of unread bits in "datum" */
+    int32 datum;                /* 32-bit input buffer */
+
+    /* Output state machine */
+    int ipass;                  /* Interlace pass; Ranges 1-4 if interlaced. */
+    PRUintn rows_remaining;        /* Rows remaining to be output */
+    PRUintn irow;                  /* Current output row, starting at zero */
+    PRUint8 *rowp;                 /* Current output pointer */
+
+    /* Parameters for image frame currently being decoded*/
+    PRUintn x_offset, y_offset;    /* With respect to "screen" origin */
+    PRUintn height, width;
+    int tpixel;                 /* Index of transparent pixel */
+    PRInt32 disposal_method;    /* Restore to background, leave in place, etc.*/
+    PRUint32 *local_colormap;   /* Per-image colormap */
+    int local_colormap_size;    /* Size of local colormap array. */
+    PRUint32 delay_time;        /* Display time, in milliseconds,
+                                   for this image in a multi-image GIF */
+
+    /* Global (multi-image) state */
+    int version;                /* Either 89 for GIF89 or 87 for GIF87 */
+    PRUintn screen_width;       /* Logical screen width & height */
+    PRUintn screen_height;
+    PRUint32 global_colormap_depth;  /* Depth of global colormap array. */
+    int images_decoded;         /* Counts images for multi-part GIFs */
+    int loop_count;             /* Netscape specific extension block to control
+                                   the number of animation loops a GIF renders. */
+
+    PRPackedBool progressive_display;    /* If TRUE, do Haeberli interlace hack */
+    PRPackedBool interlaced;             /* TRUE, if scanlines arrive interlaced order */
+    PRPackedBool is_transparent;         /* TRUE, if tpixel is valid */
+
+    PRUint16  prefix[MAX_BITS];          /* LZW decoding tables */
+    PRUint8   hold[MAX_HOLD_SIZE];       /* Accumulation buffer */
+    PRUint32  global_colormap[MAX_COLORS];   /* Default colormap if local not supplied */
+    PRUint8   suffix[MAX_BITS];          /* LZW decoding tables */
+    PRUint8   stack[MAX_BITS];           /* Base of LZW decoder stack */
+
+} gif_struct;
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/gif/Makefile.in
@@ -0,0 +1,59 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= imggif
+LIBRARY_NAME	= imggif_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME	= nsGIFModule2
+LIBXUL_LIBRARY = 1
+
+
+CPPSRCS		= nsGIFDecoder2.cpp
+
+# nsGIFDecoder2.cpp includes RasterImage.h
+LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src
+
+include $(topsrcdir)/config/rules.mk
+
+CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
@@ -0,0 +1,1239 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Saari <saari@netscape.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+The Graphics Interchange Format(c) is the copyright property of CompuServe
+Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
+enhance, alter, modify or change in any way the definition of the format.
+
+CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
+license for the use of the Graphics Interchange Format(sm) in computer
+software; computer software utilizing GIF(sm) must acknowledge ownership of the
+Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
+User and Technical Documentation. Computer software utilizing GIF, which is
+distributed or may be distributed without User or Technical Documentation must
+display to the screen or printer a message acknowledging ownership of the
+Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
+this case, the acknowledgement may be displayed in an opening screen or leading
+banner, or a closing screen or trailing banner. A message such as the following
+may be used:
+
+    "The Graphics Interchange Format(c) is the Copyright property of
+    CompuServe Incorporated. GIF(sm) is a Service Mark property of
+    CompuServe Incorporated."
+
+For further information, please contact :
+
+    CompuServe Incorporated
+    Graphics Technology Department
+    5000 Arlington Center Boulevard
+    Columbus, Ohio  43220
+    U. S. A.
+
+CompuServe Incorporated maintains a mailing list with all those individuals and
+organizations who wish to receive copies of this document when it is corrected
+or revised. This service is offered free of charge; please provide us with your
+mailing address.
+*/
+
+#include <stddef.h>
+#include "prmem.h"
+
+#include "nsIInterfaceRequestorUtils.h"
+
+#include "nsGIFDecoder2.h"
+#include "nsIInputStream.h"
+#include "nsIComponentManager.h"
+#include "imgIContainerObserver.h"
+#include "RasterImage.h"
+
+#include "gfxColor.h"
+#include "gfxPlatform.h"
+#include "qcms.h"
+
+/*
+ * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
+ *
+ * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
+ * as each GIF block (except colormaps) can never be bigger than 256 bytes.
+ * Colormaps are directly copied in the resp. global_colormap or the local_colormap of the PAL image frame
+ * So a fixed buffer in gif_struct is good enough.
+ * This buffer is only needed to copy left-over data from one GifWrite call to the next
+ */
+#define GETN(n,s)                      \
+  PR_BEGIN_MACRO                       \
+    mGIFStruct.bytes_to_consume = (n); \
+    mGIFStruct.state = (s);            \
+  PR_END_MACRO
+
+/* Get a 16-bit value stored in little-endian format */
+#define GETINT16(p)   ((p)[1]<<8|(p)[0])
+
+
+//////////////////////////////////////////////////////////////////////
+// GIF Decoder Implementation
+// This is an adaptor between GIF2 and imgIDecoder
+
+NS_IMPL_ISUPPORTS1(nsGIFDecoder2, imgIDecoder)
+
+nsGIFDecoder2::nsGIFDecoder2()
+  : mCurrentRow(-1)
+  , mLastFlushedRow(-1)
+  , mImageData(nsnull)
+  , mOldColor(0)
+  , mCurrentFrame(-1)
+  , mCurrentPass(0)
+  , mLastFlushedPass(0)
+  , mGIFOpen(PR_FALSE)
+  , mSawTransparency(PR_FALSE)
+  , mError(PR_FALSE)
+  , mEnded(PR_FALSE)
+{
+  // Clear out the structure, excluding the arrays
+  memset(&mGIFStruct, 0, sizeof(mGIFStruct));
+}
+
+nsGIFDecoder2::~nsGIFDecoder2()
+{
+}
+
+//******************************************************************************
+/** imgIDecoder methods **/
+//******************************************************************************
+
+//******************************************************************************
+/* void init (in imgIContainer aImage,
+              in imgIDecoderObserver aObsever,
+              in unsigned long aFlags); */
+NS_IMETHODIMP nsGIFDecoder2::Init(imgIContainer *aImage,
+                                  imgIDecoderObserver *aObserver,
+                                  PRUint32 aFlags)
+{
+  NS_ABORT_IF_FALSE(aImage->GetType() == imgIContainer::TYPE_RASTER,
+                    "wrong type of imgIContainer for decoding into");
+
+  // Store parameters
+  mImageContainer = static_cast<mozilla::imagelib::RasterImage*>(aImage);
+  mObserver = aObserver;
+  mFlags = aFlags;
+
+  // Fire OnStartDecode at init time to support bug 512435
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
+    mObserver->OnStartDecode(nsnull);
+
+  // Start with the version (GIF89a|GIF87a)
+  mGIFStruct.state = gif_type;
+  mGIFStruct.bytes_to_consume = 6;
+
+  return NS_OK;
+}
+
+
+//******************************************************************************
+/** nsIOutputStream methods **/
+//******************************************************************************
+
+//******************************************************************************
+/* void close (); */
+NS_IMETHODIMP nsGIFDecoder2::Close(PRUint32 aFlags)
+{
+  // Send notifications if appropriate
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
+      !mError && !(aFlags & CLOSE_FLAG_DONTNOTIFY)) {
+    if (mCurrentFrame == mGIFStruct.images_decoded)
+      EndImageFrame();
+    EndGIF(/* aSuccess = */ PR_TRUE);
+  }
+
+  PR_FREEIF(mGIFStruct.local_colormap);
+
+  mImageContainer = nsnull;
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* void flush (); */
+NS_IMETHODIMP nsGIFDecoder2::Flush()
+{
+    return NS_OK;
+}
+
+// Push any new rows according to mCurrentPass/mLastFlushedPass and
+// mCurrentRow/mLastFlushedRow.  Note: caller is responsible for
+// updating mlastFlushed{Row,Pass}.
+nsresult
+nsGIFDecoder2::FlushImageData(PRUint32 fromRow, PRUint32 rows)
+{
+  nsIntRect r(mGIFStruct.x_offset, mGIFStruct.y_offset + fromRow, mGIFStruct.width, rows);
+
+  // Update image  
+  nsresult rv = mImageContainer->FrameUpdated(mGIFStruct.images_decoded, r);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Offset to the frame position
+  // Only notify observer(s) for first frame
+  if (!mGIFStruct.images_decoded && mObserver) {
+    PRUint32 imgCurFrame;
+    mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
+    mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
+  }
+  return NS_OK;
+}
+
+nsresult
+nsGIFDecoder2::FlushImageData()
+{
+  nsresult rv = NS_OK;
+
+  switch (mCurrentPass - mLastFlushedPass) {
+    case 0:  // same pass
+      if (mCurrentRow - mLastFlushedRow)
+        rv = FlushImageData(mLastFlushedRow + 1, mCurrentRow - mLastFlushedRow);
+      break;
+  
+    case 1:  // one pass on - need to handle bottom & top rects
+      rv = FlushImageData(0, mCurrentRow + 1);
+      rv |= FlushImageData(mLastFlushedRow + 1, mGIFStruct.height - (mLastFlushedRow + 1));
+      break;
+
+    default:   // more than one pass on - push the whole frame
+      rv = FlushImageData(0, mGIFStruct.height);
+  }
+  return rv;
+}
+
+//******************************************************************************
+/* void write (in string aBuffer, in PRUint32 aCount); */
+NS_IMETHODIMP
+nsGIFDecoder2::Write(const char *aBuffer, PRUint32 aCount)
+{
+  // Don't forgive previously flagged errors
+  if (mError)
+    return NS_ERROR_FAILURE;
+
+  // Push the data to the GIF decoder
+  nsresult rv = GifWrite((const unsigned char *)aBuffer, aCount);
+
+  // Flushing is only needed for first frame
+  if (NS_SUCCEEDED(rv) && !mGIFStruct.images_decoded) {
+    rv = FlushImageData();
+    NS_ENSURE_SUCCESS(rv, rv);
+    mLastFlushedRow = mCurrentRow;
+    mLastFlushedPass = mCurrentPass;
+  }
+
+  // We do some fine-grained error control here. If we have at least one frame
+  // of an animated gif, we still want to display it (mostly for legacy reasons).
+  // libpr0n code is strict, so we have to lie and tell it we were successful. So
+  // if we have something to salvage, we send off final decode notifications, and
+  // pretend that we're decoded. Otherwise, we set mError.
+  if (NS_FAILED(rv)) {
+
+    // Determine if we want to salvage the situation
+    PRUint32 numFrames = 0;
+    if (mImageContainer)
+      mImageContainer->GetNumFrames(&numFrames);
+
+    // If we're salvaging, send off notifications
+    // Note that we need to make sure that we have 2 frames, since that tells us
+    // that the first frame is complete (the second could be in any state).
+    if (numFrames > 1) {
+      EndGIF(/* aSuccess = */ PR_TRUE);
+    }
+
+    // Otherwise, set mError
+    else
+      mError = PR_TRUE;
+  }
+
+  return mError ? NS_ERROR_FAILURE : NS_OK;
+}
+
+//******************************************************************************
+// GIF decoder callback methods. Part of public API for GIF2
+//******************************************************************************
+
+//******************************************************************************
+void nsGIFDecoder2::BeginGIF()
+{
+  if (mGIFOpen)
+    return;
+
+  mGIFOpen = PR_TRUE;
+
+  mImageContainer->SetSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
+  if (mObserver)
+    mObserver->OnStartContainer(nsnull, mImageContainer);
+
+  // If we're doing a header-only decode, we have what we came for
+  if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
+    return;
+}
+
+//******************************************************************************
+void nsGIFDecoder2::EndGIF(PRBool aSuccess)
+{
+  if (mEnded)
+    return;
+
+  if (aSuccess)
+    mImageContainer->DecodingComplete();
+
+  if (mObserver) {
+    mObserver->OnStopContainer(nsnull, mImageContainer);
+    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
+                            nsnull);
+  }
+
+  mImageContainer->SetLoopCount(mGIFStruct.loop_count);
+
+  mGIFOpen = PR_FALSE;
+  mEnded = PR_TRUE;
+}
+
+//******************************************************************************
+nsresult nsGIFDecoder2::BeginImageFrame(gfx_depth aDepth)
+{
+  if (!mGIFStruct.images_decoded) {
+    // Send a onetime OnDataAvailable (Display Refresh) for the first frame
+    // if it has a y-axis offset.  Otherwise, the area may never be refreshed
+    // and the placeholder will remain on the screen. (Bug 37589)
+    if (mGIFStruct.y_offset > 0) {
+      PRInt32 imgWidth;
+      mImageContainer->GetWidth(&imgWidth);
+      PRUint32 imgCurFrame;
+      mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
+      nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset);
+      if (mObserver)
+        mObserver->OnDataAvailable(nsnull,
+                                   imgCurFrame == PRUint32(mGIFStruct.images_decoded),
+                                   &r);
+    }
+  }
+
+  PRUint32 imageDataLength;
+  nsresult rv;
+  gfxASurface::gfxImageFormat format;
+  if (mGIFStruct.is_transparent)
+    format = gfxASurface::ImageFormatARGB32;
+  else
+    format = gfxASurface::ImageFormatRGB24;
+
+  // Use correct format, RGB for first frame, PAL for following frames
+  // and include transparency to allow for optimization of opaque images
+  if (mGIFStruct.images_decoded) {
+    // Image data is stored with original depth and palette
+    rv = mImageContainer->AppendPalettedFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
+                                              mGIFStruct.width, mGIFStruct.height,
+                                              format, aDepth, &mImageData, &imageDataLength,
+                                              &mColormap, &mColormapSize);
+  } else {
+    // Regardless of depth of input, image is decoded into 24bit RGB
+    rv = mImageContainer->AppendFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
+                                      mGIFStruct.width, mGIFStruct.height,
+                                      format, &mImageData, &imageDataLength);
+  }
+
+  if (NS_FAILED(rv))
+    return rv;
+
+  mImageContainer->SetFrameDisposalMethod(mGIFStruct.images_decoded,
+                                          mGIFStruct.disposal_method);
+
+  if (mObserver)
+    mObserver->OnStartFrame(nsnull, mGIFStruct.images_decoded);
+
+  mCurrentFrame = mGIFStruct.images_decoded;
+  return NS_OK;
+}
+
+
+//******************************************************************************
+void nsGIFDecoder2::EndImageFrame()
+{
+  // First flush all pending image data 
+  if (!mGIFStruct.images_decoded) {
+    // Only need to flush first frame
+    (void) FlushImageData();
+
+    // If the first frame is smaller in height than the entire image, send a
+    // OnDataAvailable (Display Refresh) for the area it does not have data for.
+    // This will clear the remaining bits of the placeholder. (Bug 37589)
+    const PRUint32 realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
+    if (realFrameHeight < mGIFStruct.screen_height) {
+      PRUint32 imgCurFrame;
+      mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
+      nsIntRect r(0, realFrameHeight,
+                  mGIFStruct.screen_width,
+                  mGIFStruct.screen_height - realFrameHeight);
+      if (mObserver)
+        mObserver->OnDataAvailable(nsnull,
+                                  imgCurFrame == PRUint32(mGIFStruct.images_decoded),
+                                  &r);
+    }
+    // This transparency check is only valid for first frame
+    if (mGIFStruct.is_transparent && !mSawTransparency) {
+      mImageContainer->SetFrameHasNoAlpha(mGIFStruct.images_decoded);
+    }
+  }
+  mCurrentRow = mLastFlushedRow = -1;
+  mCurrentPass = mLastFlushedPass = 0;
+
+  PRUint32 curframe = mGIFStruct.images_decoded;
+
+  // Only add frame if we have any rows at all
+  if (mGIFStruct.rows_remaining != mGIFStruct.height) {
+    if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
+      // Clear the remaining rows (only needed for the animation frames)
+      PRUint8 *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
+      memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
+    }
+
+    // We actually have the timeout information before we get the lzw encoded 
+    // image data, at least according to the spec, but we delay in setting the 
+    // timeout for the image until here to help ensure that we have the whole 
+    // image frame decoded before we go off and try to display another frame.
+    mImageContainer->SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time);
+    mImageContainer->EndFrameDecode(mGIFStruct.images_decoded);
+  }
+
+  // Unconditionally increment images_decoded, because we unconditionally
+  // append frames in BeginImageFrame(). This ensures that images_decoded
+  // always refers to the frame in mImageContainer we're currently decoding,
+  // even if some of them weren't decoded properly and thus are blank.
+  mGIFStruct.images_decoded++;
+
+  if (mObserver)
+    mObserver->OnStopFrame(nsnull, curframe);
+
+  // Reset the transparent pixel
+  if (mOldColor) {
+    mColormap[mGIFStruct.tpixel] = mOldColor;
+    mOldColor = 0;
+  }
+
+  mCurrentFrame = -1;
+}
+
+
+//******************************************************************************
+// Send the data to the display front-end.
+PRUint32 nsGIFDecoder2::OutputRow()
+{
+  int drow_start, drow_end;
+  drow_start = drow_end = mGIFStruct.irow;
+
+  /* Protect against too much image data */
+  if ((PRUintn)drow_start >= mGIFStruct.height) {
+    NS_WARNING("GIF2.cpp::OutputRow - too much image data");
+    return 0;
+  }
+
+  if (!mGIFStruct.images_decoded) {
+    /*
+     * Haeberli-inspired hack for interlaced GIFs: Replicate lines while
+     * displaying to diminish the "venetian-blind" effect as the image is
+     * loaded. Adjust pixel vertical positions to avoid the appearance of the
+     * image crawling up the screen as successive passes are drawn.
+     */
+    if (mGIFStruct.progressive_display && mGIFStruct.interlaced && (mGIFStruct.ipass < 4)) {
+      /* ipass = 1,2,3 results in resp. row_dup = 7,3,1 and row_shift = 3,1,0 */
+      const PRUint32 row_dup = 15 >> mGIFStruct.ipass;
+      const PRUint32 row_shift = row_dup >> 1;
+  
+      drow_start -= row_shift;
+      drow_end = drow_start + row_dup;
+  
+      /* Extend if bottom edge isn't covered because of the shift upward. */
+      if (((mGIFStruct.height - 1) - drow_end) <= row_shift)
+        drow_end = mGIFStruct.height - 1;
+  
+      /* Clamp first and last rows to upper and lower edge of image. */
+      if (drow_start < 0)
+        drow_start = 0;
+      if ((PRUintn)drow_end >= mGIFStruct.height)
+        drow_end = mGIFStruct.height - 1;
+    }
+
+    // Row to process
+    const PRUint32 bpr = sizeof(PRUint32) * mGIFStruct.width; 
+    PRUint8 *rowp = mImageData + (mGIFStruct.irow * bpr);
+
+    // Convert color indices to Cairo pixels
+    PRUint8 *from = rowp + mGIFStruct.width;
+    PRUint32 *to = ((PRUint32*)rowp) + mGIFStruct.width;
+    PRUint32 *cmap = mColormap;
+    if (mColorMask == 0xFF) {
+      for (PRUint32 c = mGIFStruct.width; c > 0; c--) {
+        *--to = cmap[*--from];
+      }
+    } else {
+      // Make sure that pixels within range of colormap.
+      PRUint8 mask = mColorMask;
+      for (PRUint32 c = mGIFStruct.width; c > 0; c--) {
+        *--to = cmap[(*--from) & mask];
+      }
+    }
+  
+    // check for alpha (only for first frame)
+    if (mGIFStruct.is_transparent && !mSawTransparency) {
+      const PRUint32 *rgb = (PRUint32*)rowp;
+      for (PRUint32 i = mGIFStruct.width; i > 0; i--) {
+        if (*rgb++ == 0) {
+          mSawTransparency = PR_TRUE;
+          break;
+        }
+      }
+    }
+
+    // Duplicate rows
+    if (drow_end > drow_start) {
+      // irow is the current row filled
+      for (int r = drow_start; r <= drow_end; r++) {
+        if (r != int(mGIFStruct.irow)) {
+          memcpy(mImageData + (r * bpr), rowp, bpr);
+        }
+      }
+    }
+  }
+
+  mCurrentRow = drow_end;
+  mCurrentPass = mGIFStruct.ipass;
+  if (mGIFStruct.ipass == 1)
+    mLastFlushedPass = mGIFStruct.ipass;   // interlaced starts at 1
+
+  if (!mGIFStruct.interlaced) {
+    mGIFStruct.irow++;
+  } else {
+    static const PRUint8 kjump[5] = { 1, 8, 8, 4, 2 };
+    do {
+      // Row increments resp. per 8,8,4,2 rows
+      mGIFStruct.irow += kjump[mGIFStruct.ipass];
+      if (mGIFStruct.irow >= mGIFStruct.height) {
+        // Next pass starts resp. at row 4,2,1,0
+        mGIFStruct.irow = 8 >> mGIFStruct.ipass;
+        mGIFStruct.ipass++;
+      }
+    } while (mGIFStruct.irow >= mGIFStruct.height);
+  }
+
+  return --mGIFStruct.rows_remaining;
+}
+
+//******************************************************************************
+/* Perform Lempel-Ziv-Welch decoding */
+PRBool
+nsGIFDecoder2::DoLzw(const PRUint8 *q)
+{
+  if (!mGIFStruct.rows_remaining)
+    return PR_TRUE;
+
+  /* Copy all the decoder state variables into locals so the compiler
+   * won't worry about them being aliased.  The locals will be homed
+   * back into the GIF decoder structure when we exit.
+   */
+  int avail       = mGIFStruct.avail;
+  int bits        = mGIFStruct.bits;
+  int codesize    = mGIFStruct.codesize;
+  int codemask    = mGIFStruct.codemask;
+  int count       = mGIFStruct.count;
+  int oldcode     = mGIFStruct.oldcode;
+  const int clear_code = ClearCode();
+  PRUint8 firstchar = mGIFStruct.firstchar;
+  PRInt32 datum     = mGIFStruct.datum;
+  PRUint16 *prefix  = mGIFStruct.prefix;
+  PRUint8 *stackp   = mGIFStruct.stackp;
+  PRUint8 *suffix   = mGIFStruct.suffix;
+  PRUint8 *stack    = mGIFStruct.stack;
+  PRUint8 *rowp     = mGIFStruct.rowp;
+
+  PRUint32 bpr = mGIFStruct.width;
+  if (!mGIFStruct.images_decoded) 
+    bpr *= sizeof(PRUint32);
+  PRUint8 *rowend   = mImageData + (bpr * mGIFStruct.irow) + mGIFStruct.width;
+
+#define OUTPUT_ROW()                                        \
+  PR_BEGIN_MACRO                                            \
+    if (!OutputRow())                                       \
+      goto END;                                             \
+    rowp = mImageData + mGIFStruct.irow * bpr;              \
+    rowend = rowp + mGIFStruct.width;                       \
+  PR_END_MACRO
+
+  for (const PRUint8* ch = q; count-- > 0; ch++)
+  {
+    /* Feed the next byte into the decoder's 32-bit input buffer. */
+    datum += ((int32) *ch) << bits;
+    bits += 8;
+
+    /* Check for underflow of decoder's 32-bit input buffer. */
+    while (bits >= codesize)
+    {
+      /* Get the leading variable-length symbol from the data stream */
+      int code = datum & codemask;
+      datum >>= codesize;
+      bits -= codesize;
+
+      /* Reset the dictionary to its original state, if requested */
+      if (code == clear_code) {
+        codesize = mGIFStruct.datasize + 1;
+        codemask = (1 << codesize) - 1;
+        avail = clear_code + 2;
+        oldcode = -1;
+        continue;
+      }
+
+      /* Check for explicit end-of-stream code */
+      if (code == (clear_code + 1)) {
+        /* end-of-stream should only appear after all image data */
+        return (mGIFStruct.rows_remaining == 0);
+      }
+
+      if (oldcode == -1) {
+        if (code >= MAX_BITS)
+          return PR_FALSE;
+        *rowp++ = suffix[code];
+        if (rowp == rowend)
+          OUTPUT_ROW();
+
+        firstchar = oldcode = code;
+        continue;
+      }
+
+      int incode = code;
+      if (code >= avail) {
+        *stackp++ = firstchar;
+        code = oldcode;
+
+        if (stackp >= stack + MAX_BITS)
+          return PR_FALSE;
+      }
+
+      while (code >= clear_code)
+      {
+        if ((code >= MAX_BITS) || (code == prefix[code]))
+          return PR_FALSE;
+
+        *stackp++ = suffix[code];
+        code = prefix[code];
+
+        if (stackp == stack + MAX_BITS)
+          return PR_FALSE;
+      }
+
+      *stackp++ = firstchar = suffix[code];
+
+      /* Define a new codeword in the dictionary. */
+      if (avail < 4096) {
+        prefix[avail] = oldcode;
+        suffix[avail] = firstchar;
+        avail++;
+
+        /* If we've used up all the codewords of a given length
+         * increase the length of codewords by one bit, but don't
+         * exceed the specified maximum codeword size of 12 bits.
+         */
+        if (((avail & codemask) == 0) && (avail < 4096)) {
+          codesize++;
+          codemask += avail;
+        }
+      }
+      oldcode = incode;
+
+      /* Copy the decoded data out to the scanline buffer. */
+      do {
+        *rowp++ = *--stackp;
+        if (rowp == rowend)
+          OUTPUT_ROW();
+      } while (stackp > stack);
+    }
+  }
+
+  END:
+
+  /* Home the local copies of the GIF decoder state variables */
+  mGIFStruct.avail = avail;
+  mGIFStruct.bits = bits;
+  mGIFStruct.codesize = codesize;
+  mGIFStruct.codemask = codemask;
+  mGIFStruct.count = count;
+  mGIFStruct.oldcode = oldcode;
+  mGIFStruct.firstchar = firstchar;
+  mGIFStruct.datum = datum;
+  mGIFStruct.stackp = stackp;
+  mGIFStruct.rowp = rowp;
+
+  return PR_TRUE;
+}
+
+/** 
+ * Expand the colormap from RGB to Packed ARGB as needed by Cairo.
+ * And apply any LCMS transformation.
+ */
+static void ConvertColormap(PRUint32 *aColormap, PRUint32 aColors)
+{
+  // Apply CMS transformation if enabled and available
+  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+    qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
+    if (transform)
+      qcms_transform_data(transform, aColormap, aColormap, aColors);
+  }
+  // Convert from the GIF's RGB format to the Cairo format.
+  // Work from end to begin, because of the in-place expansion
+  PRUint8 *from = ((PRUint8 *)aColormap) + 3 * aColors;
+  PRUint32 *to = aColormap + aColors;
+
+  // Convert color entries to Cairo format
+
+  // set up for loops below
+  if (!aColors) return;
+  PRUint32 c = aColors;
+
+  // copy as bytes until source pointer is 32-bit-aligned
+  // NB: can't use 32-bit reads, they might read off the end of the buffer
+  for (; (NS_PTR_TO_UINT32(from) & 0x3) && c; --c) {
+    from -= 3;
+    *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
+  }
+
+  // bulk copy of pixels.
+  while (c >= 4) {
+    from -= 12;
+    to   -=  4;
+    c    -=  4;
+    GFX_BLOCK_RGB_TO_FRGB(from,to);
+  }
+
+  // copy remaining pixel(s)
+  // NB: can't use 32-bit reads, they might read off the end of the buffer
+  while (c--) {
+    from -= 3;
+    *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
+  }
+}
+
+/******************************************************************************/
+/*
+ * process data arriving from the stream for the gif decoder
+ */
+
+nsresult nsGIFDecoder2::GifWrite(const PRUint8 *buf, PRUint32 len)
+{
+  if (!buf || !len)
+    return NS_ERROR_FAILURE;
+
+  const PRUint8 *q = buf;
+
+  // Add what we have sofar to the block
+  // If previous call to me left something in the hold first complete current block
+  // Or if we are filling the colormaps, first complete the colormap
+  PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
+               (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
+               (mGIFStruct.bytes_in_hold) ? mGIFStruct.hold : nsnull;
+  if (p) {
+    // Add what we have sofar to the block
+    PRUint32 l = PR_MIN(len, mGIFStruct.bytes_to_consume);
+    memcpy(p+mGIFStruct.bytes_in_hold, buf, l);
+
+    if (l < mGIFStruct.bytes_to_consume) {
+      // Not enough in 'buf' to complete current block, get more
+      mGIFStruct.bytes_in_hold += l;
+      mGIFStruct.bytes_to_consume -= l;
+      return NS_OK;
+    }
+    // Reset hold buffer count
+    mGIFStruct.bytes_in_hold = 0;
+    // Point 'q' to complete block in hold (or in colormap)
+    q = p;
+  }
+
+  // Invariant:
+  //    'q' is start of current to be processed block (hold, colormap or buf)
+  //    'bytes_to_consume' is number of bytes to consume from 'buf'
+  //    'buf' points to the bytes to be consumed from the input buffer
+  //    'len' is number of bytes left in input buffer from position 'buf'.
+  //    At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
+  //    to point to next buffer, 'len' is adjusted accordingly.
+  //    So that next round in for loop, q gets pointed to the next buffer.
+
+  for (;len >= mGIFStruct.bytes_to_consume; q=buf) {
+    // Eat the current block from the buffer, q keeps pointed at current block
+    buf += mGIFStruct.bytes_to_consume;
+    len -= mGIFStruct.bytes_to_consume;
+
+    switch (mGIFStruct.state)
+    {
+    case gif_lzw:
+      if (!DoLzw(q)) {
+        mGIFStruct.state = gif_error;
+        break;
+      }
+      GETN(1, gif_sub_block);
+      break;
+
+    case gif_lzw_start:
+    {
+      // Make sure the transparent pixel is transparent in the colormap
+      if (mGIFStruct.is_transparent) {
+        // Save old value so we can restore it later
+        if (mColormap == mGIFStruct.global_colormap)
+            mOldColor = mColormap[mGIFStruct.tpixel];
+        mColormap[mGIFStruct.tpixel] = 0;
+      }
+
+      /* Initialize LZW parser/decoder */
+      mGIFStruct.datasize = *q;
+      const int clear_code = ClearCode();
+      if (mGIFStruct.datasize > MAX_LZW_BITS ||
+          clear_code >= MAX_BITS) {
+        mGIFStruct.state = gif_error;
+        break;
+      }
+
+      mGIFStruct.avail = clear_code + 2;
+      mGIFStruct.oldcode = -1;
+      mGIFStruct.codesize = mGIFStruct.datasize + 1;
+      mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
+      mGIFStruct.datum = mGIFStruct.bits = 0;
+
+      /* init the tables */
+      for (int i = 0; i < clear_code; i++)
+        mGIFStruct.suffix[i] = i;
+
+      mGIFStruct.stackp = mGIFStruct.stack;
+
+      GETN(1, gif_sub_block);
+    }
+    break;
+
+    /* All GIF files begin with "GIF87a" or "GIF89a" */
+    case gif_type:
+      if (!strncmp((char*)q, "GIF89a", 6)) {
+        mGIFStruct.version = 89;
+      } else if (!strncmp((char*)q, "GIF87a", 6)) {
+        mGIFStruct.version = 87;
+      } else {
+        mGIFStruct.state = gif_error;
+        break;
+      }
+      GETN(7, gif_global_header);
+      break;
+
+    case gif_global_header:
+      /* This is the height and width of the "screen" or
+       * frame into which images are rendered.  The
+       * individual images can be smaller than the
+       * screen size and located with an origin anywhere
+       * within the screen.
+       */
+
+      mGIFStruct.screen_width = GETINT16(q);
+      mGIFStruct.screen_height = GETINT16(q + 2);
+      mGIFStruct.global_colormap_depth = (q[4]&0x07) + 1;
+
+      // screen_bgcolor is not used
+      //mGIFStruct.screen_bgcolor = q[5];
+      // q[6] = Pixel Aspect Ratio
+      //   Not used
+      //   float aspect = (float)((q[6] + 15) / 64.0);
+
+      if (q[4] & 0x80) { /* global map */
+        // Get the global colormap
+        const PRUint32 size = (3 << mGIFStruct.global_colormap_depth);
+        if (len < size) {
+          // Use 'hold' pattern to get the global colormap
+          GETN(size, gif_global_colormap);
+          break;
+        }
+        // Copy everything, go to colormap state to do CMS correction
+        memcpy(mGIFStruct.global_colormap, buf, size);
+        buf += size;
+        len -= size;
+        GETN(0, gif_global_colormap);
+        break;
+      }
+
+      GETN(1, gif_image_start);
+      break;
+
+    case gif_global_colormap:
+      // Everything is already copied into global_colormap
+      // Convert into Cairo colors including CMS transformation
+      ConvertColormap(mGIFStruct.global_colormap, 1<<mGIFStruct.global_colormap_depth);
+      GETN(1, gif_image_start);
+      break;
+
+    case gif_image_start:
+      switch (*q) {
+        case GIF_TRAILER:
+          mGIFStruct.state = gif_done;
+          break;
+
+        case GIF_EXTENSION_INTRODUCER:
+          GETN(2, gif_extension);
+          break;
+
+        case GIF_IMAGE_SEPARATOR:
+          GETN(9, gif_image_header);
+          break;
+
+        default:
+          /* If we get anything other than GIF_IMAGE_SEPARATOR, 
+           * GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
+           * between blocks. The GIF87a spec tells us to keep reading
+           * until we find an image separator, but GIF89a says such
+           * a file is corrupt. We follow GIF89a and bail out. */
+          if (mGIFStruct.images_decoded > 0) {
+            /* The file is corrupt, but one or more images have
+             * been decoded correctly. In this case, we proceed
+             * as if the file were correctly terminated and set
+             * the state to gif_done, so the GIF will display.
+             */
+            mGIFStruct.state = gif_done;
+          } else {
+            /* No images decoded, there is nothing to display. */
+            mGIFStruct.state = gif_error;
+          }
+      }
+      break;
+
+    case gif_extension:
+      mGIFStruct.bytes_to_consume = q[1];
+      if (mGIFStruct.bytes_to_consume) {
+        switch (*q) {
+        case GIF_GRAPHIC_CONTROL_LABEL:
+          mGIFStruct.state = gif_control_extension;
+          break;
+  
+        case GIF_APPLICATION_EXTENSION_LABEL:
+          mGIFStruct.state = gif_application_extension;
+          break;
+  
+        case GIF_COMMENT_LABEL:
+          mGIFStruct.state = gif_consume_comment;
+          break;
+  
+        default:
+          mGIFStruct.state = gif_skip_block;
+        }
+      } else {
+        GETN(1, gif_image_start);
+      }
+      break;
+
+    case gif_consume_block:
+      if (!*q)
+        GETN(1, gif_image_start);
+      else
+        GETN(*q, gif_skip_block);
+      break;
+
+    case gif_skip_block:
+      GETN(1, gif_consume_block);
+      break;
+
+    case gif_control_extension:
+      mGIFStruct.is_transparent = *q & 0x1;
+      mGIFStruct.tpixel = q[3];
+      mGIFStruct.disposal_method = ((*q) >> 2) & 0x7;
+      // Some specs say 3rd bit (value 4), other specs say value 3
+      // Let's choose 3 (the more popular)
+      if (mGIFStruct.disposal_method == 4)
+        mGIFStruct.disposal_method = 3;
+      mGIFStruct.delay_time = GETINT16(q + 1) * 10;
+      GETN(1, gif_consume_block);
+      break;
+
+    case gif_comment_extension:
+      if (*q)
+        GETN(*q, gif_consume_comment);
+      else
+        GETN(1, gif_image_start);
+      break;
+
+    case gif_consume_comment:
+      GETN(1, gif_comment_extension);
+      break;
+
+    case gif_application_extension:
+      /* Check for netscape application extension */
+      if (!strncmp((char*)q, "NETSCAPE2.0", 11) ||
+        !strncmp((char*)q, "ANIMEXTS1.0", 11))
+        GETN(1, gif_netscape_extension_block);
+      else
+        GETN(1, gif_consume_block);
+      break;
+
+    /* Netscape-specific GIF extension: animation looping */
+    case gif_netscape_extension_block:
+      if (*q)
+        GETN(*q, gif_consume_netscape_extension);
+      else
+        GETN(1, gif_image_start);
+      break;
+
+    /* Parse netscape-specific application extensions */
+    case gif_consume_netscape_extension:
+      switch (q[0] & 7) {
+        case 1:
+          /* Loop entire animation specified # of times.  Only read the
+             loop count during the first iteration. */
+          mGIFStruct.loop_count = GETINT16(q + 1);
+  
+          /* Zero loop count is infinite animation loop request */
+          if (mGIFStruct.loop_count == 0)
+            mGIFStruct.loop_count = -1;
+  
+          GETN(1, gif_netscape_extension_block);
+          break;
+        
+        case 2:
+          /* Wait for specified # of bytes to enter buffer */
+          // Don't do this, this extension doesn't exist (isn't used at all) 
+          // and doesn't do anything, as our streaming/buffering takes care of it all...
+          // See: http://semmix.pl/color/exgraf/eeg24.htm
+          GETN(1, gif_netscape_extension_block);
+          break;
+  
+        default:
+          // 0,3-7 are yet to be defined netscape extension codes
+          mGIFStruct.state = gif_error;
+      }
+      break;
+
+    case gif_image_header:
+    {
+      /* Get image offsets, with respect to the screen origin */
+      mGIFStruct.x_offset = GETINT16(q);
+      mGIFStruct.y_offset = GETINT16(q + 2);
+
+      /* Get image width and height. */
+      mGIFStruct.width  = GETINT16(q + 4);
+      mGIFStruct.height = GETINT16(q + 6);
+
+      if (!mGIFStruct.images_decoded) {
+        /* Work around broken GIF files where the logical screen
+         * size has weird width or height.  We assume that GIF87a
+         * files don't contain animations.
+         */
+        if ((mGIFStruct.screen_height < mGIFStruct.height) ||
+            (mGIFStruct.screen_width < mGIFStruct.width) ||
+            (mGIFStruct.version == 87)) {
+          mGIFStruct.screen_height = mGIFStruct.height;
+          mGIFStruct.screen_width = mGIFStruct.width;
+          mGIFStruct.x_offset = 0;
+          mGIFStruct.y_offset = 0;
+        }    
+        // Create the image container with the right size.
+        BeginGIF();
+
+        // If we were doing header-only, we're done
+        if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
+          return NS_OK;
+      }
+
+      /* Work around more broken GIF files that have zero image
+         width or height */
+      if (!mGIFStruct.height || !mGIFStruct.width) {
+        mGIFStruct.height = mGIFStruct.screen_height;
+        mGIFStruct.width = mGIFStruct.screen_width;
+        if (!mGIFStruct.height || !mGIFStruct.width) {
+          mGIFStruct.state = gif_error;
+          break;
+        }
+      }
+
+      /* Depth of colors is determined by colormap */
+      /* (q[8] & 0x80) indicates local colormap */
+      /* bits per pixel is (q[8]&0x07 + 1) when local colormap is set */
+      PRUint32 depth = mGIFStruct.global_colormap_depth;
+      if (q[8] & 0x80)
+        depth = (q[8]&0x07) + 1;
+      PRUint32 realDepth = depth;
+      while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
+        realDepth++;
+      } 
+      // Mask to limit the color values within the colormap
+      mColorMask = 0xFF >> (8 - realDepth);
+      nsresult rv = BeginImageFrame(realDepth);
+      if (NS_FAILED(rv) || !mImageData) {
+        mGIFStruct.state = gif_error;
+        break;
+      }
+
+      if (q[8] & 0x40) {
+        mGIFStruct.interlaced = PR_TRUE;
+        mGIFStruct.ipass = 1;
+      } else {
+        mGIFStruct.interlaced = PR_FALSE;
+        mGIFStruct.ipass = 0;
+      }
+
+      /* Only apply the Haeberli display hack on the first frame */
+      mGIFStruct.progressive_display = (mGIFStruct.images_decoded == 0);
+
+      /* Clear state from last image */
+      mGIFStruct.irow = 0;
+      mGIFStruct.rows_remaining = mGIFStruct.height;
+      mGIFStruct.rowp = mImageData;
+
+      /* bits per pixel is q[8]&0x07 */
+
+      if (q[8] & 0x80) /* has a local colormap? */
+      {
+        mGIFStruct.local_colormap_size = 1 << depth;
+        if (!mGIFStruct.images_decoded) {
+          // First frame has local colormap, allocate space for it
+          // as the image frame doesn't have its own palette
+          mColormapSize = sizeof(PRUint32) << realDepth;
+          if (!mGIFStruct.local_colormap) {
+            mGIFStruct.local_colormap = (PRUint32*)PR_MALLOC(mColormapSize);
+            if (!mGIFStruct.local_colormap) {
+              mGIFStruct.state = gif_oom;
+              break;
+            }
+          }
+          mColormap = mGIFStruct.local_colormap;
+        }
+        const PRUint32 size = 3 << depth;
+        if (mColormapSize > size) {
+          // Clear the notfilled part of the colormap
+          memset(((PRUint8*)mColormap) + size, 0, mColormapSize - size);
+        }
+        if (len < size) {
+          // Use 'hold' pattern to get the image colormap
+          GETN(size, gif_image_colormap);
+          break;
+        }
+        // Copy everything, go to colormap state to do CMS correction
+        memcpy(mColormap, buf, size);
+        buf += size;
+        len -= size;
+        GETN(0, gif_image_colormap);
+        break;
+      } else {
+        /* Switch back to the global palette */
+        if (mGIFStruct.images_decoded) {
+          // Copy global colormap into the palette of current frame
+          memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
+        } else {
+          mColormap = mGIFStruct.global_colormap;
+        }
+      }
+      GETN(1, gif_lzw_start);
+    }
+    break;
+
+    case gif_image_colormap:
+      // Everything is already copied into local_colormap
+      // Convert into Cairo colors including CMS transformation
+      ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
+      GETN(1, gif_lzw_start);
+      break;
+
+    case gif_sub_block:
+      mGIFStruct.count = *q;
+      if (mGIFStruct.count) {
+        /* Still working on the same image: Process next LZW data block */
+        /* Make sure there are still rows left. If the GIF data */
+        /* is corrupt, we may not get an explicit terminator.   */
+        if (!mGIFStruct.rows_remaining) {
+#ifdef DONT_TOLERATE_BROKEN_GIFS
+          mGIFStruct.state = gif_error;
+          break;
+#else
+          /* This is an illegal GIF, but we remain tolerant. */
+          GETN(1, gif_sub_block);
+#endif
+          if (mGIFStruct.count == GIF_TRAILER) {
+            /* Found a terminator anyway, so consider the image done */
+            GETN(1, gif_done);
+            break;
+          }
+        }
+        GETN(mGIFStruct.count, gif_lzw);
+      } else {
+        /* See if there are any more images in this sequence. */
+        EndImageFrame();
+        GETN(1, gif_image_start);
+      }
+      break;
+
+    case gif_done:
+      EndGIF(/* aSuccess = */ PR_TRUE);
+      return NS_OK;
+      break;
+
+    case gif_error:
+      EndGIF(/* aSuccess = */ PR_FALSE);
+      return NS_ERROR_FAILURE;
+      break;
+
+    // Handle out of memory errors
+    case gif_oom:
+      return NS_ERROR_OUT_OF_MEMORY;
+
+    // We shouldn't ever get here.
+    default:
+      break;
+    }
+  }
+
+  // if an error state is set but no data remains, code flow reaches here
+  if (mGIFStruct.state == gif_error) {
+      EndGIF(/* aSuccess = */ PR_FALSE);
+      return NS_ERROR_FAILURE;
+  }
+  
+  // Copy the leftover into mGIFStruct.hold
+  mGIFStruct.bytes_in_hold = len;
+  if (len) {
+    // Add what we have sofar to the block
+    PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
+                 (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
+                 mGIFStruct.hold;
+    memcpy(p, buf, len);
+    mGIFStruct.bytes_to_consume -= len;
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Saari <saari@netscape.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _nsGIFDecoder2_h
+#define _nsGIFDecoder2_h
+
+#include "nsCOMPtr.h"
+#include "imgIDecoder.h"
+#include "imgIContainer.h"
+#include "imgIDecoderObserver.h"
+
+#include "GIF2.h"
+
+#define NS_GIFDECODER2_CID \
+{ /* 797bec5a-1dd2-11b2-a7f8-ca397e0179c4 */         \
+     0x797bec5a,                                     \
+     0x1dd2,                                         \
+     0x11b2,                                         \
+    {0xa7, 0xf8, 0xca, 0x39, 0x7e, 0x01, 0x79, 0xc4} \
+}
+
+namespace mozilla {
+namespace imagelib {
+class RasterImage;
+} // namespace imagelib
+} // namespace mozilla
+
+//////////////////////////////////////////////////////////////////////
+// nsGIFDecoder2 Definition
+
+class nsGIFDecoder2 : public imgIDecoder
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGIDECODER
+
+  nsGIFDecoder2();
+  ~nsGIFDecoder2();
+
+private:
+  /* These functions will be called when the decoder has a decoded row,
+   * frame size information, etc. */
+
+  void      BeginGIF();
+  void      EndGIF(PRBool aSuccess);
+  nsresult  BeginImageFrame(gfx_depth aDepth);
+  void      EndImageFrame();
+  nsresult  FlushImageData();
+  nsresult  FlushImageData(PRUint32 fromRow, PRUint32 rows);
+
+  nsresult  GifWrite(const PRUint8 * buf, PRUint32 numbytes);
+  PRUint32  OutputRow();
+  PRBool    DoLzw(const PRUint8 *q);
+
+  inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
+
+  // XXXdholbert This member variable should probably be renamed to "mImage"
+  // for consistency with nsPNGDecoder
+  nsRefPtr<mozilla::imagelib::RasterImage> mImageContainer;
+  nsCOMPtr<imgIDecoderObserver> mObserver;
+  PRUint32 mFlags;
+  PRInt32 mCurrentRow;
+  PRInt32 mLastFlushedRow;
+
+  PRUint8 *mImageData;       // Pointer to image data in either Cairo or 8bit format
+  PRUint32 *mColormap;       // Current colormap to be used in Cairo format
+  PRUint32 mColormapSize;
+  PRUint32 mOldColor;        // The old value of the transparent pixel
+
+  // The frame number of the currently-decoding frame when we're in the middle
+  // of decoding it, and -1 otherwise.
+  PRInt32 mCurrentFrame;
+
+  PRUint8 mCurrentPass;
+  PRUint8 mLastFlushedPass;
+  PRUint8 mColorMask;        // Apply this to the pixel to keep within colormap
+  PRPackedBool mGIFOpen;
+  PRPackedBool mSawTransparency;
+  PRPackedBool mError;
+  PRPackedBool mEnded;
+
+  gif_struct mGIFStruct;
+};
+
+#endif
deleted file mode 100644
--- a/modules/libpr0n/decoders/iccjpeg.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * iccprofile.c
- *
- * This file provides code to read and write International Color Consortium
- * (ICC) device profiles embedded in JFIF JPEG image files.  The ICC has
- * defined a standard format for including such data in JPEG "APP2" markers.
- * The code given here does not know anything about the internal structure
- * of the ICC profile data; it just knows how to put the profile data into
- * a JPEG file being written, or get it back out when reading.
- *
- * This code depends on new features added to the IJG JPEG library as of
- * IJG release 6b; it will not compile or work with older IJG versions.
- *
- * NOTE: this code would need surgery to work on 16-bit-int machines
- * with ICC profiles exceeding 64K bytes in size.  If you need to do that,
- * change all the "unsigned int" variables to "INT32".  You'll also need
- * to find a malloc() replacement that can allocate more than 64K.
- */
-
-#include "iccjpeg.h"
-#include <stdlib.h>			/* define malloc() */
-
-
-/*
- * Since an ICC profile can be larger than the maximum size of a JPEG marker
- * (64K), we need provisions to split it into multiple markers.  The format
- * defined by the ICC specifies one or more APP2 markers containing the
- * following data:
- *	Identifying string	ASCII "ICC_PROFILE\0"  (12 bytes)
- *	Marker sequence number	1 for first APP2, 2 for next, etc (1 byte)
- *	Number of markers	Total number of APP2's used (1 byte)
- *      Profile data		(remainder of APP2 data)
- * Decoders should use the marker sequence numbers to reassemble the profile,
- * rather than assuming that the APP2 markers appear in the correct sequence.
- */
-
-#define ICC_MARKER  (JPEG_APP0 + 2)	/* JPEG marker code for ICC */
-#define ICC_OVERHEAD_LEN  14		/* size of non-profile data in APP2 */
-#define MAX_BYTES_IN_MARKER  65533	/* maximum data len of a JPEG marker */
-#define MAX_DATA_BYTES_IN_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
-
-/*
- * Prepare for reading an ICC profile
- */
-
-void
-setup_read_icc_profile (j_decompress_ptr cinfo)
-{
-  /* Tell the library to keep any APP2 data it may find */
-  jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
-}
-
-
-/*
- * Handy subroutine to test whether a saved marker is an ICC profile marker.
- */
-
-static boolean
-marker_is_icc (jpeg_saved_marker_ptr marker)
-{
-  return
-    marker->marker == ICC_MARKER &&
-    marker->data_length >= ICC_OVERHEAD_LEN &&
-    /* verify the identifying string */
-    GETJOCTET(marker->data[0]) == 0x49 &&
-    GETJOCTET(marker->data[1]) == 0x43 &&
-    GETJOCTET(marker->data[2]) == 0x43 &&
-    GETJOCTET(marker->data[3]) == 0x5F &&
-    GETJOCTET(marker->data[4]) == 0x50 &&
-    GETJOCTET(marker->data[5]) == 0x52 &&
-    GETJOCTET(marker->data[6]) == 0x4F &&
-    GETJOCTET(marker->data[7]) == 0x46 &&
-    GETJOCTET(marker->data[8]) == 0x49 &&
-    GETJOCTET(marker->data[9]) == 0x4C &&
-    GETJOCTET(marker->data[10]) == 0x45 &&
-    GETJOCTET(marker->data[11]) == 0x0;
-}
-
-
-/*
- * See if there was an ICC profile in the JPEG file being read;
- * if so, reassemble and return the profile data.
- *
- * TRUE is returned if an ICC profile was found, FALSE if not.
- * If TRUE is returned, *icc_data_ptr is set to point to the
- * returned data, and *icc_data_len is set to its length.
- *
- * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
- * and must be freed by the caller with free() when the caller no longer
- * needs it.  (Alternatively, we could write this routine to use the
- * IJG library's memory allocator, so that the data would be freed implicitly
- * at jpeg_finish_decompress() time.  But it seems likely that many apps
- * will prefer to have the data stick around after decompression finishes.)
- *
- * NOTE: if the file contains invalid ICC APP2 markers, we just silently
- * return FALSE.  You might want to issue an error message instead.
- */
-
-boolean
-read_icc_profile (j_decompress_ptr cinfo,
-		  JOCTET **icc_data_ptr,
-		  unsigned int *icc_data_len)
-{
-  jpeg_saved_marker_ptr marker;
-  int num_markers = 0;
-  int seq_no;
-  JOCTET *icc_data;
-  unsigned int total_length;
-#define MAX_SEQ_NO  255		/* sufficient since marker numbers are bytes */
-  char marker_present[MAX_SEQ_NO+1];	  /* 1 if marker found */
-  unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
-  unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
-
-  *icc_data_ptr = NULL;		/* avoid confusion if FALSE return */
-  *icc_data_len = 0;
-
-  /* This first pass over the saved markers discovers whether there are
-   * any ICC markers and verifies the consistency of the marker numbering.
-   */
-
-  for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
-    marker_present[seq_no] = 0;
-
-  for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
-    if (marker_is_icc(marker)) {
-      if (num_markers == 0)
-	num_markers = GETJOCTET(marker->data[13]);
-      else if (num_markers != GETJOCTET(marker->data[13]))
-	return FALSE;		/* inconsistent num_markers fields */
-      seq_no = GETJOCTET(marker->data[12]);
-      if (seq_no <= 0 || seq_no > num_markers)
-	return FALSE;		/* bogus sequence number */
-      if (marker_present[seq_no])
-	return FALSE;		/* duplicate sequence numbers */
-      marker_present[seq_no] = 1;
-      data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
-    }
-  }
-
-  if (num_markers == 0)
-    return FALSE;
-
-  /* Check for missing markers, count total space needed,
-   * compute offset of each marker's part of the data.
-   */
-
-  total_length = 0;
-  for (seq_no = 1; seq_no <= num_markers; seq_no++) {
-    if (marker_present[seq_no] == 0)
-      return FALSE;		/* missing sequence number */
-    data_offset[seq_no] = total_length;
-    total_length += data_length[seq_no];
-  }
-
-  if (total_length <= 0)
-    return FALSE;		/* found only empty markers? */
-
-  /* Allocate space for assembled data */
-  icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
-  if (icc_data == NULL)
-    return FALSE;		/* oops, out of memory */
-
-  /* and fill it in */
-  for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
-    if (marker_is_icc(marker)) {
-      JOCTET FAR *src_ptr;
-      JOCTET *dst_ptr;
-      unsigned int length;
-      seq_no = GETJOCTET(marker->data[12]);
-      dst_ptr = icc_data + data_offset[seq_no];
-      src_ptr = marker->data + ICC_OVERHEAD_LEN;
-      length = data_length[seq_no];
-      while (length--) {
-	*dst_ptr++ = *src_ptr++;
-      }
-    }
-  }
-
-  *icc_data_ptr = icc_data;
-  *icc_data_len = total_length;
-
-  return TRUE;
-}
deleted file mode 100644
--- a/modules/libpr0n/decoders/iccjpeg.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * iccprofile.h
- *
- * This file provides code to read and write International Color Consortium
- * (ICC) device profiles embedded in JFIF JPEG image files.  The ICC has
- * defined a standard format for including such data in JPEG "APP2" markers.
- * The code given here does not know anything about the internal structure
- * of the ICC profile data; it just knows how to put the profile data into
- * a JPEG file being written, or get it back out when reading.
- *
- * This code depends on new features added to the IJG JPEG library as of
- * IJG release 6b; it will not compile or work with older IJG versions.
- *
- * NOTE: this code would need surgery to work on 16-bit-int machines
- * with ICC profiles exceeding 64K bytes in size.  See iccprofile.c
- * for details.
- */
-
-#include <stdio.h>		/* needed to define "FILE", "NULL" */
-#include "jpeglib.h"
-
-/*
- * Reading a JPEG file that may contain an ICC profile requires two steps:
- *
- * 1. After jpeg_create_decompress() but before jpeg_read_header(),
- *    call setup_read_icc_profile().  This routine tells the IJG library
- *    to save in memory any APP2 markers it may find in the file.
- *
- * 2. After jpeg_read_header(), call read_icc_profile() to find out
- *    whether there was a profile and obtain it if so.
- */
-
-
-/*
- * Prepare for reading an ICC profile
- */
-
-extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo));
-
-
-/*
- * See if there was an ICC profile in the JPEG file being read;
- * if so, reassemble and return the profile data.
- *
- * TRUE is returned if an ICC profile was found, FALSE if not.
- * If TRUE is returned, *icc_data_ptr is set to point to the
- * returned data, and *icc_data_len is set to its length.
- *
- * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
- * and must be freed by the caller with free() when the caller no longer
- * needs it.  (Alternatively, we could write this routine to use the
- * IJG library's memory allocator, so that the data would be freed implicitly
- * at jpeg_finish_decompress() time.  But it seems likely that many apps
- * will prefer to have the data stick around after decompression finishes.)
- */
-
-extern boolean read_icc_profile JPP((j_decompress_ptr cinfo,
-				     JOCTET **icc_data_ptr,
-				     unsigned int *icc_data_len));
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/jpeg/Makefile.in
@@ -0,0 +1,60 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= imgjpeg
+LIBRARY_NAME	= imgjpeg_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME	= nsJPEGDecoderModule
+LIBXUL_LIBRARY  = 1
+
+
+CPPSRCS		= nsJPEGDecoder.cpp
+
+CSRCS		= iccjpeg.c
+
+# nsJPEGDecoder.cpp includes RasterImage.h
+LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src/
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/jpeg/iccjpeg.c
@@ -0,0 +1,183 @@
+/*
+ * iccprofile.c
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files.  The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size.  If you need to do that,
+ * change all the "unsigned int" variables to "INT32".  You'll also need
+ * to find a malloc() replacement that can allocate more than 64K.
+ */
+
+#include "iccjpeg.h"
+#include <stdlib.h>			/* define malloc() */
+
+
+/*
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
+ * (64K), we need provisions to split it into multiple markers.  The format
+ * defined by the ICC specifies one or more APP2 markers containing the
+ * following data:
+ *	Identifying string	ASCII "ICC_PROFILE\0"  (12 bytes)
+ *	Marker sequence number	1 for first APP2, 2 for next, etc (1 byte)
+ *	Number of markers	Total number of APP2's used (1 byte)
+ *      Profile data		(remainder of APP2 data)
+ * Decoders should use the marker sequence numbers to reassemble the profile,
+ * rather than assuming that the APP2 markers appear in the correct sequence.
+ */
+
+#define ICC_MARKER  (JPEG_APP0 + 2)	/* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN  14		/* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER  65533	/* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+void
+setup_read_icc_profile (j_decompress_ptr cinfo)
+{
+  /* Tell the library to keep any APP2 data it may find */
+  jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
+}
+
+
+/*
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
+ */
+
+static boolean
+marker_is_icc (jpeg_saved_marker_ptr marker)
+{
+  return
+    marker->marker == ICC_MARKER &&
+    marker->data_length >= ICC_OVERHEAD_LEN &&
+    /* verify the identifying string */
+    GETJOCTET(marker->data[0]) == 0x49 &&
+    GETJOCTET(marker->data[1]) == 0x43 &&
+    GETJOCTET(marker->data[2]) == 0x43 &&
+    GETJOCTET(marker->data[3]) == 0x5F &&
+    GETJOCTET(marker->data[4]) == 0x50 &&
+    GETJOCTET(marker->data[5]) == 0x52 &&
+    GETJOCTET(marker->data[6]) == 0x4F &&
+    GETJOCTET(marker->data[7]) == 0x46 &&
+    GETJOCTET(marker->data[8]) == 0x49 &&
+    GETJOCTET(marker->data[9]) == 0x4C &&
+    GETJOCTET(marker->data[10]) == 0x45 &&
+    GETJOCTET(marker->data[11]) == 0x0;
+}
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it.  (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time.  But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ *
+ * NOTE: if the file contains invalid ICC APP2 markers, we just silently
+ * return FALSE.  You might want to issue an error message instead.
+ */
+
+boolean
+read_icc_profile (j_decompress_ptr cinfo,
+		  JOCTET **icc_data_ptr,
+		  unsigned int *icc_data_len)
+{
+  jpeg_saved_marker_ptr marker;
+  int num_markers = 0;
+  int seq_no;
+  JOCTET *icc_data;
+  unsigned int total_length;
+#define MAX_SEQ_NO  255		/* sufficient since marker numbers are bytes */
+  char marker_present[MAX_SEQ_NO+1];	  /* 1 if marker found */
+  unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
+  unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
+
+  *icc_data_ptr = NULL;		/* avoid confusion if FALSE return */
+  *icc_data_len = 0;
+
+  /* This first pass over the saved markers discovers whether there are
+   * any ICC markers and verifies the consistency of the marker numbering.
+   */
+
+  for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
+    marker_present[seq_no] = 0;
+
+  for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+    if (marker_is_icc(marker)) {
+      if (num_markers == 0)
+	num_markers = GETJOCTET(marker->data[13]);
+      else if (num_markers != GETJOCTET(marker->data[13]))
+	return FALSE;		/* inconsistent num_markers fields */
+      seq_no = GETJOCTET(marker->data[12]);
+      if (seq_no <= 0 || seq_no > num_markers)
+	return FALSE;		/* bogus sequence number */
+      if (marker_present[seq_no])
+	return FALSE;		/* duplicate sequence numbers */
+      marker_present[seq_no] = 1;
+      data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
+    }
+  }
+
+  if (num_markers == 0)
+    return FALSE;
+
+  /* Check for missing markers, count total space needed,
+   * compute offset of each marker's part of the data.
+   */
+
+  total_length = 0;
+  for (seq_no = 1; seq_no <= num_markers; seq_no++) {
+    if (marker_present[seq_no] == 0)
+      return FALSE;		/* missing sequence number */
+    data_offset[seq_no] = total_length;
+    total_length += data_length[seq_no];
+  }
+
+  if (total_length <= 0)
+    return FALSE;		/* found only empty markers? */
+
+  /* Allocate space for assembled data */
+  icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
+  if (icc_data == NULL)
+    return FALSE;		/* oops, out of memory */
+
+  /* and fill it in */
+  for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+    if (marker_is_icc(marker)) {
+      JOCTET FAR *src_ptr;
+      JOCTET *dst_ptr;
+      unsigned int length;
+      seq_no = GETJOCTET(marker->data[12]);
+      dst_ptr = icc_data + data_offset[seq_no];
+      src_ptr = marker->data + ICC_OVERHEAD_LEN;
+      length = data_length[seq_no];
+      while (length--) {
+	*dst_ptr++ = *src_ptr++;
+      }
+    }
+  }
+
+  *icc_data_ptr = icc_data;
+  *icc_data_len = total_length;
+
+  return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/jpeg/iccjpeg.h
@@ -0,0 +1,59 @@
+/*
+ * iccprofile.h
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files.  The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size.  See iccprofile.c
+ * for details.
+ */
+
+#include <stdio.h>		/* needed to define "FILE", "NULL" */
+#include "jpeglib.h"
+
+/*
+ * Reading a JPEG file that may contain an ICC profile requires two steps:
+ *
+ * 1. After jpeg_create_decompress() but before jpeg_read_header(),
+ *    call setup_read_icc_profile().  This routine tells the IJG library
+ *    to save in memory any APP2 markers it may find in the file.
+ *
+ * 2. After jpeg_read_header(), call read_icc_profile() to find out
+ *    whether there was a profile and obtain it if so.
+ */
+
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it.  (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time.  But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ */
+
+extern boolean read_icc_profile JPP((j_decompress_ptr cinfo,
+				     JOCTET **icc_data_ptr,
+				     unsigned int *icc_data_len));
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
@@ -0,0 +1,1250 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <stuart@mozilla.com>
+ *   Federico Mena-Quintero <federico@novell.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsJPEGDecoder.h"
+
+#include "imgIContainerObserver.h"
+
+#include "nsIComponentManager.h"
+#include "nsIInputStream.h"
+
+#include "nspr.h"
+#include "nsCRT.h"
+#include "ImageLogging.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "gfxColor.h"
+
+#include "jerror.h"
+
+#include "gfxPlatform.h"
+
+using namespace mozilla::imagelib;
+
+extern "C" {
+#include "iccjpeg.h"
+
+/* Colorspace conversion (copied from jpegint.h) */
+struct jpeg_color_deconverter {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
+				JSAMPIMAGE input_buf, JDIMENSION input_row,
+				JSAMPARRAY output_buf, int num_rows));
+};
+
+METHODDEF(void)
+ycc_rgb_convert_argb (j_decompress_ptr cinfo,
+                 JSAMPIMAGE input_buf, JDIMENSION input_row,
+                 JSAMPARRAY output_buf, int num_rows);
+}
+
+NS_IMPL_ISUPPORTS1(nsJPEGDecoder, imgIDecoder)
+
+#if defined(PR_LOGGING)
+PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
+static PRLogModuleInfo *gJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
+#else
+#define gJPEGlog
+#define gJPEGDecoderAccountingLog
+#endif
+
+
+METHODDEF(void) init_source (j_decompress_ptr jd);
+METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
+METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
+METHODDEF(void) term_source (j_decompress_ptr jd);
+METHODDEF(void) my_error_exit (j_common_ptr cinfo);
+
+static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
+
+/* Normal JFIF markers can't have more bytes than this. */
+#define MAX_JPEG_MARKER_LENGTH  (((PRUint32)1 << 16) - 1)
+
+
+nsJPEGDecoder::nsJPEGDecoder()
+{
+  mState = JPEG_HEADER;
+  mReading = PR_TRUE;
+  mNotifiedDone = PR_FALSE;
+  mImageData = nsnull;
+
+  mBytesToSkip = 0;
+  memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
+  memset(&mSourceMgr, 0, sizeof(mSourceMgr));
+  mInfo.client_data = (void*)this;
+
+  mSegment = nsnull;
+  mSegmentLen = 0;
+
+  mBackBuffer = nsnull;
+  mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
+
+  mInProfile = nsnull;
+  mTransform = nsnull;
+
+  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+         ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
+          this));
+}
+
+nsJPEGDecoder::~nsJPEGDecoder()
+{
+  PR_FREEIF(mBackBuffer);
+  if (mTransform)
+    qcms_transform_release(mTransform);
+  if (mInProfile)
+    qcms_profile_release(mInProfile);
+
+  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+         ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
+          this));
+}
+
+
+/** imgIDecoder methods **/
+
+/* void init (in imgIContainer aImage, 
+              in imgIDecoderObserver aObserver,
+              in unsigned long aFlags); */
+NS_IMETHODIMP nsJPEGDecoder::Init(imgIContainer *aImage, 
+                                  imgIDecoderObserver *aObserver,
+                                  PRUint32 aFlags)
+{
+  NS_ABORT_IF_FALSE(aImage->GetType() == imgIContainer::TYPE_RASTER,
+                    "wrong type of imgIContainer for decoding into");
+
+  /* Grab the parameters. */
+  mImage = static_cast<RasterImage*>(aImage);
+  mObserver = aObserver;
+  mFlags = aFlags;
+
+  /* Fire OnStartDecode at init time to support bug 512435 */
+  if (!(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) && mObserver)
+    mObserver->OnStartDecode(nsnull);
+
+  /* We set up the normal JPEG error routines, then override error_exit. */
+  mInfo.err = jpeg_std_error(&mErr.pub);
+  /*   mInfo.err = jpeg_std_error(&mErr.pub); */
+  mErr.pub.error_exit = my_error_exit;
+  /* Establish the setjmp return context for my_error_exit to use. */
+  if (setjmp(mErr.setjmp_buffer)) {
+    /* If we get here, the JPEG code has signaled an error.
+     * We need to clean up the JPEG object, close the input file, and return.
+     */
+    return NS_ERROR_FAILURE;
+  }
+
+  /* Step 1: allocate and initialize JPEG decompression object */
+  jpeg_create_decompress(&mInfo);
+  /* Set the source manager */
+  mInfo.src = &mSourceMgr;
+
+  /* Step 2: specify data source (eg, a file) */
+
+  /* Setup callback functions. */
+  mSourceMgr.init_source = init_source;
+  mSourceMgr.fill_input_buffer = fill_input_buffer;
+  mSourceMgr.skip_input_data = skip_input_data;
+  mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
+  mSourceMgr.term_source = term_source;
+
+  /* Record app markers for ICC data */
+  for (PRUint32 m = 0; m < 16; m++)
+    jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
+
+  return NS_OK;
+}
+
+
+/* void close (); */
+NS_IMETHODIMP nsJPEGDecoder::Close(PRUint32 aFlags)
+{
+  PR_LOG(gJPEGlog, PR_LOG_DEBUG,
+         ("[this=%p] nsJPEGDecoder::Close\n", this));
+
+  /* Step 8: Release JPEG decompression object */
+  mInfo.src = nsnull;
+
+  jpeg_destroy_decompress(&mInfo);
+
+  /* If we already know we're in an error state, don't
+     bother flagging another one here. */
+  if (mState == JPEG_ERROR)
+    return NS_OK;
+
+  /* If we're doing a full decode and haven't notified of completion yet,
+   * we must not have got everything we wanted. Send error notifications. */
+  if (!(aFlags & CLOSE_FLAG_DONTNOTIFY) &&
+      !(mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY) &&
+      !mNotifiedDone)
+    NotifyDone(/* aSuccess = */ PR_FALSE);
+
+  /* Otherwise, no problems. */
+  return NS_OK;
+}
+
+/* void flush (); */
+NS_IMETHODIMP nsJPEGDecoder::Flush()
+{
+  LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Flush");
+
+  if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER && mState != JPEG_ERROR)
+    return this->Write(nsnull, 0);
+
+  return NS_OK;
+}
+
+//******************************************************************************
+nsresult nsJPEGDecoder::Write(const char *aBuffer, PRUint32 aCount)
+{
+  mSegment = (const JOCTET *)aBuffer;
+  mSegmentLen = aCount;
+
+  /* Return here if there is a fatal error within libjpeg. */
+  nsresult error_code;
+  if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
+    if (error_code == NS_ERROR_FAILURE) {
+      /* Error due to corrupt stream - return NS_OK and consume silently
+         so that libpr0n doesn't throw away a partial image load */
+      mState = JPEG_SINK_NON_JPEG_TRAILER;
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (setjmp returned NS_ERROR_FAILURE)"));
+      return NS_OK;
+    } else {
+      /* Error due to reasons external to the stream (probably out of
+         memory) - let libpr0n attempt to clean up, even though
+         mozilla is seconds away from falling flat on its face. */
+      mState = JPEG_ERROR;
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (setjmp returned an error)"));
+      return error_code;
+    }
+  }
+
+  PR_LOG(gJPEGlog, PR_LOG_DEBUG,
+         ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
+
+  switch (mState) {
+  case JPEG_HEADER:
+  {
+    LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
+
+    /* Step 3: read file parameters with jpeg_read_header() */
+    if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (JPEG_SUSPENDED)"));
+      return NS_OK; /* I/O suspension */
+    }
+
+    /* Set Width and height, and notify that the container is ready to go. */
+    mImage->SetSize(mInfo.image_width, mInfo.image_height);
+    if (mObserver)
+      mObserver->OnStartContainer(nsnull, mImage);
+
+    /* If we're doing a header-only decode, we're done. */
+    if (mFlags & imgIDecoder::DECODER_FLAG_HEADERONLY)
+      return NS_OK;
+
+    /* We're doing a full decode. */
+    JOCTET  *profile;
+    PRUint32 profileLength;
+    eCMSMode cmsMode = gfxPlatform::GetCMSMode();
+
+    if ((cmsMode != eCMSMode_Off) &&
+        read_icc_profile(&mInfo, &profile, &profileLength) &&
+        (mInProfile = qcms_profile_from_memory(profile, profileLength)) != NULL) {
+      free(profile);
+
+      PRUint32 profileSpace = qcms_profile_get_color_space(mInProfile);
+      PRBool mismatch = PR_FALSE;
+
+#ifdef DEBUG_tor
+      fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
+#endif
+      switch (mInfo.jpeg_color_space) {
+      case JCS_GRAYSCALE:
+        if (profileSpace == icSigRgbData)
+          mInfo.out_color_space = JCS_RGB;
+        else if (profileSpace != icSigGrayData)
+          mismatch = PR_TRUE;
+        break;
+      case JCS_RGB:
+        if (profileSpace != icSigRgbData)
+          mismatch =  PR_TRUE;
+        break;
+      case JCS_YCbCr:
+        if (profileSpace == icSigRgbData)
+          mInfo.out_color_space = JCS_RGB;
+        else
+	  // qcms doesn't support ycbcr
+          mismatch = PR_TRUE;
+        break;
+      case JCS_CMYK:
+      case JCS_YCCK:
+	  // qcms doesn't support cmyk
+          mismatch = PR_TRUE;
+        break;
+      default:
+        mState = JPEG_ERROR;
+        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+               ("} (unknown colorpsace (1))"));
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      if (!mismatch) {
+        qcms_data_type type;
+        switch (mInfo.out_color_space) {
+        case JCS_GRAYSCALE:
+          type = QCMS_DATA_GRAY_8;
+          break;
+        case JCS_RGB:
+          type = QCMS_DATA_RGB_8;
+          break;
+        default:
+          mState = JPEG_ERROR;
+          PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+                 ("} (unknown colorpsace (2))"));
+          return NS_ERROR_UNEXPECTED;
+        }
+#if 0
+        /* We don't currently support CMYK profiles. The following
+         * code dealt with lcms types. Add something like this
+         * back when we gain support for CMYK.
+         */
+        /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
+        if (mInfo.out_color_space == JCS_CMYK)
+          type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
+#endif
+
+        if (gfxPlatform::GetCMSOutputProfile()) {
+
+          /* Calculate rendering intent. */
+          int intent = gfxPlatform::GetRenderingIntent();
+          if (intent == -1)
+              intent = qcms_profile_get_rendering_intent(mInProfile);
+
+          /* Create the color management transform. */
+          mTransform = qcms_transform_create(mInProfile,
+                                          type,
+                                          gfxPlatform::GetCMSOutputProfile(),
+                                          QCMS_DATA_RGB_8,
+                                          (qcms_intent)intent);
+        }
+      } else {
+#ifdef DEBUG_tor
+        fprintf(stderr, "ICM profile colorspace mismatch\n");
+#endif
+      }
+    }
+
+    if (!mTransform) {
+      switch (mInfo.jpeg_color_space) {
+      case JCS_GRAYSCALE:
+      case JCS_RGB:
+      case JCS_YCbCr:
+        mInfo.out_color_space = JCS_RGB;
+        break;
+      case JCS_CMYK:
+      case JCS_YCCK:
+        /* libjpeg can convert from YCCK to CMYK, but not to RGB */
+        mInfo.out_color_space = JCS_CMYK;
+        break;
+      default:
+        mState = JPEG_ERROR;
+        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+               ("} (unknown colorpsace (3))"));
+        return NS_ERROR_UNEXPECTED;
+        break;
+      }
+    }
+
+    /*
+     * Don't allocate a giant and superfluous memory buffer
+     * when the image is a sequential JPEG.
+     */
+    mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
+
+    /* Used to set up image size so arrays can be allocated */
+    jpeg_calc_output_dimensions(&mInfo);
+
+
+    // Use EnsureCleanFrame so we don't create a new frame if we're being
+    // reused for e.g. multipart/x-replace
+    PRUint32 imagelength;
+    if (NS_FAILED(mImage->EnsureCleanFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
+                                           gfxASurface::ImageFormatRGB24,
+                                           &mImageData, &imagelength))) {
+      mState = JPEG_ERROR;
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (could not initialize image frame)"));
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+           ("        JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
+            mInfo.image_width, mInfo.image_height));
+
+    if (mObserver)
+      mObserver->OnStartFrame(nsnull, 0);
+    mState = JPEG_START_DECOMPRESS;
+  }
+
+  case JPEG_START_DECOMPRESS:
+  {
+    LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
+    /* Step 4: set parameters for decompression */
+
+    /* FIXME -- Should reset dct_method and dither mode
+     * for final pass of progressive JPEG
+     */
+    mInfo.dct_method =  JDCT_ISLOW;
+    mInfo.dither_mode = JDITHER_FS;
+    mInfo.do_fancy_upsampling = TRUE;
+    mInfo.enable_2pass_quant = FALSE;
+    mInfo.do_block_smoothing = TRUE;
+
+    /* Step 5: Start decompressor */
+    if (jpeg_start_decompress(&mInfo) == FALSE) {
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (I/O suspension after jpeg_start_decompress())"));
+      return NS_OK; /* I/O suspension */
+    }
+
+    /* Force to use our YCbCr to Packed RGB converter when possible */
+    if (!mTransform && (gfxPlatform::GetCMSMode() != eCMSMode_All) &&
+        mInfo.jpeg_color_space == JCS_YCbCr && mInfo.out_color_space == JCS_RGB) {
+      /* Special case for the most common case: transform from YCbCr direct into packed ARGB */
+      mInfo.out_color_components = 4; /* Packed ARGB pixels are always 4 bytes...*/
+      mInfo.cconvert->color_convert = ycc_rgb_convert_argb;
+    }
+
+    /* If this is a progressive JPEG ... */
+    mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
+  }
+
+  case JPEG_DECOMPRESS_SEQUENTIAL:
+  {
+    if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
+    {
+      LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
+      
+      PRBool suspend;
+      nsresult rv = OutputScanlines(&suspend);
+      if (NS_FAILED(rv))
+        return rv;
+      
+      if (suspend) {
+        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+               ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
+        return NS_OK; /* I/O suspension */
+      }
+      
+      /* If we've completed image output ... */
+      NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
+      mState = JPEG_DONE;
+    }
+  }
+
+  case JPEG_DECOMPRESS_PROGRESSIVE:
+  {
+    if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
+    {
+      LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
+
+      int status;
+      do {
+        status = jpeg_consume_input(&mInfo);
+      } while ((status != JPEG_SUSPENDED) &&
+               (status != JPEG_REACHED_EOI));
+
+      for (;;) {
+        if (mInfo.output_scanline == 0) {
+          int scan = mInfo.input_scan_number;
+
+          /* if we haven't displayed anything yet (output_scan_number==0)
+             and we have enough data for a complete scan, force output
+             of the last full scan */
+          if ((mInfo.output_scan_number == 0) &&
+              (scan > 1) &&
+              (status != JPEG_REACHED_EOI))
+            scan--;
+
+          if (!jpeg_start_output(&mInfo, scan)) {
+            PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+                   ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
+            return NS_OK; /* I/O suspension */
+          }
+        }
+
+        if (mInfo.output_scanline == 0xffffff)
+          mInfo.output_scanline = 0;
+
+        PRBool suspend;
+        nsresult rv = OutputScanlines(&suspend);
+        if (NS_FAILED(rv))
+          return rv;
+
+        if (suspend) {
+          if (mInfo.output_scanline == 0) {
+            /* didn't manage to read any lines - flag so we don't call
+               jpeg_start_output() multiple times for the same scan */
+            mInfo.output_scanline = 0xffffff;
+          }
+          PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+                 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
+          return NS_OK; /* I/O suspension */
+        }
+
+        if (mInfo.output_scanline == mInfo.output_height)
+        {
+          if (!jpeg_finish_output(&mInfo)) {
+            PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+                   ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
+            return NS_OK; /* I/O suspension */
+          }
+
+          if (jpeg_input_complete(&mInfo) &&
+              (mInfo.input_scan_number == mInfo.output_scan_number))
+            break;
+
+          mInfo.output_scanline = 0;
+        }
+      }
+
+      mState = JPEG_DONE;
+    }
+  }
+
+  case JPEG_DONE:
+  {
+    LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
+
+    /* Step 7: Finish decompression */
+
+    if (jpeg_finish_decompress(&mInfo) == FALSE) {
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
+      return NS_OK; /* I/O suspension */
+    }
+
+    mState = JPEG_SINK_NON_JPEG_TRAILER;
+
+    /* we're done dude */
+    break;
+  }
+  case JPEG_SINK_NON_JPEG_TRAILER:
+    PR_LOG(gJPEGlog, PR_LOG_DEBUG,
+           ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
+
+    break;
+
+  case JPEG_ERROR:
+    PR_LOG(gJPEGlog, PR_LOG_DEBUG,
+           ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_ERROR case\n", this));
+    return NS_ERROR_FAILURE;
+  }
+
+  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+         ("} (end of function)"));
+  return NS_OK;
+}
+
+void
+nsJPEGDecoder::NotifyDone(PRBool aSuccess)
+{
+  // We should only be called once
+  NS_ABORT_IF_FALSE(!mNotifiedDone, "calling NotifyDone twice!");
+
+  // Notify
+  if (mObserver)
+    mObserver->OnStopFrame(nsnull, 0);
+  if (aSuccess)
+    mImage->DecodingComplete();
+  if (mObserver) {
+    mObserver->OnStopContainer(nsnull, mImage);
+    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
+                            nsnull);
+  }
+
+  // Mark that we've been called
+  mNotifiedDone = PR_TRUE;
+}
+
+nsresult
+nsJPEGDecoder::OutputScanlines(PRBool* suspend)
+{
+  *suspend = PR_FALSE;
+
+  const PRUint32 top = mInfo.output_scanline;
+  nsresult rv = NS_OK;
+
+  while ((mInfo.output_scanline < mInfo.output_height)) {
+      /* Use the Cairo image buffer as scanline buffer */
+      PRUint32 *imageRow = ((PRUint32*)mImageData) +
+                           (mInfo.output_scanline * mInfo.output_width);
+
+      if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) {
+        /* Special case: scanline will be directly converted into packed ARGB */
+        if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
+          *suspend = PR_TRUE; /* suspend */
+          break;
+        }
+        continue; /* all done for this row! */
+      }
+
+      JSAMPROW sampleRow = (JSAMPROW)imageRow;
+      if (mInfo.output_components == 3) {
+        /* Put the pixels at end of row to enable in-place expansion */
+        sampleRow += mInfo.output_width;
+      }
+
+      /* Request one scanline.  Returns 0 or 1 scanlines. */    
+      if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
+        *suspend = PR_TRUE; /* suspend */
+        break;
+      }
+
+      if (mTransform) {
+        JSAMPROW source = sampleRow;
+        if (mInfo.out_color_space == JCS_GRAYSCALE) {
+          /* Convert from the 1byte grey pixels at begin of row 
+             to the 3byte RGB byte pixels at 'end' of row */
+          sampleRow += mInfo.output_width;
+        }
+        qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
+        /* Move 3byte RGB data to end of row */
+        if (mInfo.out_color_space == JCS_CMYK) {
+          memmove(sampleRow + mInfo.output_width,
+                  sampleRow,
+                  3 * mInfo.output_width);
+          sampleRow += mInfo.output_width;
+        }
+      } else {
+        if (mInfo.out_color_space == JCS_CMYK) {
+          /* Convert from CMYK to RGB */
+          /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
+          /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
+          cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
+          sampleRow += mInfo.output_width;
+        }
+        if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
+          /* No embedded ICC profile - treat as sRGB */
+          qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
+          if (transform) {
+            qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
+          }
+        }
+      }
+
+      // counter for while() loops below
+      PRUint32 idx = mInfo.output_width;
+
+      // copy as bytes until source pointer is 32-bit-aligned
+      for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
+        *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
+        sampleRow += 3;
+      }
+
+      // copy pixels in blocks of 4
+      while (idx >= 4) {
+        GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
+        idx       -=  4;
+        sampleRow += 12;
+        imageRow  +=  4;
+      }
+
+      // copy remaining pixel(s)
+      while (idx--) {
+        // 32-bit read of final pixel will exceed buffer, so read bytes
+        *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
+        sampleRow += 3;
+      }
+  }
+
+  if (top != mInfo.output_scanline) {
+      nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
+      rv = mImage->FrameUpdated(0, r);
+      if (mObserver)
+        mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
+  }
+
+  return rv;
+}
+
+
+/* Override the standard error method in the IJG JPEG decoder code. */
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+  decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
+
+  /* Convert error to a browser error code */
+  nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
+                      ? NS_ERROR_OUT_OF_MEMORY
+                      : NS_ERROR_FAILURE;
+
+#ifdef DEBUG
+  char buffer[JMSG_LENGTH_MAX];
+
+  /* Create the message */
+  (*err->pub.format_message) (cinfo, buffer);
+
+  fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
+#endif
+
+  /* Return control to the setjmp point. */
+  longjmp(err->setjmp_buffer, error_code);
+}
+
+/******************************************************************************/
+/*-----------------------------------------------------------------------------
+ * This is the callback routine from the IJG JPEG library used to supply new
+ * data to the decompressor when its input buffer is exhausted.  It juggles
+ * multiple buffers in an attempt to avoid unnecessary copying of input data.
+ *
+ * (A simpler scheme is possible: It's much easier to use only a single
+ * buffer; when fill_input_buffer() is called, move any unconsumed data
+ * (beyond the current pointer/count) down to the beginning of this buffer and
+ * then load new data into the remaining buffer space.  This approach requires
+ * a little more data copying but is far easier to get right.)
+ *
+ * At any one time, the JPEG decompressor is either reading from the necko
+ * input buffer, which is volatile across top-level calls to the IJG library,
+ * or the "backtrack" buffer.  The backtrack buffer contains the remaining
+ * unconsumed data from the necko buffer after parsing was suspended due
+ * to insufficient data in some previous call to the IJG library.
+ *
+ * When suspending, the decompressor will back up to a convenient restart
+ * point (typically the start of the current MCU). The variables
+ * next_input_byte & bytes_in_buffer indicate where the restart point will be
+ * if the current call returns FALSE.  Data beyond this point must be
+ * rescanned after resumption, so it must be preserved in case the decompressor
+ * decides to backtrack.
+ *
+ * Returns:
+ *  TRUE if additional data is available, FALSE if no data present and
+ *   the JPEG library should therefore suspend processing of input stream
+ *---------------------------------------------------------------------------*/
+
+/******************************************************************************/
+/* data source manager method                                                 */
+/******************************************************************************/
+
+
+/******************************************************************************/
+/* data source manager method 
+        Initialize source.  This is called by jpeg_read_header() before any
+        data is actually read.  May leave
+        bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
+        will occur immediately).
+*/
+METHODDEF(void)
+init_source (j_decompress_ptr jd)
+{
+}
+
+/******************************************************************************/
+/* data source manager method
+        Skip num_bytes worth of data.  The buffer pointer and count should
+        be advanced over num_bytes input bytes, refilling the buffer as
+        needed.  This is used to skip over a potentially large amount of
+        uninteresting data (such as an APPn marker).  In some applications
+        it may be possible to optimize away the reading of the skipped data,
+        but it's not clear that being smart is worth much trouble; large
+        skips are uncommon.  bytes_in_buffer may be zero on return.
+        A zero or negative skip count should be treated as a no-op.
+*/
+METHODDEF(void)
+skip_input_data (j_decompress_ptr jd, long num_bytes)
+{
+  struct jpeg_source_mgr *src = jd->src;
+  nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
+
+  if (num_bytes > (long)src->bytes_in_buffer) {
+    /*
+     * Can't skip it all right now until we get more data from
+     * network stream. Set things up so that fill_input_buffer
+     * will skip remaining amount.
+     */
+    decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
+    src->next_input_byte += src->bytes_in_buffer;
+    src->bytes_in_buffer = 0;
+
+  } else {
+    /* Simple case. Just advance buffer pointer */
+
+    src->bytes_in_buffer -= (size_t)num_bytes;
+    src->next_input_byte += num_bytes;
+  }
+}
+
+
+/******************************************************************************/
+/* data source manager method
+        This is called whenever bytes_in_buffer has reached zero and more
+        data is wanted.  In typical applications, it should read fresh data
+        into the buffer (ignoring the current state of next_input_byte and
+        bytes_in_buffer), reset the pointer & count to the start of the
+        buffer, and return TRUE indicating that the buffer has been reloaded.
+        It is not necessary to fill the buffer entirely, only to obtain at
+        least one more byte.  bytes_in_buffer MUST be set to a positive value
+        if TRUE is returned.  A FALSE return should only be used when I/O
+        suspension is desired.
+*/
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr jd)
+{
+  struct jpeg_source_mgr *src = jd->src;
+  nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
+
+  if (decoder->mReading) {
+    const JOCTET *new_buffer = decoder->mSegment;
+    PRUint32 new_buflen = decoder->mSegmentLen;
+  
+    if (!new_buffer || new_buflen == 0)
+      return PR_FALSE; /* suspend */
+
+    decoder->mSegmentLen = 0;
+
+    if (decoder->mBytesToSkip) {
+      if (decoder->mBytesToSkip < new_buflen) {
+        /* All done skipping bytes; Return what's left. */
+        new_buffer += decoder->mBytesToSkip;
+        new_buflen -= decoder->mBytesToSkip;
+        decoder->mBytesToSkip = 0;
+      } else {
+        /* Still need to skip some more data in the future */
+        decoder->mBytesToSkip -= (size_t)new_buflen;
+        return PR_FALSE; /* suspend */
+      }
+    }
+
+      decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
+
+    src->next_input_byte = new_buffer;
+    src->bytes_in_buffer = (size_t)new_buflen;
+    decoder->mReading = PR_FALSE;
+
+    return PR_TRUE;
+  }
+
+  if (src->next_input_byte != decoder->mSegment) {
+    /* Backtrack data has been permanently consumed. */
+    decoder->mBackBufferUnreadLen = 0;
+    decoder->mBackBufferLen = 0;
+  }
+
+  /* Save remainder of netlib buffer in backtrack buffer */
+  const PRUint32 new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
+ 
+  /* Make sure backtrack buffer is big enough to hold new data. */
+  if (decoder->mBackBufferSize < new_backtrack_buflen) {
+    /* Check for malformed MARKER segment lengths, before allocating space for it */
+    if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
+      my_error_exit((j_common_ptr)(&decoder->mInfo));
+    }
+
+    /* Round up to multiple of 256 bytes. */
+    const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
+    JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
+    /* Check for OOM */
+    if (!buf) {
+      decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
+      my_error_exit((j_common_ptr)(&decoder->mInfo));
+    }
+    decoder->mBackBuffer = buf;
+    decoder->mBackBufferSize = roundup_buflen;
+  }
+
+  /* Copy remainder of netlib segment into backtrack buffer. */
+  memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
+          src->next_input_byte,
+          src->bytes_in_buffer);
+
+  /* Point to start of data to be rescanned. */
+  src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen - decoder->mBackBufferUnreadLen;
+  src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
+  decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
+  decoder->mReading = PR_TRUE;
+
+  return PR_FALSE;
+}
+
+/******************************************************************************/
+/* data source manager method */
+/*
+ * Terminate source --- called by jpeg_finish_decompress() after all
+ * data has been read to clean up JPEG source manager. NOT called by 
+ * jpeg_abort() or jpeg_destroy().
+ */
+METHODDEF(void)
+term_source (j_decompress_ptr jd)
+{
+  nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
+
+  // This function shouldn't be called if we ran into an error we didn't
+  // recover from.
+  NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
+                    "Calling term_source on a JPEG with mState == JPEG_ERROR!");
+
+  // Notify
+  decoder->NotifyDone(/* aSuccess = */ PR_TRUE);
+}
+
+
+/**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ *      R = Y                + 1.40200 * Cr
+ *      G = Y - 0.34414 * Cb - 0.71414 * Cr
+ *      B = Y + 1.77200 * Cb
+ * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ * Notice that Y, being an integral input, does not contribute any fraction
+ * so it need not participate in the rounding.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times Cb and Cr for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable.  It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+ * values for the G calculation are left scaled up, since we must add them
+ * together before rounding.
+ */
+
+#define SCALEBITS       16      /* speediest right-shift on some machines */
+
+/* Use static tables for color processing. */
+/* Four tables, each 256 entries of 4 bytes totals 4K which is not bad... */
+
+const int Cr_r_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
+  0xffffff4dU, 0xffffff4eU, 0xffffff4fU, 0xffffff51U, 0xffffff52U, 0xffffff54U, 
+  0xffffff55U, 0xffffff56U, 0xffffff58U, 0xffffff59U, 0xffffff5bU, 0xffffff5cU, 
+  0xffffff5dU, 0xffffff5fU, 0xffffff60U, 0xffffff62U, 0xffffff63U, 0xffffff64U, 
+  0xffffff66U, 0xffffff67U, 0xffffff69U, 0xffffff6aU, 0xffffff6bU, 0xffffff6dU, 
+  0xffffff6eU, 0xffffff70U, 0xffffff71U, 0xffffff72U, 0xffffff74U, 0xffffff75U, 
+  0xffffff77U, 0xffffff78U, 0xffffff79U, 0xffffff7bU, 0xffffff7cU, 0xffffff7eU, 
+  0xffffff7fU, 0xffffff80U, 0xffffff82U, 0xffffff83U, 0xffffff85U, 0xffffff86U, 
+  0xffffff87U, 0xffffff89U, 0xffffff8aU, 0xffffff8cU, 0xffffff8dU, 0xffffff8eU, 
+  0xffffff90U, 0xffffff91U, 0xffffff93U, 0xffffff94U, 0xffffff95U, 0xffffff97U, 
+  0xffffff98U, 0xffffff9aU, 0xffffff9bU, 0xffffff9cU, 0xffffff9eU, 0xffffff9fU, 
+  0xffffffa1U, 0xffffffa2U, 0xffffffa3U, 0xffffffa5U, 0xffffffa6U, 0xffffffa8U, 
+  0xffffffa9U, 0xffffffaaU, 0xffffffacU, 0xffffffadU, 0xffffffafU, 0xffffffb0U, 
+  0xffffffb1U, 0xffffffb3U, 0xffffffb4U, 0xffffffb6U, 0xffffffb7U, 0xffffffb8U, 
+  0xffffffbaU, 0xffffffbbU, 0xffffffbdU, 0xffffffbeU, 0xffffffc0U, 0xffffffc1U, 
+  0xffffffc2U, 0xffffffc4U, 0xffffffc5U, 0xffffffc7U, 0xffffffc8U, 0xffffffc9U, 
+  0xffffffcbU, 0xffffffccU, 0xffffffceU, 0xffffffcfU, 0xffffffd0U, 0xffffffd2U, 
+  0xffffffd3U, 0xffffffd5U, 0xffffffd6U, 0xffffffd7U, 0xffffffd9U, 0xffffffdaU, 
+  0xffffffdcU, 0xffffffddU, 0xffffffdeU, 0xffffffe0U, 0xffffffe1U, 0xffffffe3U, 
+  0xffffffe4U, 0xffffffe5U, 0xffffffe7U, 0xffffffe8U, 0xffffffeaU, 0xffffffebU, 
+  0xffffffecU, 0xffffffeeU, 0xffffffefU, 0xfffffff1U, 0xfffffff2U, 0xfffffff3U, 
+  0xfffffff5U, 0xfffffff6U, 0xfffffff8U, 0xfffffff9U, 0xfffffffaU, 0xfffffffcU, 
+  0xfffffffdU, 0xffffffffU,       0x00U,       0x01U,       0x03U,       0x04U, 
+        0x06U,       0x07U,       0x08U,       0x0aU,       0x0bU,       0x0dU, 
+        0x0eU,       0x0fU,       0x11U,       0x12U,       0x14U,       0x15U, 
+        0x16U,       0x18U,       0x19U,       0x1bU,       0x1cU,       0x1dU, 
+        0x1fU,       0x20U,       0x22U,       0x23U,       0x24U,       0x26U, 
+        0x27U,       0x29U,       0x2aU,       0x2bU,       0x2dU,       0x2eU, 
+        0x30U,       0x31U,       0x32U,       0x34U,       0x35U,       0x37U, 
+        0x38U,       0x39U,       0x3bU,       0x3cU,       0x3eU,       0x3fU, 
+        0x40U,       0x42U,       0x43U,       0x45U,       0x46U,       0x48U, 
+        0x49U,       0x4aU,       0x4cU,       0x4dU,       0x4fU,       0x50U, 
+        0x51U,       0x53U,       0x54U,       0x56U,       0x57U,       0x58U, 
+        0x5aU,       0x5bU,       0x5dU,       0x5eU,       0x5fU,       0x61U, 
+        0x62U,       0x64U,       0x65U,       0x66U,       0x68U,       0x69U, 
+        0x6bU,       0x6cU,       0x6dU,       0x6fU,       0x70U,       0x72U, 
+        0x73U,       0x74U,       0x76U,       0x77U,       0x79U,       0x7aU, 
+        0x7bU,       0x7dU,       0x7eU,       0x80U,       0x81U,       0x82U, 
+        0x84U,       0x85U,       0x87U,       0x88U,       0x89U,       0x8bU, 
+        0x8cU,       0x8eU,       0x8fU,       0x90U,       0x92U,       0x93U, 
+        0x95U,       0x96U,       0x97U,       0x99U,       0x9aU,       0x9cU, 
+        0x9dU,       0x9eU,       0xa0U,       0xa1U,       0xa3U,       0xa4U, 
+        0xa5U,       0xa7U,       0xa8U,       0xaaU,       0xabU,       0xacU, 
+        0xaeU,       0xafU,       0xb1U,       0xb2U
+  };
+
+const int Cb_b_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
+  0xffffff1dU, 0xffffff1fU, 0xffffff21U, 0xffffff22U, 0xffffff24U, 0xffffff26U, 
+  0xffffff28U, 0xffffff2aU, 0xffffff2bU, 0xffffff2dU, 0xffffff2fU, 0xffffff31U, 
+  0xffffff32U, 0xffffff34U, 0xffffff36U, 0xffffff38U, 0xffffff3aU, 0xffffff3bU, 
+  0xffffff3dU, 0xffffff3fU, 0xffffff41U, 0xffffff42U, 0xffffff44U, 0xffffff46U, 
+  0xffffff48U, 0xffffff49U, 0xffffff4bU, 0xffffff4dU, 0xffffff4fU, 0xffffff51U, 
+  0xffffff52U, 0xffffff54U, 0xffffff56U, 0xffffff58U, 0xffffff59U, 0xffffff5bU, 
+  0xffffff5dU, 0xffffff5fU, 0xffffff61U, 0xffffff62U, 0xffffff64U, 0xffffff66U, 
+  0xffffff68U, 0xffffff69U, 0xffffff6bU, 0xffffff6dU, 0xffffff6fU, 0xffffff70U, 
+  0xffffff72U, 0xffffff74U, 0xffffff76U, 0xffffff78U, 0xffffff79U, 0xffffff7bU, 
+  0xffffff7dU, 0xffffff7fU, 0xffffff80U, 0xffffff82U, 0xffffff84U, 0xffffff86U, 
+  0xffffff88U, 0xffffff89U, 0xffffff8bU, 0xffffff8dU, 0xffffff8fU, 0xffffff90U, 
+  0xffffff92U, 0xffffff94U, 0xffffff96U, 0xffffff97U, 0xffffff99U, 0xffffff9bU, 
+  0xffffff9dU, 0xffffff9fU, 0xffffffa0U, 0xffffffa2U, 0xffffffa4U, 0xffffffa6U, 
+  0xffffffa7U, 0xffffffa9U, 0xffffffabU, 0xffffffadU, 0xffffffaeU, 0xffffffb0U, 
+  0xffffffb2U, 0xffffffb4U, 0xffffffb6U, 0xffffffb7U, 0xffffffb9U, 0xffffffbbU, 
+  0xffffffbdU, 0xffffffbeU, 0xffffffc0U, 0xffffffc2U, 0xffffffc4U, 0xffffffc6U, 
+  0xffffffc7U, 0xffffffc9U, 0xffffffcbU, 0xffffffcdU, 0xffffffceU, 0xffffffd0U, 
+  0xffffffd2U, 0xffffffd4U, 0xffffffd5U, 0xffffffd7U, 0xffffffd9U, 0xffffffdbU, 
+  0xffffffddU, 0xffffffdeU, 0xffffffe0U, 0xffffffe2U, 0xffffffe4U, 0xffffffe5U, 
+  0xffffffe7U, 0xffffffe9U, 0xffffffebU, 0xffffffedU, 0xffffffeeU, 0xfffffff0U, 
+  0xfffffff2U, 0xfffffff4U, 0xfffffff5U, 0xfffffff7U, 0xfffffff9U, 0xfffffffbU, 
+  0xfffffffcU, 0xfffffffeU,       0x00U,       0x02U,       0x04U,       0x05U, 
+        0x07U,       0x09U,       0x0bU,       0x0cU,       0x0eU,       0x10U, 
+        0x12U,       0x13U,       0x15U,       0x17U,       0x19U,       0x1bU, 
+        0x1cU,       0x1eU,       0x20U,       0x22U,       0x23U,       0x25U, 
+        0x27U,       0x29U,       0x2bU,       0x2cU,       0x2eU,       0x30U, 
+        0x32U,       0x33U,       0x35U,       0x37U,       0x39U,       0x3aU, 
+        0x3cU,       0x3eU,       0x40U,       0x42U,       0x43U,       0x45U, 
+        0x47U,       0x49U,       0x4aU,       0x4cU,       0x4eU,       0x50U, 
+        0x52U,       0x53U,       0x55U,       0x57U,       0x59U,       0x5aU, 
+        0x5cU,       0x5eU,       0x60U,       0x61U,       0x63U,       0x65U, 
+        0x67U,       0x69U,       0x6aU,       0x6cU,       0x6eU,       0x70U, 
+        0x71U,       0x73U,       0x75U,       0x77U,       0x78U,       0x7aU, 
+        0x7cU,       0x7eU,       0x80U,       0x81U,       0x83U,       0x85U, 
+        0x87U,       0x88U,       0x8aU,       0x8cU,       0x8eU,       0x90U, 
+        0x91U,       0x93U,       0x95U,       0x97U,       0x98U,       0x9aU, 
+        0x9cU,       0x9eU,       0x9fU,       0xa1U,       0xa3U,       0xa5U, 
+        0xa7U,       0xa8U,       0xaaU,       0xacU,       0xaeU,       0xafU, 
+        0xb1U,       0xb3U,       0xb5U,       0xb7U,       0xb8U,       0xbaU, 
+        0xbcU,       0xbeU,       0xbfU,       0xc1U,       0xc3U,       0xc5U, 
+        0xc6U,       0xc8U,       0xcaU,       0xccU,       0xceU,       0xcfU, 
+        0xd1U,       0xd3U,       0xd5U,       0xd6U,       0xd8U,       0xdaU, 
+        0xdcU,       0xdeU,       0xdfU,       0xe1U
+  };
+
+const int Cr_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
+    0x5b6900U,   0x5ab22eU,   0x59fb5cU,   0x59448aU,   0x588db8U,   0x57d6e6U, 
+    0x572014U,   0x566942U,   0x55b270U,   0x54fb9eU,   0x5444ccU,   0x538dfaU, 
+    0x52d728U,   0x522056U,   0x516984U,   0x50b2b2U,   0x4ffbe0U,   0x4f450eU, 
+    0x4e8e3cU,   0x4dd76aU,   0x4d2098U,   0x4c69c6U,   0x4bb2f4U,   0x4afc22U, 
+    0x4a4550U,   0x498e7eU,   0x48d7acU,   0x4820daU,   0x476a08U,   0x46b336U, 
+    0x45fc64U,   0x454592U,   0x448ec0U,   0x43d7eeU,   0x43211cU,   0x426a4aU, 
+    0x41b378U,   0x40fca6U,   0x4045d4U,   0x3f8f02U,   0x3ed830U,   0x3e215eU, 
+    0x3d6a8cU,   0x3cb3baU,   0x3bfce8U,   0x3b4616U,   0x3a8f44U,   0x39d872U, 
+    0x3921a0U,   0x386aceU,   0x37b3fcU,   0x36fd2aU,   0x364658U,   0x358f86U, 
+    0x34d8b4U,   0x3421e2U,   0x336b10U,   0x32b43eU,   0x31fd6cU,   0x31469aU, 
+    0x308fc8U,   0x2fd8f6U,   0x2f2224U,   0x2e6b52U,   0x2db480U,   0x2cfdaeU, 
+    0x2c46dcU,   0x2b900aU,   0x2ad938U,   0x2a2266U,   0x296b94U,   0x28b4c2U, 
+    0x27fdf0U,   0x27471eU,   0x26904cU,   0x25d97aU,   0x2522a8U,   0x246bd6U, 
+    0x23b504U,   0x22fe32U,   0x224760U,   0x21908eU,   0x20d9bcU,   0x2022eaU, 
+    0x1f6c18U,   0x1eb546U,   0x1dfe74U,   0x1d47a2U,   0x1c90d0U,   0x1bd9feU, 
+    0x1b232cU,   0x1a6c5aU,   0x19b588U,   0x18feb6U,   0x1847e4U,   0x179112U, 
+    0x16da40U,   0x16236eU,   0x156c9cU,   0x14b5caU,   0x13fef8U,   0x134826U, 
+    0x129154U,   0x11da82U,   0x1123b0U,   0x106cdeU,    0xfb60cU,    0xeff3aU, 
+     0xe4868U,    0xd9196U,    0xcdac4U,    0xc23f2U,    0xb6d20U,    0xab64eU, 
+     0x9ff7cU,    0x948aaU,    0x891d8U,    0x7db06U,    0x72434U,    0x66d62U, 
+     0x5b690U,    0x4ffbeU,    0x448ecU,    0x3921aU,    0x2db48U,    0x22476U, 
+     0x16da4U,     0xb6d2U,        0x0U, 0xffff492eU, 0xfffe925cU, 0xfffddb8aU, 
+  0xfffd24b8U, 0xfffc6de6U, 0xfffbb714U, 0xfffb0042U, 0xfffa4970U, 0xfff9929eU, 
+  0xfff8dbccU, 0xfff824faU, 0xfff76e28U, 0xfff6b756U, 0xfff60084U, 0xfff549b2U, 
+  0xfff492e0U, 0xfff3dc0eU, 0xfff3253cU, 0xfff26e6aU, 0xfff1b798U, 0xfff100c6U, 
+  0xfff049f4U, 0xffef9322U, 0xffeedc50U, 0xffee257eU, 0xffed6eacU, 0xffecb7daU, 
+  0xffec0108U, 0xffeb4a36U, 0xffea9364U, 0xffe9dc92U, 0xffe925c0U, 0xffe86eeeU, 
+  0xffe7b81cU, 0xffe7014aU, 0xffe64a78U, 0xffe593a6U, 0xffe4dcd4U, 0xffe42602U, 
+  0xffe36f30U, 0xffe2b85eU, 0xffe2018cU, 0xffe14abaU, 0xffe093e8U, 0xffdfdd16U, 
+  0xffdf2644U, 0xffde6f72U, 0xffddb8a0U, 0xffdd01ceU, 0xffdc4afcU, 0xffdb942aU, 
+  0xffdadd58U, 0xffda2686U, 0xffd96fb4U, 0xffd8b8e2U, 0xffd80210U, 0xffd74b3eU, 
+  0xffd6946cU, 0xffd5dd9aU, 0xffd526c8U, 0xffd46ff6U, 0xffd3b924U, 0xffd30252U, 
+  0xffd24b80U, 0xffd194aeU, 0xffd0dddcU, 0xffd0270aU, 0xffcf7038U, 0xffceb966U, 
+  0xffce0294U, 0xffcd4bc2U, 0xffcc94f0U, 0xffcbde1eU, 0xffcb274cU, 0xffca707aU, 
+  0xffc9b9a8U, 0xffc902d6U, 0xffc84c04U, 0xffc79532U, 0xffc6de60U, 0xffc6278eU, 
+  0xffc570bcU, 0xffc4b9eaU, 0xffc40318U, 0xffc34c46U, 0xffc29574U, 0xffc1dea2U, 
+  0xffc127d0U, 0xffc070feU, 0xffbfba2cU, 0xffbf035aU, 0xffbe4c88U, 0xffbd95b6U, 
+  0xffbcdee4U, 0xffbc2812U, 0xffbb7140U, 0xffbaba6eU, 0xffba039cU, 0xffb94ccaU, 
+  0xffb895f8U, 0xffb7df26U, 0xffb72854U, 0xffb67182U, 0xffb5bab0U, 0xffb503deU, 
+  0xffb44d0cU, 0xffb3963aU, 0xffb2df68U, 0xffb22896U, 0xffb171c4U, 0xffb0baf2U, 
+  0xffb00420U, 0xffaf4d4eU, 0xffae967cU, 0xffaddfaaU, 0xffad28d8U, 0xffac7206U, 
+  0xffabbb34U, 0xffab0462U, 0xffaa4d90U, 0xffa996beU, 0xffa8dfecU, 0xffa8291aU, 
+  0xffa77248U, 0xffa6bb76U, 0xffa604a4U, 0xffa54dd2U
+ };
+
+const int Cb_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
+    0x2c8d00U,   0x2c34e6U,   0x2bdcccU,   0x2b84b2U,   0x2b2c98U,   0x2ad47eU, 
+    0x2a7c64U,   0x2a244aU,   0x29cc30U,   0x297416U,   0x291bfcU,   0x28c3e2U, 
+    0x286bc8U,   0x2813aeU,   0x27bb94U,   0x27637aU,   0x270b60U,   0x26b346U, 
+    0x265b2cU,   0x260312U,   0x25aaf8U,   0x2552deU,   0x24fac4U,   0x24a2aaU, 
+    0x244a90U,   0x23f276U,   0x239a5cU,   0x234242U,   0x22ea28U,   0x22920eU, 
+    0x2239f4U,   0x21e1daU,   0x2189c0U,   0x2131a6U,   0x20d98cU,   0x208172U, 
+    0x202958U,   0x1fd13eU,   0x1f7924U,   0x1f210aU,   0x1ec8f0U,   0x1e70d6U, 
+    0x1e18bcU,   0x1dc0a2U,   0x1d6888U,   0x1d106eU,   0x1cb854U,   0x1c603aU, 
+    0x1c0820U,   0x1bb006U,   0x1b57ecU,   0x1affd2U,   0x1aa7b8U,   0x1a4f9eU, 
+    0x19f784U,   0x199f6aU,   0x194750U,   0x18ef36U,   0x18971cU,   0x183f02U, 
+    0x17e6e8U,   0x178eceU,   0x1736b4U,   0x16de9aU,   0x168680U,   0x162e66U, 
+    0x15d64cU,   0x157e32U,   0x152618U,   0x14cdfeU,   0x1475e4U,   0x141dcaU, 
+    0x13c5b0U,   0x136d96U,   0x13157cU,   0x12bd62U,   0x126548U,   0x120d2eU, 
+    0x11b514U,   0x115cfaU,   0x1104e0U,   0x10acc6U,   0x1054acU,    0xffc92U, 
+     0xfa478U,    0xf4c5eU,    0xef444U,    0xe9c2aU,    0xe4410U,    0xdebf6U, 
+     0xd93dcU,    0xd3bc2U,    0xce3a8U,    0xc8b8eU,    0xc3374U,    0xbdb5aU, 
+     0xb8340U,    0xb2b26U,    0xad30cU,    0xa7af2U,    0xa22d8U,    0x9cabeU, 
+     0x972a4U,    0x91a8aU,    0x8c270U,    0x86a56U,    0x8123cU,    0x7ba22U, 
+     0x76208U,    0x709eeU,    0x6b1d4U,    0x659baU,    0x601a0U,    0x5a986U, 
+     0x5516cU,    0x4f952U,    0x4a138U,    0x4491eU,    0x3f104U,    0x398eaU, 
+     0x340d0U,    0x2e8b6U,    0x2909cU,    0x23882U,    0x1e068U,    0x1884eU, 
+     0x13034U,     0xd81aU,     0x8000U,     0x27e6U, 0xffffcfccU, 0xffff77b2U,
+  0xffff1f98U, 0xfffec77eU, 0xfffe6f64U, 0xfffe174aU, 0xfffdbf30U, 0xfffd6716U,
+  0xfffd0efcU, 0xfffcb6e2U, 0xfffc5ec8U, 0xfffc06aeU, 0xfffbae94U, 0xfffb567aU,
+  0xfffafe60U, 0xfffaa646U, 0xfffa4e2cU, 0xfff9f612U, 0xfff99df8U, 0xfff945deU,
+  0xfff8edc4U, 0xfff895aaU, 0xfff83d90U, 0xfff7e576U, 0xfff78d5cU, 0xfff73542U,
+  0xfff6dd28U, 0xfff6850eU, 0xfff62cf4U, 0xfff5d4daU, 0xfff57cc0U, 0xfff524a6U,
+  0xfff4cc8cU, 0xfff47472U, 0xfff41c58U, 0xfff3c43eU, 0xfff36c24U, 0xfff3140aU,
+  0xfff2bbf0U, 0xfff263d6U, 0xfff20bbcU, 0xfff1b3a2U, 0xfff15b88U, 0xfff1036eU,
+  0xfff0ab54U, 0xfff0533aU, 0xffeffb20U, 0xffefa306U, 0xffef4aecU, 0xffeef2d2U,
+  0xffee9ab8U, 0xffee429eU, 0xffedea84U, 0xffed926aU, 0xffed3a50U, 0xffece236U,
+  0xffec8a1cU, 0xffec3202U, 0xffebd9e8U, 0xffeb81ceU, 0xffeb29b4U, 0xffead19aU,
+  0xffea7980U, 0xffea2166U, 0xffe9c94cU, 0xffe97132U, 0xffe91918U, 0xffe8c0feU,
+  0xffe868e4U, 0xffe810caU, 0xffe7b8b0U, 0xffe76096U, 0xffe7087cU, 0xffe6b062U,
+  0xffe65848U, 0xffe6002eU, 0xffe5a814U, 0xffe54ffaU, 0xffe4f7e0U, 0xffe49fc6U,
+  0xffe447acU, 0xffe3ef92U, 0xffe39778U, 0xffe33f5eU, 0xffe2e744U, 0xffe28f2aU,
+  0xffe23710U, 0xffe1def6U, 0xffe186dcU, 0xffe12ec2U, 0xffe0d6a8U, 0xffe07e8eU,
+  0xffe02674U, 0xffdfce5aU, 0xffdf7640U, 0xffdf1e26U, 0xffdec60cU, 0xffde6df2U,
+  0xffde15d8U, 0xffddbdbeU, 0xffdd65a4U, 0xffdd0d8aU, 0xffdcb570U, 0xffdc5d56U,
+  0xffdc053cU, 0xffdbad22U, 0xffdb5508U, 0xffdafceeU, 0xffdaa4d4U, 0xffda4cbaU,
+  0xffd9f4a0U, 0xffd99c86U, 0xffd9446cU, 0xffd8ec52U, 0xffd89438U, 0xffd83c1eU,
+  0xffd7e404U, 0xffd78beaU, 0xffd733d0U, 0xffd6dbb6U, 0xffd6839cU, 0xffd62b82U,
+  0xffd5d368U, 0xffd57b4eU, 0xffd52334U, 0xffd4cb1aU
+ };
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity.  This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit.  But some
+ * C compilers implement >> with an unsigned shift.  For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts.  SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS	INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft)  \
+	((shift_temp = (x)) < 0 ? \
+	 (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+	 (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+
+METHODDEF(void)
+ycc_rgb_convert_argb (j_decompress_ptr cinfo,
+                 JSAMPIMAGE input_buf, JDIMENSION input_row,
+                 JSAMPARRAY output_buf, int num_rows)
+{
+  JDIMENSION num_cols = cinfo->output_width;
+  JSAMPLE * range_limit = cinfo->sample_range_limit;
+
+  SHIFT_TEMPS
+
+  /* This is used if we don't have SSE2 */
+
+  while (--num_rows >= 0) {
+    JSAMPROW inptr0 = input_buf[0][input_row];
+    JSAMPROW inptr1 = input_buf[1][input_row];
+    JSAMPROW inptr2 = input_buf[2][input_row];
+    input_row++;
+    PRUint32 *outptr = (PRUint32 *) *output_buf++;
+    for (JDIMENSION col = 0; col < num_cols; col++) {
+      int y  = GETJSAMPLE(inptr0[col]);
+      int cb = GETJSAMPLE(inptr1[col]);
+      int cr = GETJSAMPLE(inptr2[col]);
+      JSAMPLE * range_limit_y = range_limit + y;
+      /* Range-limiting is essential due to noise introduced by DCT losses. */
+      outptr[col] = 0xFF000000 |
+                    ( range_limit_y[Cr_r_tab[cr]] << 16 ) |
+                    ( range_limit_y[((int) RIGHT_SHIFT(Cb_g_tab[cb] + Cr_g_tab[cr], SCALEBITS))] << 8 ) |
+                    ( range_limit_y[Cb_b_tab[cb]] );
+    }
+  }
+}
+
+
+/**************** Inverted CMYK -> RGB conversion **************/
+/*
+ * Input is (Inverted) CMYK stored as 4 bytes per pixel.
+ * Output is RGB stored as 3 bytes per pixel.
+ * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
+ * @param width Number of pixels in the row.
+ */
+static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
+{
+  /* Work from end to front to shrink from 4 bytes per pixel to 3 */
+  JSAMPROW in = row + width*4;
+  JSAMPROW out = in;
+
+  for (PRUint32 i = width; i > 0; i--) {
+    in -= 4;
+    out -= 3;
+
+    // Source is 'Inverted CMYK', output is RGB.
+    // See: http://www.easyrgb.com/math.php?MATH=M12#text12
+    // Or:  http://www.ilkeratalay.com/colorspacesfaq.php#rgb
+
+    // From CMYK to CMY
+    // C = ( C * ( 1 - K ) + K )
+    // M = ( M * ( 1 - K ) + K )
+    // Y = ( Y * ( 1 - K ) + K )
+
+    // From Inverted CMYK to CMY is thus:
+    // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
+    // Same for M and Y
+
+    // Convert from CMY (0..1) to RGB (0..1)
+    // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
+    // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
+    // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
+  
+    // Convert from Inverted CMYK (0..255) to RGB (0..255)
+    const PRUint32 iC = in[0];
+    const PRUint32 iM = in[1];
+    const PRUint32 iY = in[2];
+    const PRUint32 iK = in[3];
+    out[0] = iC*iK/255;   // Red
+    out[1] = iM*iK/255;   // Green
+    out[2] = iY*iK/255;   // Blue
+  }
+}
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <pavlov@netscape.com>
+ *   Bobby Holley <bobbyholley@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsJPEGDecoder_h__
+#define nsJPEGDecoder_h__
+
+#include "RasterImage.h"
+/* On Windows systems, RasterImage.h brings in 'windows.h', which defines INT32.
+ * But the jpeg decoder has its own definition of INT32. To avoid build issues,
+ * we need to undefine the version from 'windows.h'. */
+#undef INT32
+
+#include "imgIDecoder.h"
+
+#include "nsAutoPtr.h"
+
+#include "imgIDecoderObserver.h"
+#include "nsIInputStream.h"
+#include "nsIPipe.h"
+#include "qcms.h"
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+#include <setjmp.h>
+
+#define NS_JPEGDECODER_CID \
+{ /* 5871a422-1dd2-11b2-ab3f-e2e56be5da9c */         \
+     0x5871a422,                                     \
+     0x1dd2,                                         \
+     0x11b2,                                         \
+    {0xab, 0x3f, 0xe2, 0xe5, 0x6b, 0xe5, 0xda, 0x9c} \
+}
+
+typedef struct {
+    struct jpeg_error_mgr pub;  /* "public" fields for IJG library*/
+    jmp_buf setjmp_buffer;      /* For handling catastropic errors */
+} decoder_error_mgr;
+
+typedef enum {
+    JPEG_HEADER,                          /* Reading JFIF headers */
+    JPEG_START_DECOMPRESS,
+    JPEG_DECOMPRESS_PROGRESSIVE,          /* Output progressive pixels */
+    JPEG_DECOMPRESS_SEQUENTIAL,           /* Output sequential pixels */
+    JPEG_DONE,
+    JPEG_SINK_NON_JPEG_TRAILER,          /* Some image files have a */
+                                         /* non-JPEG trailer */
+    JPEG_ERROR    
+} jstate;
+
+namespace mozilla {
+namespace imagelib {
+class RasterImage;
+} // namespace imagelib
+} // namespace mozilla
+
+class nsJPEGDecoder : public imgIDecoder
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGIDECODER
+
+  nsJPEGDecoder();
+  virtual ~nsJPEGDecoder();
+
+  void NotifyDone(PRBool aSuccess);
+
+protected:
+  nsresult OutputScanlines(PRBool* suspend);
+
+public:
+  nsRefPtr<mozilla::imagelib::RasterImage> mImage;
+  nsCOMPtr<imgIDecoderObserver> mObserver;
+
+  PRUint32 mFlags;
+  PRUint8 *mImageData;
+
+  struct jpeg_decompress_struct mInfo;
+  struct jpeg_source_mgr mSourceMgr;
+  decoder_error_mgr mErr;
+  jstate mState;
+
+  PRUint32 mBytesToSkip;
+
+  const JOCTET *mSegment;   // The current segment we are decoding from
+  PRUint32 mSegmentLen;     // amount of data in mSegment
+
+  JOCTET *mBackBuffer;
+  PRUint32 mBackBufferLen; // Offset of end of active backtrack data
+  PRUint32 mBackBufferSize; // size in bytes what mBackBuffer was created with
+  PRUint32 mBackBufferUnreadLen; // amount of data currently in mBackBuffer
+
+  JOCTET  *mProfile;
+  PRUint32 mProfileLength;
+
+  qcms_profile *mInProfile;
+  qcms_transform *mTransform;
+
+  PRPackedBool mReading;
+  PRPackedBool mNotifiedDone;
+};
+
+#endif // nsJPEGDecoder_h__
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsBMPDecoder.cpp
+++ /dev/null
@@ -1,654 +0,0 @@
-/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla BMP Decoder.
- *
- * The Initial Developer of the Original Code is
- * Christian Biesinger <cbiesinger@web.de>.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Neil Rashbrook <neil@parkwaycc.co.uk>
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-/* I got the format description from http://www.daubnet.com/formats/BMP.html */
-
-/* This is a Cross-Platform BMP Decoder, which should work everywhere, including
- * Big-Endian machines like the PowerPC. */
-
-#include <stdlib.h>
-
-#include "nsBMPDecoder.h"
-
-#include "nsIInputStream.h"
-#include "RasterImage.h"
-#include "imgIContainerObserver.h"
-
-#include "prlog.h"
-
-namespace mozilla {
-namespace imagelib {
-
-#ifdef PR_LOGGING
-PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
-#endif
-
-// Convert from row (1..height) to absolute line (0..height-1)
-#define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
-#define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
-
-nsBMPDecoder::nsBMPDecoder()
-{
-    mColors = nsnull;
-    mRow = nsnull;
-    mCurPos = mPos = mNumColors = mRowBytes = 0;
-    mOldLine = mCurLine = 1; // Otherwise decoder will never start
-    mState = eRLEStateInitial;
-    mStateData = 0;
-    mLOH = WIN_HEADER_LENGTH;
-    mError = PR_FALSE;
-}
-
-nsBMPDecoder::~nsBMPDecoder()
-{
-  delete[] mColors;
-  if (mRow)
-      free(mRow);
-}
-
-nsresult
-nsBMPDecoder::InitInternal()
-{
-    PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", mImage.get()));
-
-    // Fire OnStartDecode at init time to support bug 512435
-    if (!IsSizeDecode() && mObserver)
-        mObserver->OnStartDecode(nsnull);
-
-    return NS_OK;
-}
-
-nsresult
-nsBMPDecoder::FinishInternal()
-{
-    // We should never make multiple frames
-    NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
-
-    // Send notifications if appropriate
-    if (!IsSizeDecode() && !mError && (GetFrameCount() == 1)) {
-        PostFrameStop();
-        mImage->DecodingComplete();
-        if (mObserver) {
-            mObserver->OnStopContainer(nsnull, mImage);
-            mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
-        }
-    }
-    return NS_OK;
-}
-
-// ----------------------------------------
-// Actual Data Processing
-// ----------------------------------------
-
-static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
-{
-    // find the rightmost 1
-    PRUint8 pos;
-    PRBool started = PR_FALSE;
-    aBegin = aLength = 0;
-    for (pos = 0; pos <= 31; pos++) {
-        if (!started && (aMask & (1 << pos))) {
-            aBegin = pos;
-            started = PR_TRUE;
-        }
-        else if (started && !(aMask & (1 << pos))) {
-            aLength = pos - aBegin;
-            break;
-        }
-    }
-}
-
-NS_METHOD nsBMPDecoder::CalcBitShift()
-{
-    PRUint8 begin, length;
-    // red
-    calcBitmask(mBitFields.red, begin, length);
-    mBitFields.redRightShift = begin;
-    mBitFields.redLeftShift = 8 - length;
-    // green
-    calcBitmask(mBitFields.green, begin, length);
-    mBitFields.greenRightShift = begin;
-    mBitFields.greenLeftShift = 8 - length;
-    // blue
-    calcBitmask(mBitFields.blue, begin, length);
-    mBitFields.blueRightShift = begin;
-    mBitFields.blueLeftShift = 8 - length;
-    return NS_OK;
-}
-
-nsresult
-nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
-{
-    // No forgiveness
-    if (mError)
-      return NS_ERROR_FAILURE;
-
-    // aCount=0 means EOF, mCurLine=0 means we're past end of image
-    if (!aCount || !mCurLine)
-        return NS_OK;
-
-    nsresult rv;
-    if (mPos < BFH_LENGTH) { /* In BITMAPFILEHEADER */
-        PRUint32 toCopy = BFH_LENGTH - mPos;
-        if (toCopy > aCount)
-            toCopy = aCount;
-        memcpy(mRawBuf + mPos, aBuffer, toCopy);
-        mPos += toCopy;
-        aCount -= toCopy;
-        aBuffer += toCopy;
-    }
-    if (mPos == BFH_LENGTH) {
-        ProcessFileHeader();
-        if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
-            mError = PR_TRUE;
-            return NS_ERROR_FAILURE;
-        }
-        if (mBFH.bihsize == OS2_BIH_LENGTH)
-            mLOH = OS2_HEADER_LENGTH;
-    }
-    if (mPos >= BFH_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
-        PRUint32 toCopy = mLOH - mPos;
-        if (toCopy > aCount)
-            toCopy = aCount;
-        memcpy(mRawBuf + (mPos - BFH_LENGTH), aBuffer, toCopy);
-        mPos += toCopy;
-        aCount -= toCopy;
-        aBuffer += toCopy;
-    }
-    if (mPos == mLOH) {
-        ProcessInfoHeader();
-        PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lix%lix%lu. compression=%lu\n",
-            mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
-        // Verify we support this bit depth
-        if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
-            mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
-          mError = PR_TRUE;
-          return NS_ERROR_UNEXPECTED;
-        }
-
-        // BMPs with negative width are invalid
-        // Reject extremely wide images to keep the math sane
-        const PRInt32 k64KWidth = 0x0000FFFF;
-        if (mBIH.width < 0 || mBIH.width > k64KWidth) {
-            mError = PR_TRUE;
-            return NS_ERROR_FAILURE;
-        }
-
-        PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
-
-        // Post our size to the superclass
-        PostSize(mBIH.width, real_height);
-
-        // We have the size. If we're doing a size decode, we got what
-        // we came for.
-        if (IsSizeDecode())
-            return NS_OK;
-
-        // We're doing a real decode.
-        mOldLine = mCurLine = real_height;
-
-        if (mBIH.bpp <= 8) {
-            mNumColors = 1 << mBIH.bpp;
-            if (mBIH.colors && mBIH.colors < mNumColors)
-                mNumColors = mBIH.colors;
-
-            // Always allocate 256 even though mNumColors might be smaller
-            mColors = new colorTable[256];
-            if (!mColors) {
-                mError = PR_TRUE;
-                return NS_ERROR_OUT_OF_MEMORY;
-            }
-
-            memset(mColors, 0, 256 * sizeof(colorTable));
-        }
-        else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
-            // Use default 5-5-5 format
-            mBitFields.red   = 0x7C00;
-            mBitFields.green = 0x03E0;
-            mBitFields.blue  = 0x001F;
-            CalcBitShift();
-        }
-
-        PRUint32 imageLength;
-        if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
-            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatARGB32,
-                                     (PRUint8**)&mImageData, &imageLength);
-        } else {
-            // mRow is not used for RLE encoded images
-            mRow = (PRUint8*)malloc((mBIH.width * mBIH.bpp)/8 + 4);
-            // +4 because the line is padded to a 4 bit boundary, but I don't want
-            // to make exact calculations here, that's unnecessary.
-            // Also, it compensates rounding error.
-            if (!mRow) {
-                mError = PR_TRUE;
-                return NS_ERROR_OUT_OF_MEMORY;
-            }
-            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatRGB24,
-                                     (PRUint8**)&mImageData, &imageLength);
-        }
-        NS_ENSURE_SUCCESS(rv, rv);
-        if (!mImageData) {
-            mError = PR_TRUE;
-            return NS_ERROR_FAILURE;
-        }
-
-        // Prepare for transparancy
-        if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
-            if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) 
-             || ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
-                PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
-                mError = PR_TRUE;
-                return NS_ERROR_FAILURE;
-            }
-            // Clear the image, as the RLE may jump over areas
-            memset(mImageData, 0, imageLength);
-        }
-
-        // Tell the superclass we're starting a frame
-        PostFrameStart();
-    }
-    PRUint8 bpc; // bytes per color
-    bpc = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4; // OS/2 Bitmaps have no padding byte
-    if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
-        // We will receive (mNumColors * bpc) bytes of color data
-        PRUint32 colorBytes = mPos - mLOH; // Number of bytes already received
-        PRUint8 colorNum = colorBytes / bpc; // Color which is currently received
-        PRUint8 at = colorBytes % bpc;
-        while (aCount && (mPos < (mLOH + mNumColors * bpc))) {
-            switch (at) {
-                case 0:
-                    mColors[colorNum].blue = *aBuffer;
-                    break;
-                case 1:
-                    mColors[colorNum].green = *aBuffer;
-                    break;
-                case 2:
-                    mColors[colorNum].red = *aBuffer;
-                    colorNum++;
-                    break;
-                case 3:
-                    // This is a padding byte
-                    break;
-            }
-            mPos++; aBuffer++; aCount--;
-            at = (at + 1) % bpc;
-        }
-    }
-    else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_HEADER_LENGTH + BITFIELD_LENGTH)) {
-        // If compression is used, this is a windows bitmap, hence we can
-        // use WIN_HEADER_LENGTH instead of mLOH
-        PRUint32 toCopy = (WIN_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
-        if (toCopy > aCount)
-            toCopy = aCount;
-        memcpy(mRawBuf + (mPos - WIN_HEADER_LENGTH), aBuffer, toCopy);
-        mPos += toCopy;
-        aBuffer += toCopy;
-        aCount -= toCopy;
-    }
-    if (mBIH.compression == BI_BITFIELDS && mPos == WIN_HEADER_LENGTH + BITFIELD_LENGTH) {
-        mBitFields.red = LITTLE_TO_NATIVE32(*(PRUint32*)mRawBuf);
-        mBitFields.green = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 4));
-        mBitFields.blue = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 8));
-        CalcBitShift();
-    }
-    while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
-        mPos++; aBuffer++; aCount--;
-    }
-    if (aCount && ++mPos >= mBFH.dataoffset) {
-        // Need to increment mPos, else we might get to mPos==mLOH again
-        // From now on, mPos is irrelevant
-        if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
-            PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
-            if (rowSize % 4)
-                rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
-            PRUint32 toCopy;
-            do {
-                toCopy = rowSize - mRowBytes;
-                if (toCopy) {
-                    if (toCopy > aCount)
-                        toCopy = aCount;
-                    memcpy(mRow + mRowBytes, aBuffer, toCopy);
-                    aCount -= toCopy;
-                    aBuffer += toCopy;
-                    mRowBytes += toCopy;
-                }
-                if (rowSize == mRowBytes) {
-                    // Collected a whole row into mRow, process it
-                    PRUint8* p = mRow;
-                    PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, 0);
-                    PRUint32 lpos = mBIH.width;
-                    switch (mBIH.bpp) {
-                      case 1:
-                        while (lpos > 0) {
-                          PRInt8 bit;
-                          PRUint8 idx;
-                          for (bit = 7; bit >= 0 && lpos > 0; bit--) {
-                              idx = (*p >> bit) & 1;
-                              SetPixel(d, idx, mColors);
-                              --lpos;
-                          }
-                          ++p;
-                        }
-                        break;
-                      case 4:
-                        while (lpos > 0) {
-                          Set4BitPixel(d, *p, lpos, mColors);
-                          ++p;
-                        }
-                        break;
-                      case 8:
-                        while (lpos > 0) {
-                          SetPixel(d, *p, mColors);
-                          --lpos;
-                          ++p;
-                        }
-                        break;
-                      case 16:
-                        while (lpos > 0) {
-                          PRUint16 val = LITTLE_TO_NATIVE16(*(PRUint16*)p);
-                          SetPixel(d,
-                                  (val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
-                                  (val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
-                                  (val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
-                          --lpos;
-                          p+=2;
-                        }
-                        break;
-                      case 32:
-                      case 24:
-                        while (lpos > 0) {
-                          SetPixel(d, p[2], p[1], p[0]);
-                          p += 2;
-                          --lpos;
-                          if (mBIH.bpp == 32)
-                            p++; // Padding byte
-                          ++p;
-                        }
-                        break;
-                      default:
-                        NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
-                    }
-                    mCurLine --;
-                    if (mCurLine == 0) { // Finished last line
-                        break;
-                    }
-                    mRowBytes = 0;
-
-                }
-            } while (aCount > 0);
-        } 
-        else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
-            if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) 
-             || ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
-                PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
-                mError = PR_TRUE;
-                return NS_ERROR_FAILURE;
-            }
-
-            while (aCount > 0) {
-                PRUint8 byte;
-
-                switch(mState) {
-                    case eRLEStateInitial:
-                        mStateData = (PRUint8)*aBuffer++;
-                        aCount--;
-
-                        mState = eRLEStateNeedSecondEscapeByte;
-                        continue;
-
-                    case eRLEStateNeedSecondEscapeByte:
-                        byte = *aBuffer++;
-                        aCount--;
-                        if (mStateData != RLE_ESCAPE) { // encoded mode
-                            // Encoded mode consists of two bytes: 
-                            // the first byte (mStateData) specifies the
-                            // number of consecutive pixels to be drawn 
-                            // using the color index contained in
-                            // the second byte
-                            // Work around bitmaps that specify too many pixels
-                            mState = eRLEStateInitial;
-                            PRUint32 pixelsNeeded = PR_MIN((PRUint32)(mBIH.width - mCurPos), mStateData);
-                            if (pixelsNeeded) {
-                                PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
-                                mCurPos += pixelsNeeded;
-                                if (mBIH.compression == BI_RLE8) {
-                                    do {
-                                        SetPixel(d, byte, mColors);
-                                        pixelsNeeded --;
-                                    } while (pixelsNeeded);
-                                } else {
-                                    do {
-                                        Set4BitPixel(d, byte, pixelsNeeded, mColors);
-                                    } while (pixelsNeeded);
-                                }
-                            }
-                            continue;
-                        }
-
-                        switch(byte) {
-                            case RLE_ESCAPE_EOL:
-                                // End of Line: Go to next row
-                                mCurLine --;
-                                mCurPos = 0;
-                                mState = eRLEStateInitial;
-                                break;
-
-                            case RLE_ESCAPE_EOF: // EndOfFile
-                                mCurPos = mCurLine = 0;
-                                break;
-
-                            case RLE_ESCAPE_DELTA:
-                                mState = eRLEStateNeedXDelta;
-                                continue;
-
-                            default : // absolute mode
-                                // Save the number of pixels to read
-                                mStateData = byte;
-                                if (mCurPos + mStateData > (PRUint32)mBIH.width) {
-                                    // We can work around bitmaps that specify one
-                                    // pixel too many, but only if their width is odd.
-                                    mStateData -= mBIH.width & 1;
-                                    if (mCurPos + mStateData > (PRUint32)mBIH.width) {
-                                        mError = PR_TRUE;
-                                        return NS_ERROR_FAILURE;
-                                    }
-                                }
-
-                                // See if we will need to skip a byte
-                                // to word align the pixel data
-                                // mStateData is a number of pixels
-                                // so allow for the RLE compression type
-                                // Pixels RLE8=1 RLE4=2
-                                //    1    Pad    Pad
-                                //    2    No     Pad
-                                //    3    Pad    No
-                                //    4    No     No
-                                if (((mStateData - 1) & mBIH.compression) != 0)
-                                    mState = eRLEStateAbsoluteMode;
-                                else
-                                    mState = eRLEStateAbsoluteModePadded;
-                                continue;
-                        }
-                        break;
-
-                    case eRLEStateNeedXDelta:
-                        // Handle the XDelta and proceed to get Y Delta
-                        byte = *aBuffer++;
-                        aCount--;
-                        mCurPos += byte;
-                        if (mCurPos > mBIH.width)
-                            mCurPos = mBIH.width;
-
-                        mState = eRLEStateNeedYDelta;
-                        continue;
-
-                    case eRLEStateNeedYDelta:
-                        // Get the Y Delta and then "handle" the move
-                        byte = *aBuffer++;
-                        aCount--;
-                        mState = eRLEStateInitial;
-                        mCurLine -= PR_MIN(byte, mCurLine);
-                        break;
-
-                    case eRLEStateAbsoluteMode: // Absolute Mode
-                    case eRLEStateAbsoluteModePadded:
-                        if (mStateData) {
-                            // In absolute mode, the second byte (mStateData)
-                            // represents the number of pixels 
-                            // that follow, each of which contains 
-                            // the color index of a single pixel.
-                            PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
-                            PRUint32* oldPos = d;
-                            if (mBIH.compression == BI_RLE8) {
-                                while (aCount > 0 && mStateData > 0) {
-                                    byte = *aBuffer++;
-                                    aCount--;
-                                    SetPixel(d, byte, mColors);
-                                    mStateData--;
-                                }
-                            } else {
-                                while (aCount > 0 && mStateData > 0) {
-                                    byte = *aBuffer++;
-                                    aCount--;
-                                    Set4BitPixel(d, byte, mStateData, mColors);
-                                }
-                            }
-                            mCurPos += d - oldPos;
-                        }
-
-                        if (mStateData == 0) {
-                            // In absolute mode, each run must 
-                            // be aligned on a word boundary
-
-                            if (mState == eRLEStateAbsoluteMode) { // Word Aligned
-                                mState = eRLEStateInitial;
-                            } else if (aCount > 0) {               // Not word Aligned
-                                // "next" byte is just a padding byte
-                                // so "move" past it and we can continue
-                                aBuffer++;
-                                aCount--;
-                                mState = eRLEStateInitial;
-                            }
-                        }
-                        // else state is still eRLEStateAbsoluteMode
-                        continue;
-
-                    default :
-                        NS_NOTREACHED("BMP RLE decompression: unknown state!");
-                        mError = PR_TRUE;
-                        return NS_ERROR_FAILURE;
-                }
-                // Because of the use of the continue statement
-                // we only get here for eol, eof or y delta
-                if (mCurLine == 0) { // Finished last line
-                    break;
-                }
-            }
-        }
-    }
-    
-    const PRUint32 rows = mOldLine - mCurLine;
-    if (rows) {
-        nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
-                    mBIH.width, rows);
-
-        // Tell the image that its data has been updated
-        rv = mImage->FrameUpdated(0, r); 
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        if (mObserver)
-            mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
-        mOldLine = mCurLine;
-    }
-
-    return NS_OK;
-}
-
-void nsBMPDecoder::ProcessFileHeader()
-{
-    memset(&mBFH, 0, sizeof(mBFH));
-    memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
-    memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
-    memcpy(&mBFH.reserved, mRawBuf + 6, sizeof(mBFH.reserved));
-    memcpy(&mBFH.dataoffset, mRawBuf + 10, sizeof(mBFH.dataoffset));
-    memcpy(&mBFH.bihsize, mRawBuf + 14, sizeof(mBFH.bihsize));
-
-    // Now correct the endianness of the header
-    mBFH.filesize = LITTLE_TO_NATIVE32(mBFH.filesize);
-    mBFH.dataoffset = LITTLE_TO_NATIVE32(mBFH.dataoffset);
-    mBFH.bihsize = LITTLE_TO_NATIVE32(mBFH.bihsize);
-}
-
-void nsBMPDecoder::ProcessInfoHeader()
-{
-    memset(&mBIH, 0, sizeof(mBIH));
-    if (mBFH.bihsize == 12) { // OS/2 Bitmap
-        memcpy(&mBIH.width, mRawBuf, 2);
-        memcpy(&mBIH.height, mRawBuf + 2, 2);
-        memcpy(&mBIH.planes, mRawBuf + 4, sizeof(mBIH.planes));
-        memcpy(&mBIH.bpp, mRawBuf + 6, sizeof(mBIH.bpp));
-    }
-    else {
-        memcpy(&mBIH.width, mRawBuf, sizeof(mBIH.width));
-        memcpy(&mBIH.height, mRawBuf + 4, sizeof(mBIH.height));
-        memcpy(&mBIH.planes, mRawBuf + 8, sizeof(mBIH.planes));
-        memcpy(&mBIH.bpp, mRawBuf + 10, sizeof(mBIH.bpp));
-        memcpy(&mBIH.compression, mRawBuf + 12, sizeof(mBIH.compression));
-        memcpy(&mBIH.image_size, mRawBuf + 16, sizeof(mBIH.image_size));
-        memcpy(&mBIH.xppm, mRawBuf + 20, sizeof(mBIH.xppm));
-        memcpy(&mBIH.yppm, mRawBuf + 24, sizeof(mBIH.yppm));
-        memcpy(&mBIH.colors, mRawBuf + 28, sizeof(mBIH.colors));
-        memcpy(&mBIH.important_colors, mRawBuf + 32, sizeof(mBIH.important_colors));
-    }
-
-    // Convert endianness
-    mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
-    mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
-    mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
-    mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
-
-    mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
-    mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
-    mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
-    mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
-    mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
-    mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
-}
-
-} // namespace imagelib
-} // namespace mozilla
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsBMPDecoder.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla BMP Decoder.
- *
- * The Initial Developer of the Original Code is
- * Christian Biesinger <cbiesinger@web.de>.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#ifndef _nsBMPDecoder_h
-#define _nsBMPDecoder_h
-
-#include "nsAutoPtr.h"
-#include "imgIDecoderObserver.h"
-#include "gfxColor.h"
-#include "Decoder.h"
-
-namespace mozilla {
-namespace imagelib {
-
-struct BMPFILEHEADER {
-    char signature[2]; // String "BM"
-    PRUint32 filesize;
-    PRInt32 reserved; // Zero
-    PRUint32 dataoffset; // Offset to raster data
-
-    PRUint32 bihsize;
-};
-#define BFH_LENGTH 18 // Note: For our purposes, we include bihsize in the BFH
-
-#define OS2_BIH_LENGTH 12 // This is the real BIH size (as contained in the bihsize field of BMPFILEHEADER)
-#define OS2_HEADER_LENGTH (BFH_LENGTH + 8)
-#define WIN_HEADER_LENGTH (BFH_LENGTH + 36)
-
-struct BMPINFOHEADER {
-    PRInt32 width; // Uint16 in OS/2 BMPs
-    PRInt32 height; // Uint16 in OS/2 BMPs
-    PRUint16 planes; // =1
-    PRUint16 bpp; // Bits per pixel.
-    // The rest of the header is not available in OS/2 BMP Files
-    PRUint32 compression; // 0=no compression 1=8bit RLE 2=4bit RLE
-    PRUint32 image_size; // (compressed) image size. Can be 0 if compression==0
-    PRUint32 xppm; // Pixels per meter, horizontal
-    PRUint32 yppm; // Pixels per meter, vertical
-    PRUint32 colors; // Used Colors
-    PRUint32 important_colors; // Number of important colors. 0=all
-};
-
-struct colorTable {
-    PRUint8 red;
-    PRUint8 green;
-    PRUint8 blue;
-};
-
-struct bitFields {
-    PRUint32 red;
-    PRUint32 green;
-    PRUint32 blue;
-    PRUint8 redLeftShift;
-    PRUint8 redRightShift;
-    PRUint8 greenLeftShift;
-    PRUint8 greenRightShift;
-    PRUint8 blueLeftShift;
-    PRUint8 blueRightShift;
-};
-
-#define BITFIELD_LENGTH 12 // Length of the bitfields structure in the bmp file
-
-#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
-// We must ensure that the entity is unsigned
-// otherwise, if it is signed/negative, the MSB will be
-// propagated when we shift
-#define LITTLE_TO_NATIVE16(x) (((((PRUint16) x) & 0xFF) << 8) | \
-                               (((PRUint16) x) >> 8))
-#define LITTLE_TO_NATIVE32(x) (((((PRUint32) x) & 0xFF) << 24) | \
-                               (((((PRUint32) x) >> 8) & 0xFF) << 16) | \
-                               (((((PRUint32) x) >> 16) & 0xFF) << 8) | \
-                               (((PRUint32) x) >> 24))
-#else
-#define LITTLE_TO_NATIVE16(x) x
-#define LITTLE_TO_NATIVE32(x) x
-#endif
-
-#define USE_RGB
-
-// BMPINFOHEADER.compression defines
-#define BI_RLE8 1
-#define BI_RLE4 2
-#define BI_BITFIELDS 3
-
-// RLE Escape codes
-#define RLE_ESCAPE       0
-#define RLE_ESCAPE_EOL   0
-#define RLE_ESCAPE_EOF   1
-#define RLE_ESCAPE_DELTA 2
-
-/// enums for mState
-enum ERLEState {
-    eRLEStateInitial,
-    eRLEStateNeedSecondEscapeByte,
-    eRLEStateNeedXDelta,
-    eRLEStateNeedYDelta,    ///< mStateData will hold x delta
-    eRLEStateAbsoluteMode,  ///< mStateData will hold count of existing data to read
-    eRLEStateAbsoluteModePadded ///< As above, but another byte of data has to be read as padding
-};
-
-class RasterImage;
-
-/**
- * Decoder for BMP-Files, as used by Windows and OS/2
- */
-class nsBMPDecoder : public Decoder
-{
-public:
-
-    nsBMPDecoder();
-    ~nsBMPDecoder();
-
-    virtual nsresult InitInternal();
-    virtual nsresult WriteInternal(const char* aBuffer, PRUint32 aCount);
-    virtual nsresult FinishInternal();
-
-private:
-
-    /** Calculates the red-, green- and blueshift in mBitFields using
-     * the bitmasks from mBitFields */
-    NS_METHOD CalcBitShift();
-
-    PRUint32 mPos;
-
-    BMPFILEHEADER mBFH;
-    BMPINFOHEADER mBIH;
-    char mRawBuf[36];
-
-    PRUint32 mLOH; ///< Length of the header
-
-    PRUint32 mNumColors; ///< The number of used colors, i.e. the number of entries in mColors
-    colorTable *mColors;
-
-    bitFields mBitFields;
-
-    PRUint32 *mImageData; ///< Pointer to the image data for the frame
-    PRUint8 *mRow;      ///< Holds one raw line of the image
-    PRUint32 mRowBytes; ///< How many bytes of the row were already received
-    PRInt32 mCurLine;   ///< Index of the line of the image that's currently being decoded
-    PRInt32 mOldLine;   ///< Previous index of the line 
-    PRInt32 mCurPos;    ///< Index in the current line of the image
-
-    ERLEState mState;   ///< Maintains the current state of the RLE decoding
-    PRUint32 mStateData;///< Decoding information that is needed depending on mState
-    PRBool mError;      ///< Did we hit an error?
-
-    /** Set mBFH from the raw data in mRawBuf, converting from little-endian
-     * data to native data as necessary */
-    void ProcessFileHeader();
-    /** Set mBIH from the raw data in mRawBuf, converting from little-endian
-     * data to native data as necessary */
-    void ProcessInfoHeader();
-};
-
-/** Sets the pixel data in aDecoded to the given values.
- * @param aDecoded pointer to pixel to be set, will be incremented to point to the next pixel.
- */
-static inline void SetPixel(PRUint32*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
-{
-    *aDecoded++ = GFX_PACKED_PIXEL(aAlpha, aRed, aGreen, aBlue);
-}
-
-static inline void SetPixel(PRUint32*& aDecoded, PRUint8 idx, colorTable* aColors)
-{
-    SetPixel(aDecoded, aColors[idx].red, aColors[idx].green, aColors[idx].blue);
-}
-
-/** Sets two (or one if aCount = 1) pixels
- * @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
- * depending on whether one or two pixels are written.
- * @param aData The values for the two pixels
- * @param aCount Current count. Is decremented by one or two.
- */
-inline void Set4BitPixel(PRUint32*& aDecoded, PRUint8 aData,
-                         PRUint32& aCount, colorTable* aColors)
-{
-    PRUint8 idx = aData >> 4;
-    SetPixel(aDecoded, idx, aColors);
-    if (--aCount > 0) {
-        idx = aData & 0xF;
-        SetPixel(aDecoded, idx, aColors);
-        --aCount;
-    }
-}
-
-} // namespace imagelib
-} // namespace mozilla
-
-
-#endif
-
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsGIFDecoder2.cpp
+++ /dev/null
@@ -1,1190 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Chris Saari <saari@netscape.com>
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-/*
-The Graphics Interchange Format(c) is the copyright property of CompuServe
-Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
-enhance, alter, modify or change in any way the definition of the format.
-
-CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
-license for the use of the Graphics Interchange Format(sm) in computer
-software; computer software utilizing GIF(sm) must acknowledge ownership of the
-Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
-User and Technical Documentation. Computer software utilizing GIF, which is
-distributed or may be distributed without User or Technical Documentation must
-display to the screen or printer a message acknowledging ownership of the
-Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
-this case, the acknowledgement may be displayed in an opening screen or leading
-banner, or a closing screen or trailing banner. A message such as the following
-may be used:
-
-    "The Graphics Interchange Format(c) is the Copyright property of
-    CompuServe Incorporated. GIF(sm) is a Service Mark property of
-    CompuServe Incorporated."
-
-For further information, please contact :
-
-    CompuServe Incorporated
-    Graphics Technology Department
-    5000 Arlington Center Boulevard
-    Columbus, Ohio  43220
-    U. S. A.
-
-CompuServe Incorporated maintains a mailing list with all those individuals and
-organizations who wish to receive copies of this document when it is corrected
-or revised. This service is offered free of charge; please provide us with your
-mailing address.
-*/
-
-#include <stddef.h>
-#include "prmem.h"
-
-#include "nsGIFDecoder2.h"
-#include "nsIInputStream.h"
-#include "imgIContainerObserver.h"
-#include "RasterImage.h"
-
-#include "gfxColor.h"
-#include "gfxPlatform.h"
-#include "qcms.h"
-
-namespace mozilla {
-namespace imagelib {
-
-/*
- * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
- *
- * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
- * as each GIF block (except colormaps) can never be bigger than 256 bytes.
- * Colormaps are directly copied in the resp. global_colormap or the local_colormap of the PAL image frame
- * So a fixed buffer in gif_struct is good enough.
- * This buffer is only needed to copy left-over data from one GifWrite call to the next
- */
-#define GETN(n,s)                      \
-  PR_BEGIN_MACRO                       \
-    mGIFStruct.bytes_to_consume = (n); \
-    mGIFStruct.state = (s);            \
-  PR_END_MACRO
-
-/* Get a 16-bit value stored in little-endian format */
-#define GETINT16(p)   ((p)[1]<<8|(p)[0])
-//////////////////////////////////////////////////////////////////////
-// GIF Decoder Implementation
-
-nsGIFDecoder2::nsGIFDecoder2()
-  : mCurrentRow(-1)
-  , mLastFlushedRow(-1)
-  , mImageData(nsnull)
-  , mOldColor(0)
-  , mCurrentFrame(-1)
-  , mCurrentPass(0)
-  , mLastFlushedPass(0)
-  , mGIFOpen(PR_FALSE)
-  , mSawTransparency(PR_FALSE)
-  , mError(PR_FALSE)
-  , mEnded(PR_FALSE)
-{
-  // Clear out the structure, excluding the arrays
-  memset(&mGIFStruct, 0, sizeof(mGIFStruct));
-}
-
-nsGIFDecoder2::~nsGIFDecoder2()
-{
-  PR_FREEIF(mGIFStruct.local_colormap);
-}
-
-nsresult
-nsGIFDecoder2::InitInternal()
-{
-  // Fire OnStartDecode at init time to support bug 512435
-  if (!IsSizeDecode() && mObserver)
-    mObserver->OnStartDecode(nsnull);
-
-  // Start with the version (GIF89a|GIF87a)
-  mGIFStruct.state = gif_type;
-  mGIFStruct.bytes_to_consume = 6;
-
-  return NS_OK;
-}
-
-nsresult
-nsGIFDecoder2::FinishInternal()
-{
-  // Send notifications if appropriate
-  if (!IsSizeDecode() && !mError) {
-    if (mCurrentFrame == mGIFStruct.images_decoded)
-      EndImageFrame();
-    EndGIF(/* aSuccess = */ PR_TRUE);
-  }
-
-  return NS_OK;
-}
-
-// Push any new rows according to mCurrentPass/mLastFlushedPass and
-// mCurrentRow/mLastFlushedRow.  Note: caller is responsible for
-// updating mlastFlushed{Row,Pass}.
-nsresult
-nsGIFDecoder2::FlushImageData(PRUint32 fromRow, PRUint32 rows)
-{
-  nsIntRect r(mGIFStruct.x_offset, mGIFStruct.y_offset + fromRow, mGIFStruct.width, rows);
-
-  // Update image  
-  nsresult rv = mImage->FrameUpdated(mGIFStruct.images_decoded, r);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Offset to the frame position
-  // Only notify observer(s) for first frame
-  if (!mGIFStruct.images_decoded && mObserver) {
-    PRUint32 imgCurFrame = mImage->GetCurrentFrameIndex();
-    mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
-  }
-  return NS_OK;
-}
-
-nsresult
-nsGIFDecoder2::FlushImageData()
-{
-  nsresult rv = NS_OK;
-
-  switch (mCurrentPass - mLastFlushedPass) {
-    case 0:  // same pass
-      if (mCurrentRow - mLastFlushedRow)
-        rv = FlushImageData(mLastFlushedRow + 1, mCurrentRow - mLastFlushedRow);
-      break;
-  
-    case 1:  // one pass on - need to handle bottom & top rects
-      rv = FlushImageData(0, mCurrentRow + 1);
-      rv |= FlushImageData(mLastFlushedRow + 1, mGIFStruct.height - (mLastFlushedRow + 1));
-      break;
-
-    default:   // more than one pass on - push the whole frame
-      rv = FlushImageData(0, mGIFStruct.height);
-  }
-  return rv;
-}
-
-nsresult
-nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount)
-{
-  // Don't forgive previously flagged errors
-  if (mError)
-    return NS_ERROR_FAILURE;
-
-  // Push the data to the GIF decoder
-  nsresult rv = GifWrite((const unsigned char *)aBuffer, aCount);
-
-  // Flushing is only needed for first frame
-  if (NS_SUCCEEDED(rv) && !mGIFStruct.images_decoded) {
-    rv = FlushImageData();
-    NS_ENSURE_SUCCESS(rv, rv);
-    mLastFlushedRow = mCurrentRow;
-    mLastFlushedPass = mCurrentPass;
-  }
-
-  // We do some fine-grained error control here. If we have at least one frame
-  // of an animated gif, we still want to display it (mostly for legacy reasons).
-  // libpr0n code is strict, so we have to lie and tell it we were successful. So
-  // if we have something to salvage, we send off final decode notifications, and
-  // pretend that we're decoded. Otherwise, we set mError.
-  if (NS_FAILED(rv)) {
-
-    // Determine if we want to salvage the situation.
-    // If we're salvaging, send off notifications.
-    // Note that we need to make sure that we have 2 frames, since that tells us
-    // that the first frame is complete (the second could be in any state).
-    if (mImage && mImage->GetNumFrames() > 1) {
-      EndGIF(/* aSuccess = */ PR_TRUE);
-    }
-
-    // Otherwise, set mError
-    else
-      mError = PR_TRUE;
-  }
-
-  return mError ? NS_ERROR_FAILURE : NS_OK;
-}
-
-//******************************************************************************
-// GIF decoder callback methods. Part of public API for GIF2
-//******************************************************************************
-
-//******************************************************************************
-void nsGIFDecoder2::BeginGIF()
-{
-  if (mGIFOpen)
-    return;
-
-  mGIFOpen = PR_TRUE;
-
-  PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
-
-  // If we're doing a size decode, we have what we came for
-  if (IsSizeDecode())
-    return;
-}
-
-//******************************************************************************
-void nsGIFDecoder2::EndGIF(PRBool aSuccess)
-{
-  if (mEnded)
-    return;
-
-  if (aSuccess)
-    mImage->DecodingComplete();
-
-  if (mObserver) {
-    mObserver->OnStopContainer(nsnull, mImage);
-    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
-                            nsnull);
-  }
-
-  mImage->SetLoopCount(mGIFStruct.loop_count);
-
-  mGIFOpen = PR_FALSE;
-  mEnded = PR_TRUE;
-}
-
-//******************************************************************************
-nsresult nsGIFDecoder2::BeginImageFrame(gfx_depth aDepth)
-{
-  if (!mGIFStruct.images_decoded) {
-    // Send a onetime OnDataAvailable (Display Refresh) for the first frame
-    // if it has a y-axis offset.  Otherwise, the area may never be refreshed
-    // and the placeholder will remain on the screen. (Bug 37589)
-    if (mGIFStruct.y_offset > 0) {
-      PRInt32 imgWidth;
-      mImage->GetWidth(&imgWidth);
-      PRUint32 imgCurFrame = mImage->GetCurrentFrameIndex();
-      nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset);
-      if (mObserver)
-        mObserver->OnDataAvailable(nsnull,
-                                   imgCurFrame == PRUint32(mGIFStruct.images_decoded),
-                                   &r);
-    }
-  }
-
-  PRUint32 imageDataLength;
-  nsresult rv;
-  gfxASurface::gfxImageFormat format;
-  if (mGIFStruct.is_transparent)
-    format = gfxASurface::ImageFormatARGB32;
-  else
-    format = gfxASurface::ImageFormatRGB24;
-
-  // Use correct format, RGB for first frame, PAL for following frames
-  // and include transparency to allow for optimization of opaque images
-  if (mGIFStruct.images_decoded) {
-    // Image data is stored with original depth and palette
-    rv = mImage->AppendPalettedFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
-                                     mGIFStruct.width, mGIFStruct.height,
-                                     format, aDepth, &mImageData, &imageDataLength,
-                                     &mColormap, &mColormapSize);
-  } else {
-    // Regardless of depth of input, image is decoded into 24bit RGB
-    rv = mImage->AppendFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
-                             mGIFStruct.width, mGIFStruct.height,
-                             format, &mImageData, &imageDataLength);
-  }
-
-  if (NS_FAILED(rv))
-    return rv;
-
-  mImage->SetFrameDisposalMethod(mGIFStruct.images_decoded,
-                                 mGIFStruct.disposal_method);
-
-  // Tell the superclass we're starting a frame
-  PostFrameStart();
-
-  mCurrentFrame = mGIFStruct.images_decoded;
-  return NS_OK;
-}
-
-
-//******************************************************************************
-void nsGIFDecoder2::EndImageFrame()
-{
-  // First flush all pending image data 
-  if (!mGIFStruct.images_decoded) {
-    // Only need to flush first frame
-    (void) FlushImageData();
-
-    // If the first frame is smaller in height than the entire image, send a
-    // OnDataAvailable (Display Refresh) for the area it does not have data for.
-    // This will clear the remaining bits of the placeholder. (Bug 37589)
-    const PRUint32 realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
-    if (realFrameHeight < mGIFStruct.screen_height) {
-      PRUint32 imgCurFrame = mImage->GetCurrentFrameIndex();
-      nsIntRect r(0, realFrameHeight,
-                  mGIFStruct.screen_width,
-                  mGIFStruct.screen_height - realFrameHeight);
-      if (mObserver)
-        mObserver->OnDataAvailable(nsnull,
-                                  imgCurFrame == PRUint32(mGIFStruct.images_decoded),
-                                  &r);
-    }
-    // This transparency check is only valid for first frame
-    if (mGIFStruct.is_transparent && !mSawTransparency) {
-      mImage->SetFrameHasNoAlpha(mGIFStruct.images_decoded);
-    }
-  }
-  mCurrentRow = mLastFlushedRow = -1;
-  mCurrentPass = mLastFlushedPass = 0;
-
-  // Only add frame if we have any rows at all
-  if (mGIFStruct.rows_remaining != mGIFStruct.height) {
-    if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
-      // Clear the remaining rows (only needed for the animation frames)
-      PRUint8 *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
-      memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
-    }
-
-    // We actually have the timeout information before we get the lzw encoded 
-    // image data, at least according to the spec, but we delay in setting the 
-    // timeout for the image until here to help ensure that we have the whole 
-    // image frame decoded before we go off and try to display another frame.
-    mImage->SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time);
-    mImage->EndFrameDecode(mGIFStruct.images_decoded);
-  }
-
-  // Unconditionally increment images_decoded, because we unconditionally
-  // append frames in BeginImageFrame(). This ensures that images_decoded
-  // always refers to the frame in mImage we're currently decoding,
-  // even if some of them weren't decoded properly and thus are blank.
-  mGIFStruct.images_decoded++;
-
-  // Tell the superclass we finished a frame
-  PostFrameStop();
-
-  // Reset the transparent pixel
-  if (mOldColor) {
-    mColormap[mGIFStruct.tpixel] = mOldColor;
-    mOldColor = 0;
-  }
-
-  mCurrentFrame = -1;
-}
-
-
-//******************************************************************************
-// Send the data to the display front-end.
-PRUint32 nsGIFDecoder2::OutputRow()
-{
-  int drow_start, drow_end;
-  drow_start = drow_end = mGIFStruct.irow;
-
-  /* Protect against too much image data */
-  if ((PRUintn)drow_start >= mGIFStruct.height) {
-    NS_WARNING("GIF2.cpp::OutputRow - too much image data");
-    return 0;
-  }
-
-  if (!mGIFStruct.images_decoded) {
-    /*
-     * Haeberli-inspired hack for interlaced GIFs: Replicate lines while
-     * displaying to diminish the "venetian-blind" effect as the image is
-     * loaded. Adjust pixel vertical positions to avoid the appearance of the
-     * image crawling up the screen as successive passes are drawn.
-     */
-    if (mGIFStruct.progressive_display && mGIFStruct.interlaced && (mGIFStruct.ipass < 4)) {
-      /* ipass = 1,2,3 results in resp. row_dup = 7,3,1 and row_shift = 3,1,0 */
-      const PRUint32 row_dup = 15 >> mGIFStruct.ipass;
-      const PRUint32 row_shift = row_dup >> 1;
-  
-      drow_start -= row_shift;
-      drow_end = drow_start + row_dup;
-  
-      /* Extend if bottom edge isn't covered because of the shift upward. */
-      if (((mGIFStruct.height - 1) - drow_end) <= row_shift)
-        drow_end = mGIFStruct.height - 1;
-  
-      /* Clamp first and last rows to upper and lower edge of image. */
-      if (drow_start < 0)
-        drow_start = 0;
-      if ((PRUintn)drow_end >= mGIFStruct.height)
-        drow_end = mGIFStruct.height - 1;
-    }
-
-    // Row to process
-    const PRUint32 bpr = sizeof(PRUint32) * mGIFStruct.width; 
-    PRUint8 *rowp = mImageData + (mGIFStruct.irow * bpr);
-
-    // Convert color indices to Cairo pixels
-    PRUint8 *from = rowp + mGIFStruct.width;
-    PRUint32 *to = ((PRUint32*)rowp) + mGIFStruct.width;
-    PRUint32 *cmap = mColormap;
-    if (mColorMask == 0xFF) {
-      for (PRUint32 c = mGIFStruct.width; c > 0; c--) {
-        *--to = cmap[*--from];
-      }
-    } else {
-      // Make sure that pixels within range of colormap.
-      PRUint8 mask = mColorMask;
-      for (PRUint32 c = mGIFStruct.width; c > 0; c--) {
-        *--to = cmap[(*--from) & mask];
-      }
-    }
-  
-    // check for alpha (only for first frame)
-    if (mGIFStruct.is_transparent && !mSawTransparency) {
-      const PRUint32 *rgb = (PRUint32*)rowp;
-      for (PRUint32 i = mGIFStruct.width; i > 0; i--) {
-        if (*rgb++ == 0) {
-          mSawTransparency = PR_TRUE;
-          break;
-        }
-      }
-    }
-
-    // Duplicate rows
-    if (drow_end > drow_start) {
-      // irow is the current row filled
-      for (int r = drow_start; r <= drow_end; r++) {
-        if (r != int(mGIFStruct.irow)) {
-          memcpy(mImageData + (r * bpr), rowp, bpr);
-        }
-      }
-    }
-  }
-
-  mCurrentRow = drow_end;
-  mCurrentPass = mGIFStruct.ipass;
-  if (mGIFStruct.ipass == 1)
-    mLastFlushedPass = mGIFStruct.ipass;   // interlaced starts at 1
-
-  if (!mGIFStruct.interlaced) {
-    mGIFStruct.irow++;
-  } else {
-    static const PRUint8 kjump[5] = { 1, 8, 8, 4, 2 };
-    do {
-      // Row increments resp. per 8,8,4,2 rows
-      mGIFStruct.irow += kjump[mGIFStruct.ipass];
-      if (mGIFStruct.irow >= mGIFStruct.height) {
-        // Next pass starts resp. at row 4,2,1,0
-        mGIFStruct.irow = 8 >> mGIFStruct.ipass;
-        mGIFStruct.ipass++;
-      }
-    } while (mGIFStruct.irow >= mGIFStruct.height);
-  }
-
-  return --mGIFStruct.rows_remaining;
-}
-
-//******************************************************************************
-/* Perform Lempel-Ziv-Welch decoding */
-PRBool
-nsGIFDecoder2::DoLzw(const PRUint8 *q)
-{
-  if (!mGIFStruct.rows_remaining)
-    return PR_TRUE;
-
-  /* Copy all the decoder state variables into locals so the compiler
-   * won't worry about them being aliased.  The locals will be homed
-   * back into the GIF decoder structure when we exit.
-   */
-  int avail       = mGIFStruct.avail;
-  int bits        = mGIFStruct.bits;
-  int codesize    = mGIFStruct.codesize;
-  int codemask    = mGIFStruct.codemask;
-  int count       = mGIFStruct.count;
-  int oldcode     = mGIFStruct.oldcode;
-  const int clear_code = ClearCode();
-  PRUint8 firstchar = mGIFStruct.firstchar;
-  PRInt32 datum     = mGIFStruct.datum;
-  PRUint16 *prefix  = mGIFStruct.prefix;
-  PRUint8 *stackp   = mGIFStruct.stackp;
-  PRUint8 *suffix   = mGIFStruct.suffix;
-  PRUint8 *stack    = mGIFStruct.stack;
-  PRUint8 *rowp     = mGIFStruct.rowp;
-
-  PRUint32 bpr = mGIFStruct.width;
-  if (!mGIFStruct.images_decoded) 
-    bpr *= sizeof(PRUint32);
-  PRUint8 *rowend   = mImageData + (bpr * mGIFStruct.irow) + mGIFStruct.width;
-
-#define OUTPUT_ROW()                                        \
-  PR_BEGIN_MACRO                                            \
-    if (!OutputRow())                                       \
-      goto END;                                             \
-    rowp = mImageData + mGIFStruct.irow * bpr;              \
-    rowend = rowp + mGIFStruct.width;                       \
-  PR_END_MACRO
-
-  for (const PRUint8* ch = q; count-- > 0; ch++)
-  {
-    /* Feed the next byte into the decoder's 32-bit input buffer. */
-    datum += ((int32) *ch) << bits;
-    bits += 8;
-
-    /* Check for underflow of decoder's 32-bit input buffer. */
-    while (bits >= codesize)
-    {
-      /* Get the leading variable-length symbol from the data stream */
-      int code = datum & codemask;
-      datum >>= codesize;
-      bits -= codesize;
-
-      /* Reset the dictionary to its original state, if requested */
-      if (code == clear_code) {
-        codesize = mGIFStruct.datasize + 1;
-        codemask = (1 << codesize) - 1;
-        avail = clear_code + 2;
-        oldcode = -1;
-        continue;
-      }
-
-      /* Check for explicit end-of-stream code */
-      if (code == (clear_code + 1)) {
-        /* end-of-stream should only appear after all image data */
-        return (mGIFStruct.rows_remaining == 0);
-      }
-
-      if (oldcode == -1) {
-        if (code >= MAX_BITS)
-          return PR_FALSE;
-        *rowp++ = suffix[code];
-        if (rowp == rowend)
-          OUTPUT_ROW();
-
-        firstchar = oldcode = code;
-        continue;
-      }
-
-      int incode = code;
-      if (code >= avail) {
-        *stackp++ = firstchar;
-        code = oldcode;
-
-        if (stackp >= stack + MAX_BITS)
-          return PR_FALSE;
-      }
-
-      while (code >= clear_code)
-      {
-        if ((code >= MAX_BITS) || (code == prefix[code]))
-          return PR_FALSE;
-
-        *stackp++ = suffix[code];
-        code = prefix[code];
-
-        if (stackp == stack + MAX_BITS)
-          return PR_FALSE;
-      }
-
-      *stackp++ = firstchar = suffix[code];
-
-      /* Define a new codeword in the dictionary. */
-      if (avail < 4096) {
-        prefix[avail] = oldcode;
-        suffix[avail] = firstchar;
-        avail++;
-
-        /* If we've used up all the codewords of a given length
-         * increase the length of codewords by one bit, but don't
-         * exceed the specified maximum codeword size of 12 bits.
-         */
-        if (((avail & codemask) == 0) && (avail < 4096)) {
-          codesize++;
-          codemask += avail;
-        }
-      }
-      oldcode = incode;
-
-      /* Copy the decoded data out to the scanline buffer. */
-      do {
-        *rowp++ = *--stackp;
-        if (rowp == rowend)
-          OUTPUT_ROW();
-      } while (stackp > stack);
-    }
-  }
-
-  END:
-
-  /* Home the local copies of the GIF decoder state variables */
-  mGIFStruct.avail = avail;
-  mGIFStruct.bits = bits;
-  mGIFStruct.codesize = codesize;
-  mGIFStruct.codemask = codemask;
-  mGIFStruct.count = count;
-  mGIFStruct.oldcode = oldcode;
-  mGIFStruct.firstchar = firstchar;
-  mGIFStruct.datum = datum;
-  mGIFStruct.stackp = stackp;
-  mGIFStruct.rowp = rowp;
-
-  return PR_TRUE;
-}
-
-/** 
- * Expand the colormap from RGB to Packed ARGB as needed by Cairo.
- * And apply any LCMS transformation.
- */
-static void ConvertColormap(PRUint32 *aColormap, PRUint32 aColors)
-{
-  // Apply CMS transformation if enabled and available
-  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
-    qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
-    if (transform)
-      qcms_transform_data(transform, aColormap, aColormap, aColors);
-  }
-  // Convert from the GIF's RGB format to the Cairo format.
-  // Work from end to begin, because of the in-place expansion
-  PRUint8 *from = ((PRUint8 *)aColormap) + 3 * aColors;
-  PRUint32 *to = aColormap + aColors;
-
-  // Convert color entries to Cairo format
-
-  // set up for loops below
-  if (!aColors) return;
-  PRUint32 c = aColors;
-
-  // copy as bytes until source pointer is 32-bit-aligned
-  // NB: can't use 32-bit reads, they might read off the end of the buffer
-  for (; (NS_PTR_TO_UINT32(from) & 0x3) && c; --c) {
-    from -= 3;
-    *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
-  }
-
-  // bulk copy of pixels.
-  while (c >= 4) {
-    from -= 12;
-    to   -=  4;
-    c    -=  4;
-    GFX_BLOCK_RGB_TO_FRGB(from,to);
-  }
-
-  // copy remaining pixel(s)
-  // NB: can't use 32-bit reads, they might read off the end of the buffer
-  while (c--) {
-    from -= 3;
-    *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
-  }
-}
-
-/******************************************************************************/
-/*
- * process data arriving from the stream for the gif decoder
- */
-
-nsresult nsGIFDecoder2::GifWrite(const PRUint8 *buf, PRUint32 len)
-{
-  if (!buf || !len)
-    return NS_ERROR_FAILURE;
-
-  const PRUint8 *q = buf;
-
-  // Add what we have sofar to the block
-  // If previous call to me left something in the hold first complete current block
-  // Or if we are filling the colormaps, first complete the colormap
-  PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
-               (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
-               (mGIFStruct.bytes_in_hold) ? mGIFStruct.hold : nsnull;
-  if (p) {
-    // Add what we have sofar to the block
-    PRUint32 l = PR_MIN(len, mGIFStruct.bytes_to_consume);
-    memcpy(p+mGIFStruct.bytes_in_hold, buf, l);
-
-    if (l < mGIFStruct.bytes_to_consume) {
-      // Not enough in 'buf' to complete current block, get more
-      mGIFStruct.bytes_in_hold += l;
-      mGIFStruct.bytes_to_consume -= l;
-      return NS_OK;
-    }
-    // Reset hold buffer count
-    mGIFStruct.bytes_in_hold = 0;
-    // Point 'q' to complete block in hold (or in colormap)
-    q = p;
-  }
-
-  // Invariant:
-  //    'q' is start of current to be processed block (hold, colormap or buf)
-  //    'bytes_to_consume' is number of bytes to consume from 'buf'
-  //    'buf' points to the bytes to be consumed from the input buffer
-  //    'len' is number of bytes left in input buffer from position 'buf'.
-  //    At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
-  //    to point to next buffer, 'len' is adjusted accordingly.
-  //    So that next round in for loop, q gets pointed to the next buffer.
-
-  for (;len >= mGIFStruct.bytes_to_consume; q=buf) {
-    // Eat the current block from the buffer, q keeps pointed at current block
-    buf += mGIFStruct.bytes_to_consume;
-    len -= mGIFStruct.bytes_to_consume;
-
-    switch (mGIFStruct.state)
-    {
-    case gif_lzw:
-      if (!DoLzw(q)) {
-        mGIFStruct.state = gif_error;
-        break;
-      }
-      GETN(1, gif_sub_block);
-      break;
-
-    case gif_lzw_start:
-    {
-      // Make sure the transparent pixel is transparent in the colormap
-      if (mGIFStruct.is_transparent) {
-        // Save old value so we can restore it later
-        if (mColormap == mGIFStruct.global_colormap)
-            mOldColor = mColormap[mGIFStruct.tpixel];
-        mColormap[mGIFStruct.tpixel] = 0;
-      }
-
-      /* Initialize LZW parser/decoder */
-      mGIFStruct.datasize = *q;
-      const int clear_code = ClearCode();
-      if (mGIFStruct.datasize > MAX_LZW_BITS ||
-          clear_code >= MAX_BITS) {
-        mGIFStruct.state = gif_error;
-        break;
-      }
-
-      mGIFStruct.avail = clear_code + 2;
-      mGIFStruct.oldcode = -1;
-      mGIFStruct.codesize = mGIFStruct.datasize + 1;
-      mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
-      mGIFStruct.datum = mGIFStruct.bits = 0;
-
-      /* init the tables */
-      for (int i = 0; i < clear_code; i++)
-        mGIFStruct.suffix[i] = i;
-
-      mGIFStruct.stackp = mGIFStruct.stack;
-
-      GETN(1, gif_sub_block);
-    }
-    break;
-
-    /* All GIF files begin with "GIF87a" or "GIF89a" */
-    case gif_type:
-      if (!strncmp((char*)q, "GIF89a", 6)) {
-        mGIFStruct.version = 89;
-      } else if (!strncmp((char*)q, "GIF87a", 6)) {
-        mGIFStruct.version = 87;
-      } else {
-        mGIFStruct.state = gif_error;
-        break;
-      }
-      GETN(7, gif_global_header);
-      break;
-
-    case gif_global_header:
-      /* This is the height and width of the "screen" or
-       * frame into which images are rendered.  The
-       * individual images can be smaller than the
-       * screen size and located with an origin anywhere
-       * within the screen.
-       */
-
-      mGIFStruct.screen_width = GETINT16(q);
-      mGIFStruct.screen_height = GETINT16(q + 2);
-      mGIFStruct.global_colormap_depth = (q[4]&0x07) + 1;
-
-      // screen_bgcolor is not used
-      //mGIFStruct.screen_bgcolor = q[5];
-      // q[6] = Pixel Aspect Ratio
-      //   Not used
-      //   float aspect = (float)((q[6] + 15) / 64.0);
-
-      if (q[4] & 0x80) { /* global map */
-        // Get the global colormap
-        const PRUint32 size = (3 << mGIFStruct.global_colormap_depth);
-        if (len < size) {
-          // Use 'hold' pattern to get the global colormap
-          GETN(size, gif_global_colormap);
-          break;
-        }
-        // Copy everything, go to colormap state to do CMS correction
-        memcpy(mGIFStruct.global_colormap, buf, size);
-        buf += size;
-        len -= size;
-        GETN(0, gif_global_colormap);
-        break;
-      }
-
-      GETN(1, gif_image_start);
-      break;
-
-    case gif_global_colormap:
-      // Everything is already copied into global_colormap
-      // Convert into Cairo colors including CMS transformation
-      ConvertColormap(mGIFStruct.global_colormap, 1<<mGIFStruct.global_colormap_depth);
-      GETN(1, gif_image_start);
-      break;
-
-    case gif_image_start:
-      switch (*q) {
-        case GIF_TRAILER:
-          mGIFStruct.state = gif_done;
-          break;
-
-        case GIF_EXTENSION_INTRODUCER:
-          GETN(2, gif_extension);
-          break;
-
-        case GIF_IMAGE_SEPARATOR:
-          GETN(9, gif_image_header);
-          break;
-
-        default:
-          /* If we get anything other than GIF_IMAGE_SEPARATOR, 
-           * GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
-           * between blocks. The GIF87a spec tells us to keep reading
-           * until we find an image separator, but GIF89a says such
-           * a file is corrupt. We follow GIF89a and bail out. */
-          if (mGIFStruct.images_decoded > 0) {
-            /* The file is corrupt, but one or more images have
-             * been decoded correctly. In this case, we proceed
-             * as if the file were correctly terminated and set
-             * the state to gif_done, so the GIF will display.
-             */
-            mGIFStruct.state = gif_done;
-          } else {
-            /* No images decoded, there is nothing to display. */
-            mGIFStruct.state = gif_error;
-          }
-      }
-      break;
-
-    case gif_extension:
-      mGIFStruct.bytes_to_consume = q[1];
-      if (mGIFStruct.bytes_to_consume) {
-        switch (*q) {
-        case GIF_GRAPHIC_CONTROL_LABEL:
-          mGIFStruct.state = gif_control_extension;
-          break;
-  
-        case GIF_APPLICATION_EXTENSION_LABEL:
-          mGIFStruct.state = gif_application_extension;
-          break;
-  
-        case GIF_COMMENT_LABEL:
-          mGIFStruct.state = gif_consume_comment;
-          break;
-  
-        default:
-          mGIFStruct.state = gif_skip_block;
-        }
-      } else {
-        GETN(1, gif_image_start);
-      }
-      break;
-
-    case gif_consume_block:
-      if (!*q)
-        GETN(1, gif_image_start);
-      else
-        GETN(*q, gif_skip_block);
-      break;
-
-    case gif_skip_block:
-      GETN(1, gif_consume_block);
-      break;
-
-    case gif_control_extension:
-      mGIFStruct.is_transparent = *q & 0x1;
-      mGIFStruct.tpixel = q[3];
-      mGIFStruct.disposal_method = ((*q) >> 2) & 0x7;
-      // Some specs say 3rd bit (value 4), other specs say value 3
-      // Let's choose 3 (the more popular)
-      if (mGIFStruct.disposal_method == 4)
-        mGIFStruct.disposal_method = 3;
-      mGIFStruct.delay_time = GETINT16(q + 1) * 10;
-      GETN(1, gif_consume_block);
-      break;
-
-    case gif_comment_extension:
-      if (*q)
-        GETN(*q, gif_consume_comment);
-      else
-        GETN(1, gif_image_start);
-      break;
-
-    case gif_consume_comment:
-      GETN(1, gif_comment_extension);
-      break;
-
-    case gif_application_extension:
-      /* Check for netscape application extension */
-      if (!strncmp((char*)q, "NETSCAPE2.0", 11) ||
-        !strncmp((char*)q, "ANIMEXTS1.0", 11))
-        GETN(1, gif_netscape_extension_block);
-      else
-        GETN(1, gif_consume_block);
-      break;
-
-    /* Netscape-specific GIF extension: animation looping */
-    case gif_netscape_extension_block:
-      if (*q)
-        GETN(*q, gif_consume_netscape_extension);
-      else
-        GETN(1, gif_image_start);
-      break;
-
-    /* Parse netscape-specific application extensions */
-    case gif_consume_netscape_extension:
-      switch (q[0] & 7) {
-        case 1:
-          /* Loop entire animation specified # of times.  Only read the
-             loop count during the first iteration. */
-          mGIFStruct.loop_count = GETINT16(q + 1);
-  
-          /* Zero loop count is infinite animation loop request */
-          if (mGIFStruct.loop_count == 0)
-            mGIFStruct.loop_count = -1;
-  
-          GETN(1, gif_netscape_extension_block);
-          break;
-        
-        case 2:
-          /* Wait for specified # of bytes to enter buffer */
-          // Don't do this, this extension doesn't exist (isn't used at all) 
-          // and doesn't do anything, as our streaming/buffering takes care of it all...
-          // See: http://semmix.pl/color/exgraf/eeg24.htm
-          GETN(1, gif_netscape_extension_block);
-          break;
-  
-        default:
-          // 0,3-7 are yet to be defined netscape extension codes
-          mGIFStruct.state = gif_error;
-      }
-      break;
-
-    case gif_image_header:
-    {
-      /* Get image offsets, with respect to the screen origin */
-      mGIFStruct.x_offset = GETINT16(q);
-      mGIFStruct.y_offset = GETINT16(q + 2);
-
-      /* Get image width and height. */
-      mGIFStruct.width  = GETINT16(q + 4);
-      mGIFStruct.height = GETINT16(q + 6);
-
-      if (!mGIFStruct.images_decoded) {
-        /* Work around broken GIF files where the logical screen
-         * size has weird width or height.  We assume that GIF87a
-         * files don't contain animations.
-         */
-        if ((mGIFStruct.screen_height < mGIFStruct.height) ||
-            (mGIFStruct.screen_width < mGIFStruct.width) ||
-            (mGIFStruct.version == 87)) {
-          mGIFStruct.screen_height = mGIFStruct.height;
-          mGIFStruct.screen_width = mGIFStruct.width;
-          mGIFStruct.x_offset = 0;
-          mGIFStruct.y_offset = 0;
-        }    
-        // Create the image container with the right size.
-        BeginGIF();
-
-        // If we were doing a size decode, we're done
-        if (IsSizeDecode())
-          return NS_OK;
-      }
-
-      /* Work around more broken GIF files that have zero image
-         width or height */
-      if (!mGIFStruct.height || !mGIFStruct.width) {
-        mGIFStruct.height = mGIFStruct.screen_height;
-        mGIFStruct.width = mGIFStruct.screen_width;
-        if (!mGIFStruct.height || !mGIFStruct.width) {
-          mGIFStruct.state = gif_error;
-          break;
-        }
-      }
-
-      /* Depth of colors is determined by colormap */
-      /* (q[8] & 0x80) indicates local colormap */
-      /* bits per pixel is (q[8]&0x07 + 1) when local colormap is set */
-      PRUint32 depth = mGIFStruct.global_colormap_depth;
-      if (q[8] & 0x80)
-        depth = (q[8]&0x07) + 1;
-      PRUint32 realDepth = depth;
-      while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
-        realDepth++;
-      } 
-      // Mask to limit the color values within the colormap
-      mColorMask = 0xFF >> (8 - realDepth);
-      nsresult rv = BeginImageFrame(realDepth);
-      if (NS_FAILED(rv) || !mImageData) {
-        mGIFStruct.state = gif_error;
-        break;
-      }
-
-      if (q[8] & 0x40) {
-        mGIFStruct.interlaced = PR_TRUE;
-        mGIFStruct.ipass = 1;
-      } else {
-        mGIFStruct.interlaced = PR_FALSE;
-        mGIFStruct.ipass = 0;
-      }
-
-      /* Only apply the Haeberli display hack on the first frame */
-      mGIFStruct.progressive_display = (mGIFStruct.images_decoded == 0);
-
-      /* Clear state from last image */
-      mGIFStruct.irow = 0;
-      mGIFStruct.rows_remaining = mGIFStruct.height;
-      mGIFStruct.rowp = mImageData;
-
-      /* bits per pixel is q[8]&0x07 */
-
-      if (q[8] & 0x80) /* has a local colormap? */
-      {
-        mGIFStruct.local_colormap_size = 1 << depth;
-        if (!mGIFStruct.images_decoded) {
-          // First frame has local colormap, allocate space for it
-          // as the image frame doesn't have its own palette
-          mColormapSize = sizeof(PRUint32) << realDepth;
-          if (!mGIFStruct.local_colormap) {
-            mGIFStruct.local_colormap = (PRUint32*)PR_MALLOC(mColormapSize);
-            if (!mGIFStruct.local_colormap) {
-              mGIFStruct.state = gif_oom;
-              break;
-            }
-          }
-          mColormap = mGIFStruct.local_colormap;
-        }
-        const PRUint32 size = 3 << depth;
-        if (mColormapSize > size) {
-          // Clear the notfilled part of the colormap
-          memset(((PRUint8*)mColormap) + size, 0, mColormapSize - size);
-        }
-        if (len < size) {
-          // Use 'hold' pattern to get the image colormap
-          GETN(size, gif_image_colormap);
-          break;
-        }
-        // Copy everything, go to colormap state to do CMS correction
-        memcpy(mColormap, buf, size);
-        buf += size;
-        len -= size;
-        GETN(0, gif_image_colormap);
-        break;
-      } else {
-        /* Switch back to the global palette */
-        if (mGIFStruct.images_decoded) {
-          // Copy global colormap into the palette of current frame
-          memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
-        } else {
-          mColormap = mGIFStruct.global_colormap;
-        }
-      }
-      GETN(1, gif_lzw_start);
-    }
-    break;
-
-    case gif_image_colormap:
-      // Everything is already copied into local_colormap
-      // Convert into Cairo colors including CMS transformation
-      ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
-      GETN(1, gif_lzw_start);
-      break;
-
-    case gif_sub_block:
-      mGIFStruct.count = *q;
-      if (mGIFStruct.count) {
-        /* Still working on the same image: Process next LZW data block */
-        /* Make sure there are still rows left. If the GIF data */
-        /* is corrupt, we may not get an explicit terminator.   */
-        if (!mGIFStruct.rows_remaining) {
-#ifdef DONT_TOLERATE_BROKEN_GIFS
-          mGIFStruct.state = gif_error;
-          break;
-#else
-          /* This is an illegal GIF, but we remain tolerant. */
-          GETN(1, gif_sub_block);
-#endif
-          if (mGIFStruct.count == GIF_TRAILER) {
-            /* Found a terminator anyway, so consider the image done */
-            GETN(1, gif_done);
-            break;
-          }
-        }
-        GETN(mGIFStruct.count, gif_lzw);
-      } else {
-        /* See if there are any more images in this sequence. */
-        EndImageFrame();
-        GETN(1, gif_image_start);
-      }
-      break;
-
-    case gif_done:
-      EndGIF(/* aSuccess = */ PR_TRUE);
-      return NS_OK;
-      break;
-
-    case gif_error:
-      EndGIF(/* aSuccess = */ PR_FALSE);
-      return NS_ERROR_FAILURE;
-      break;
-
-    // Handle out of memory errors
-    case gif_oom:
-      return NS_ERROR_OUT_OF_MEMORY;
-
-    // We shouldn't ever get here.
-    default:
-      break;
-    }
-  }
-
-  // if an error state is set but no data remains, code flow reaches here
-  if (mGIFStruct.state == gif_error) {
-      EndGIF(/* aSuccess = */ PR_FALSE);
-      return NS_ERROR_FAILURE;
-  }
-  
-  // Copy the leftover into mGIFStruct.hold
-  mGIFStruct.bytes_in_hold = len;
-  if (len) {
-    // Add what we have sofar to the block
-    PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
-                 (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
-                 mGIFStruct.hold;
-    memcpy(p, buf, len);
-    mGIFStruct.bytes_to_consume -= len;
-  }
-
-  return NS_OK;
-}
-
-} // namespace imagelib
-} // namespace mozilla
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsGIFDecoder2.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Chris Saari <saari@netscape.com>
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _nsGIFDecoder2_h
-#define _nsGIFDecoder2_h
-
-#include "nsCOMPtr.h"
-#include "Decoder.h"
-#include "imgIDecoderObserver.h"
-
-#include "GIF2.h"
-
-namespace mozilla {
-namespace imagelib {
-class RasterImage;
-
-//////////////////////////////////////////////////////////////////////
-// nsGIFDecoder2 Definition
-
-class nsGIFDecoder2 : public Decoder
-{
-public:
-
-  nsGIFDecoder2();
-  ~nsGIFDecoder2();
-
-  virtual nsresult InitInternal();
-  virtual nsresult WriteInternal(const char* aBuffer, PRUint32 aCount);
-  virtual nsresult FinishInternal();
-
-private:
-  /* These functions will be called when the decoder has a decoded row,
-   * frame size information, etc. */
-
-  void      BeginGIF();
-  void      EndGIF(PRBool aSuccess);
-  nsresult  BeginImageFrame(gfx_depth aDepth);
-  void      EndImageFrame();
-  nsresult  FlushImageData();
-  nsresult  FlushImageData(PRUint32 fromRow, PRUint32 rows);
-
-  nsresult  GifWrite(const PRUint8 * buf, PRUint32 numbytes);
-  PRUint32  OutputRow();
-  PRBool    DoLzw(const PRUint8 *q);
-
-  inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
-
-  PRInt32 mCurrentRow;
-  PRInt32 mLastFlushedRow;
-
-  PRUint8 *mImageData;       // Pointer to image data in either Cairo or 8bit format
-  PRUint32 *mColormap;       // Current colormap to be used in Cairo format
-  PRUint32 mColormapSize;
-  PRUint32 mOldColor;        // The old value of the transparent pixel
-
-  // The frame number of the currently-decoding frame when we're in the middle
-  // of decoding it, and -1 otherwise.
-  PRInt32 mCurrentFrame;
-
-  PRUint8 mCurrentPass;
-  PRUint8 mLastFlushedPass;
-  PRUint8 mColorMask;        // Apply this to the pixel to keep within colormap
-  PRPackedBool mGIFOpen;
-  PRPackedBool mSawTransparency;
-  PRPackedBool mError;
-  PRPackedBool mEnded;
-
-  gif_struct mGIFStruct;
-};
-
-} // namespace imagelib
-} // namespace mozilla
-
-#endif
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsICODecoder.cpp
+++ /dev/null
@@ -1,537 +0,0 @@
-/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla ICO Decoder.
- *
- * The Initial Developer of the Original Code is
- * Netscape.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   David Hyatt <hyatt@netscape.com> (Original Author)
- *   Christian Biesinger <cbiesinger@web.de>
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/* This is a Cross-Platform ICO Decoder, which should work everywhere, including
- * Big-Endian machines like the PowerPC. */
-
-#include <stdlib.h>
-
-#include "nsICODecoder.h"
-
-#include "nsIInputStream.h"
-#include "nsIComponentManager.h"
-#include "RasterImage.h"
-#include "imgIContainerObserver.h"
-
-#include "nsIProperties.h"
-#include "nsISupportsPrimitives.h"
-
-namespace mozilla {
-namespace imagelib {
-
-#define ICONCOUNTOFFSET 4
-#define DIRENTRYOFFSET 6
-#define BITMAPINFOSIZE 40
-#define PREFICONSIZE 16
-
-// ----------------------------------------
-// Actual Data Processing
-// ----------------------------------------
-
-PRUint32 nsICODecoder::CalcAlphaRowSize()
-{
-  // Calculate rowsize in DWORD's and then return in # of bytes
-  PRUint32 rowSize = (mDirEntry.mWidth + 31) / 32; // +31 to round up
-  return rowSize * 4;        // Return rowSize in bytes
-}
-
-nsICODecoder::nsICODecoder()
-{
-  mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
-  mCurLine = 1; // Otherwise decoder will never start
-  mColors = nsnull;
-  mRow = nsnull;
-  mHaveAlphaData = mDecodingAndMask = PR_FALSE;
-  mError = PR_FALSE;
-}
-
-nsICODecoder::~nsICODecoder()
-{
-  mPos = 0;
-
-  delete[] mColors;
-
-  mCurLine = 0;
-  mRowBytes = 0;
-  mImageOffset = 0;
-  mCurrIcon = 0;
-  mNumIcons = 0;
-
-  if (mRow) {
-    free(mRow);
-    mRow = nsnull;
-  }
-  mDecodingAndMask = PR_FALSE;
-}
-
-nsresult
-nsICODecoder::InitInternal()
-{
-  // Fire OnStartDecode at init time to support bug 512435
-  if (!IsSizeDecode() && mObserver)
-    mObserver->OnStartDecode(nsnull);
-
-  return NS_OK;
-}
-
-nsresult
-nsICODecoder::FinishInternal()
-{
-  nsresult rv = NS_OK;
-
-  // We should never make multiple frames
-  NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple ICO frames?");
-
-  // Send notifications if appropriate
-  if (!IsSizeDecode() && !mError && (GetFrameCount() == 1)) {
-    // Tell the image that it's data has been updated 
-    nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
-    rv = mImage->FrameUpdated(0, r);
-
-
-    if (mObserver) {
-      mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
-    }
-    PostFrameStop();
-    mImage->DecodingComplete();
-    if (mObserver) {
-      mObserver->OnStopContainer(nsnull, 0);
-      mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
-    }
-  }
-
-  return rv;
-}
-
-nsresult
-nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
-{
-  // No forgiveness
-  if (mError)
-    return NS_ERROR_FAILURE;
-
-  if (!aCount) // aCount=0 means EOF
-    return NS_OK;
-
-  while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
-    if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
-      if ((*aBuffer != 1) && (*aBuffer != 2)) {
-        mError = PR_TRUE;
-        return NS_ERROR_FAILURE;
-      }
-      mIsCursor = (*aBuffer == 2);
-    }
-    mPos++; aBuffer++; aCount--;
-  }
-
-  if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
-    mNumIcons = LITTLE_TO_NATIVE16(((PRUint16*)aBuffer)[0]);
-    aBuffer += 2;
-    mPos += 2;
-    aCount -= 2;
-  }
-
-  if (mNumIcons == 0)
-    return NS_OK; // Nothing to do.
-
-  PRUint16 colorDepth = 0;
-  while (mCurrIcon < mNumIcons) {
-    if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) && 
-        mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
-      PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
-      if (toCopy > aCount)
-        toCopy = aCount;
-      memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
-      mPos += toCopy;
-      aCount -= toCopy;
-      aBuffer += toCopy;
-    }
-    if (aCount == 0)
-      return NS_OK; // Need more data
-
-    IconDirEntry e;
-    if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
-      mCurrIcon++;
-      ProcessDirEntry(e);
-      if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE && e.mBitCount >= colorDepth)
-           || (mCurrIcon == mNumIcons && mImageOffset == 0)) {
-        mImageOffset = e.mImageOffset;
-
-        // ensure mImageOffset is >= the size of the direntry headers (bug #245631)
-        PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
-        if (mImageOffset < minImageOffset) {
-          mError = PR_TRUE;
-          return NS_ERROR_FAILURE;
-        }
-
-        colorDepth = e.mBitCount;
-        memcpy(&mDirEntry, &e, sizeof(IconDirEntry));
-      }
-    }
-  }
-
-  if (mPos < mImageOffset) {
-    // Skip to (or at least towards) the desired image offset
-    PRUint32 toSkip = mImageOffset - mPos;
-    if (toSkip > aCount)
-      toSkip = aCount;
-
-    mPos    += toSkip;
-    aBuffer += toSkip;
-    aCount  -= toSkip;
-  }
-
-  if (mCurrIcon == mNumIcons && mPos >= mImageOffset && mPos < mImageOffset + BITMAPINFOSIZE) {
-    // We've found the icon.
-    PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
-    if (toCopy > aCount)
-      toCopy = aCount;
-
-    memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
-    mPos += toCopy;
-    aCount -= toCopy;
-    aBuffer += toCopy;
-  }
-
-  nsresult rv;
-
-  if (mPos == mImageOffset + BITMAPINFOSIZE) {
-
-    ProcessInfoHeader();
-    PostSize(mDirEntry.mWidth, mDirEntry.mHeight);
-    if (IsSizeDecode())
-      return NS_OK;
-
-    if (mBIH.bpp <= 8) {
-      switch (mBIH.bpp) {
-        case 1:
-          mNumColors = 2;
-          break;
-        case 4:
-          mNumColors = 16;
-          break;
-        case 8:
-          mNumColors = 256;
-          break;
-        default:
-          mError = PR_TRUE;
-          return NS_ERROR_FAILURE;
-      }
-
-      mColors = new colorTable[mNumColors];
-      if (!mColors) {
-        mError = PR_TRUE;
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-    }
-
-    if (mIsCursor) {
-      nsCOMPtr<nsISupportsPRUint32> intwrapx = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
-      nsCOMPtr<nsISupportsPRUint32> intwrapy = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
-
-      if (intwrapx && intwrapy) {
-        intwrapx->SetData(mDirEntry.mXHotspot);
-        intwrapy->SetData(mDirEntry.mYHotspot);
-
-        mImage->Set("hotspotX", intwrapx);
-        mImage->Set("hotspotY", intwrapy);
-      }
-    }
-
-    mCurLine = mDirEntry.mHeight;
-    mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
-    // +4 because the line is padded to a 4 bit boundary, but I don't want
-    // to make exact calculations here, that's unnecessary.
-    // Also, it compensates rounding error.
-    if (!mRow) {
-      mError = PR_TRUE;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    PRUint32 imageLength;
-    rv = mImage->AppendFrame(0, 0, mDirEntry.mWidth, mDirEntry.mHeight,
-                             gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Tell the superclass we're starting a frame
-    PostFrameStart();
-  }
-
-  if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) && 
-                 (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
-    // We will receive (mNumColors * 4) bytes of color data
-    PRUint32 colorBytes = mPos - (mImageOffset + 40); // Number of bytes already received
-    PRUint8 colorNum = colorBytes / 4; // Color which is currently received
-    PRUint8 at = colorBytes % 4;
-    while (aCount && (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
-      switch (at) {
-        case 0:
-          mColors[colorNum].blue = *aBuffer;
-          break;
-        case 1:
-          mColors[colorNum].green = *aBuffer;
-          break;
-        case 2:
-          mColors[colorNum].red = *aBuffer;
-          break;
-        case 3:
-          colorNum++; // This is a padding byte
-          break;
-      }
-      mPos++; aBuffer++; aCount--;
-      at = (at + 1) % 4;
-    }
-  }
-
-  if (!mDecodingAndMask && (mPos >= (mImageOffset + BITMAPINFOSIZE + mNumColors*4))) {
-    if (mPos == (mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
-      // Increment mPos to avoid reprocessing the info header.
-      mPos++;
-    }
-
-    // Ensure memory has been allocated before decoding. If we get this far 
-    // without allocated memory, the file is most likely invalid.
-    NS_ASSERTION(mRow, "mRow is null");
-    NS_ASSERTION(mImageData, "mImageData is null");
-    if (!mRow || !mImageData) {
-      mError = PR_TRUE;
-      return NS_ERROR_FAILURE;
-    }
-
-    PRUint32 rowSize = (mBIH.bpp * mDirEntry.mWidth + 7) / 8; // +7 to round up
-    if (rowSize % 4)
-      rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
-    PRUint32 toCopy;
-    do {
-        toCopy = rowSize - mRowBytes;
-        if (toCopy) {
-            if (toCopy > aCount)
-                toCopy = aCount;
-            memcpy(mRow + mRowBytes, aBuffer, toCopy);
-            aCount -= toCopy;
-            aBuffer += toCopy;
-            mRowBytes += toCopy;
-        }
-        if (rowSize == mRowBytes) {
-            mCurLine--;
-            PRUint32* d = mImageData + (mCurLine * mDirEntry.mWidth);
-            PRUint8* p = mRow;
-            PRUint32 lpos = mDirEntry.mWidth;
-            switch (mBIH.bpp) {
-              case 1:
-                while (lpos > 0) {
-                  PRInt8 bit;
-                  PRUint8 idx;
-                  for (bit = 7; bit >= 0 && lpos > 0; bit--) {
-                      idx = (*p >> bit) & 1;
-                      SetPixel(d, idx, mColors);
-                      --lpos;
-                  }
-                  ++p;
-                }
-                break;
-              case 4:
-                while (lpos > 0) {
-                  Set4BitPixel(d, *p, lpos, mColors);
-                  ++p;
-                }
-                break;
-              case 8:
-                while (lpos > 0) {
-                  SetPixel(d, *p, mColors);
-                  --lpos;
-                  ++p;
-                }
-                break;
-              case 16:
-                while (lpos > 0) {
-                  SetPixel(d,
-                          (p[1] & 124) << 1,
-                          ((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
-                          (p[0] & 31) << 3);
-
-                  --lpos;
-                  p+=2;
-                }
-                break;
-              case 24:
-                while (lpos > 0) {
-                  SetPixel(d, p[2], p[1], p[0]);
-                  p += 3;
-                  --lpos;
-                }
-                break;
-              case 32:
-                // We assume that 32bit doesn't have alpha data until we
-                // find a non-zero alpha byte. If we find such a byte, 
-                // it means that all previous pixels are really clear (alphabyte=0).
-                // This working assumption prevents us having to premultiply afterwards.
-                while (lpos > 0) {
-                  if (!mHaveAlphaData && p[3]) {
-                    // Non-zero alpha byte detected! Clear previous pixels from current row to end
-                    memset(mImageData + mCurLine * mDirEntry.mWidth, 0, 
-                           (mDirEntry.mHeight - mCurLine) * mDirEntry.mWidth * sizeof(PRUint32));
-                    mHaveAlphaData = PR_TRUE;
-                  }                        
-                  SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
-                  p += 4;
-                  --lpos;
-                }
-                break;
-              default:
-                // This is probably the wrong place to check this...
-                mError = PR_TRUE;
-                return NS_ERROR_FAILURE;
-            }
-
-            if (mCurLine == 0)
-              mDecodingAndMask = PR_TRUE;
-              
-            mRowBytes = 0;
-        }
-    } while (!mDecodingAndMask && aCount > 0);
-
-  }
-
-  if (mDecodingAndMask && !mHaveAlphaData) {
-    PRUint32 rowSize = CalcAlphaRowSize();
-
-    if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
-      mPos++;
-      mRowBytes = 0;
-      mCurLine = mDirEntry.mHeight;
-      mRow = (PRUint8*)realloc(mRow, rowSize);
-      if (!mRow) {
-        mError = PR_TRUE;
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-    }
-
-    // Ensure memory has been allocated before decoding.
-    NS_ASSERTION(mRow, "mRow is null");
-    NS_ASSERTION(mImageData, "mImageData is null");
-    if (!mRow || !mImageData) {
-      mError = PR_TRUE;
-      return NS_ERROR_FAILURE;
-    }
-
-    while (mCurLine > 0 && aCount > 0) {
-      PRUint32 toCopy = PR_MIN(rowSize - mRowBytes, aCount);
-      if (toCopy) {
-        memcpy(mRow + mRowBytes, aBuffer, toCopy);
-        aCount -= toCopy;
-        aBuffer += toCopy;
-        mRowBytes += toCopy;
-      }
-      if (rowSize == mRowBytes) {
-        mCurLine--;
-        mRowBytes = 0;
-
-        PRUint32* decoded = mImageData + mCurLine * mDirEntry.mWidth;
-        PRUint32* decoded_end = decoded + mDirEntry.mWidth;
-        PRUint8* p = mRow, *p_end = mRow + rowSize; 
-        while (p < p_end) {
-          PRUint8 idx = *p++;
-          for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
-            // Clear pixel completely for transparency.
-            if (idx & bit) *decoded = 0;
-            decoded ++;
-          }
-        }
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-void
-nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
-{
-  memset(&aTarget, 0, sizeof(aTarget));
-  memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
-  memcpy(&aTarget.mHeight, mDirEntryArray+1, sizeof(aTarget.mHeight));
-  memcpy(&aTarget.mColorCount, mDirEntryArray+2, sizeof(aTarget.mColorCount));
-  memcpy(&aTarget.mReserved, mDirEntryArray+3, sizeof(aTarget.mReserved));
-  
-  memcpy(&aTarget.mPlanes, mDirEntryArray+4, sizeof(aTarget.mPlanes));
-  aTarget.mPlanes = LITTLE_TO_NATIVE16(aTarget.mPlanes);
-
-  memcpy(&aTarget.mBitCount, mDirEntryArray+6, sizeof(aTarget.mBitCount));
-  aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);
-
-  memcpy(&aTarget.mBytesInRes, mDirEntryArray+8, sizeof(aTarget.mBytesInRes));
-  aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
-
-  memcpy(&aTarget.mImageOffset, mDirEntryArray+12, sizeof(aTarget.mImageOffset));
-  aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
-}
-
-void nsICODecoder::ProcessInfoHeader() {
-  memset(&mBIH, 0, sizeof(mBIH));
-  // Ignoring the size; it should always be 40 for icons, anyway
-
-  memcpy(&mBIH.width, mBIHraw + 4, sizeof(mBIH.width));
-  memcpy(&mBIH.height, mBIHraw + 8, sizeof(mBIH.height));
-  memcpy(&mBIH.planes, mBIHraw + 12, sizeof(mBIH.planes));
-  memcpy(&mBIH.bpp, mBIHraw + 14, sizeof(mBIH.bpp));
-  memcpy(&mBIH.compression, mBIHraw + 16, sizeof(mBIH.compression));
-  memcpy(&mBIH.image_size, mBIHraw + 20, sizeof(mBIH.image_size));
-  memcpy(&mBIH.xppm, mBIHraw + 24, sizeof(mBIH.xppm));
-  memcpy(&mBIH.yppm, mBIHraw + 28, sizeof(mBIH.yppm));
-  memcpy(&mBIH.colors, mBIHraw + 32, sizeof(mBIH.colors));
-  memcpy(&mBIH.important_colors, mBIHraw + 36, sizeof(mBIH.important_colors));
-
-  // Convert endianness
-  mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
-  mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
-  mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
-  mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
-
-  mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
-  mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
-  mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
-  mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
-  mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
-  mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
-}
-
-} // namespace imagelib
-} // namespace mozilla
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsICODecoder.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla ICO Decoder.
- *
- * The Initial Developer of the Original Code is
- * Netscape.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   David Hyatt <hyatt@netscape.com> (Original Author)
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#ifndef _nsICODecoder_h
-#define _nsICODecoder_h
-
-#include "nsAutoPtr.h"
-#include "Decoder.h"
-#include "imgIDecoderObserver.h"
-#include "nsBMPDecoder.h"
-
-namespace mozilla {
-namespace imagelib {
-
-class RasterImage;
-
-struct IconDirEntry
-{
-  PRUint8   mWidth;
-  PRUint8   mHeight;
-  PRUint8   mColorCount;
-  PRUint8   mReserved;
-  union {
-    PRUint16 mPlanes;   // ICO
-    PRUint16 mXHotspot; // CUR
-  };
-  union {
-    PRUint16 mBitCount; // ICO
-    PRUint16 mYHotspot; // CUR
-  };
-  PRUint32  mBytesInRes;
-  PRUint32  mImageOffset;
-};
-
-class nsICODecoder : public Decoder
-{
-public:
-
-  nsICODecoder();
-  virtual ~nsICODecoder();
-
-  virtual nsresult InitInternal();
-  virtual nsresult WriteInternal(const char* aBuffer, PRUint32 aCount);
-  virtual nsresult FinishInternal();
-
-private:
-  // Private helper methods
-  void ProcessDirEntry(IconDirEntry& aTarget);
-  void ProcessInfoHeader();
-
-  nsresult SetImageData();
-
-  PRUint32 CalcAlphaRowSize();
-
-  PRUint32 mPos;
-  PRUint16 mNumIcons;
-  PRUint16 mCurrIcon;
-  PRUint32 mImageOffset;
-
-  char mDirEntryArray[16];
-  IconDirEntry mDirEntry;
-
-  char mBIHraw[40];
-  BMPINFOHEADER mBIH;
-
-  PRUint32 mNumColors;
-  colorTable* mColors;
-
-  PRUint8* mRow; // Holds one raw line of the image
-  PRUint32 mRowBytes; // How many bytes of the row were already received
-  PRInt32 mCurLine;
-
-  PRUint32* mImageData;
-
-  PRPackedBool mHaveAlphaData;
-  PRPackedBool mIsCursor;
-  PRPackedBool mDecodingAndMask;
-  PRPackedBool mError;
-};
-
-} // namespace imagelib
-} // namespace mozilla
-
-#endif
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsIconDecoder.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Scott MacGregor <mscott@netscape.com>
- *   Bobby Holley <bobbyholley@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsIconDecoder.h"
-#include "nsIInputStream.h"
-#include "RasterImage.h"
-#include "imgIContainerObserver.h"
-#include "nspr.h"
-#include "nsRect.h"
-
-#include "ImageErrors.h"
-
-namespace mozilla {
-namespace imagelib {
-
-nsIconDecoder::nsIconDecoder() :
-  mWidth(-1),
-  mHeight(-1),
-  mPixBytesRead(0),
-  mPixBytesTotal(0),
-  mImageData(nsnull),
-  mState(iconStateStart),
-  mNotifiedDone(PR_FALSE)
-{
-  // Nothing to do
-}
-
-nsIconDecoder::~nsIconDecoder()
-{ }
-
-
-nsresult
-nsIconDecoder::InitInternal()
-{
-  // Fire OnStartDecode at init time to support bug 512435
-  if (!IsSizeDecode() && mObserver)
-    mObserver->OnStartDecode(nsnull);
-
-  return NS_OK;
-}
-
-nsresult
-nsIconDecoder::FinishInternal()
-{
-  // If we haven't notified of completion yet for a full/success decode, we
-  // didn't finish. Notify in error mode
-  if (!IsSizeDecode() && !mNotifiedDone)
-    NotifyDone(/* aSuccess = */ PR_FALSE);
-
-  return NS_OK;
-}
-
-nsresult
-nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
-{
-  nsresult rv;
-
-  // We put this here to avoid errors about crossing initialization with case
-  // jumps on linux.
-  PRUint32 bytesToRead = 0;
-
-  // Performance isn't critical here, so our update rectangle is 
-  // always the full icon
-  nsIntRect r(0, 0, mWidth, mHeight);
-
-  // Loop until the input data is gone
-  while (aCount > 0) {
-    switch (mState) {
-      case iconStateStart:
-
-        // Grab the width
-        mWidth = (PRUint8)*aBuffer;
-
-        // Book Keeping
-        aBuffer++;
-        aCount--;
-        mState = iconStateHaveHeight;
-        break;
-
-      case iconStateHaveHeight:
-
-        // Grab the Height
-        mHeight = (PRUint8)*aBuffer;
-
-        // Post our size to the superclass
-        PostSize(mWidth, mHeight);
-
-        // If We're doing a size decode, we're done
-        if (IsSizeDecode()) {
-          mState = iconStateFinished;
-          break;
-        }
-
-        // Add the frame and signal
-        rv = mImage->AppendFrame(0, 0, mWidth, mHeight,
-                                 gfxASurface::ImageFormatARGB32,
-                                 &mImageData, &mPixBytesTotal);
-        if (NS_FAILED(rv)) {
-          mState = iconStateError;
-          return rv;
-        }
-
-        // Tell the superclass we're starting a frame
-        PostFrameStart();
-
-        // Book Keeping
-        aBuffer++;
-        aCount--;
-        mState = iconStateReadPixels;
-        break;
-
-      case iconStateReadPixels:
-
-        // How many bytes are we reading?
-        bytesToRead = PR_MIN(aCount, mPixBytesTotal - mPixBytesRead);
-
-        // Copy the bytes
-        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);
-
-        // Notify
-        rv = mImage->FrameUpdated(0, r);
-        if (NS_FAILED(rv)) {
-          mState = iconStateError;
-          return rv;
-        }
-        if (mObserver)
-          mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
-
-        // Book Keeping
-        aBuffer += bytesToRead;
-        aCount -= bytesToRead;
-        mPixBytesRead += bytesToRead;
-
-        // If we've got all the pixel bytes, we're finished
-        if (mPixBytesRead == mPixBytesTotal) {
-          NotifyDone(/* aSuccess = */ PR_TRUE);
-          mState = iconStateFinished;
-        }
-        break;
-
-      case iconStateFinished:
-
-        // Consume all excess data silently
-        aCount = 0;
-
-        break;
-
-      case iconStateError:
-        return NS_IMAGELIB_ERROR_FAILURE;
-        break;
-    }
-  }
-
-  return NS_OK;
-}
-
-void
-nsIconDecoder::NotifyDone(PRBool aSuccess)
-{
-  // We should only call this once
-  NS_ABORT_IF_FALSE(!mNotifiedDone, "Calling NotifyDone twice");
-
-  // Notify
-  PostFrameStop();
-  if (aSuccess)
-    mImage->DecodingComplete();
-  if (mObserver) {
-    mObserver->OnStopContainer(nsnull, mImage);
-    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
-                            nsnull);
-  }
-
-  // Flag that we've notified
-  mNotifiedDone = PR_TRUE;
-}
-
-} // namespace imagelib
-} // namespace mozilla
deleted file mode 100644
--- a/modules/libpr0n/decoders/nsIconDecoder.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Scott MacGregor <mscott@netscape.com>
- *   Bobby Holley <bobbyholley@gmail.com>
- *