From: Mike Hommey <glandium@debian.org>
Date: Fri, 14 Mar 2008 08:29:51 +0100
Subject: Disable APNG support when system libpng doesn't support it

---
 config/autoconf.mk.in                         |    1 +
 configure.in                                  |    5 ++-
 modules/libpr0n/decoders/png/nsPNGDecoder.cpp |   30 +++++++++++++++++--
 modules/libpr0n/decoders/png/nsPNGDecoder.h   |    4 ++
 modules/libpr0n/encoders/png/nsPNGEncoder.cpp |   39 ++++++++++++++++++++----
 modules/libpr0n/encoders/png/nsPNGEncoder.h   |    4 ++
 6 files changed, 72 insertions(+), 11 deletions(-)

diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in
index d1a7d98..2c9c204 100644
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -225,6 +225,7 @@ MOZ_NATIVE_ZLIB	= @SYSTEM_ZLIB@
 MOZ_NATIVE_BZ2	= @SYSTEM_BZ2@
 MOZ_NATIVE_JPEG	= @SYSTEM_JPEG@
 MOZ_NATIVE_PNG	= @SYSTEM_PNG@
+APNG		= @APNG@
 MOZ_TREE_CAIRO = @MOZ_TREE_CAIRO@
 
 MOZ_UPDATE_XTERM = @MOZ_UPDATE_XTERM@
diff --git a/configure.in b/configure.in
index ff7872a..9361511 100644
--- a/configure.in
+++ b/configure.in
@@ -4322,6 +4322,7 @@ if test -n "${PNG_DIR}" -a "${PNG_DIR}" != "yes"; then
     CFLAGS="-I${PNG_DIR}/include $CFLAGS"
     LDFLAGS="-L${PNG_DIR}/lib $LDFLAGS"
 fi
+APNG=1
 if test -z "$PNG_DIR" -o "$PNG_DIR" = no; then
     SYSTEM_PNG=
 else
@@ -4330,7 +4331,8 @@ else
                  AC_MSG_ERROR([--with-system-png requested but no working libpng found]), 
                  $PNG_LIBS)
     AC_CHECK_LIB(png, png_get_acTL, ,
-                 AC_MSG_ERROR([--with-system-png won't work because the system's libpng doesn't have APNG support]),
+                 AC_MSG_WARN([system's libpng doesn't have APNG support])
+		 APNG=,
                  $_SAVE_PNG_LIBS)
 fi
 if test "$SYSTEM_PNG" = 0; then
@@ -8170,6 +8172,7 @@ AC_SUBST(SYSTEM_MAKEDEPEND)
 AC_SUBST(SYSTEM_LIBXUL)
 AC_SUBST(SYSTEM_JPEG)
 AC_SUBST(SYSTEM_PNG)
+AC_SUBST(APNG)
 AC_SUBST(SYSTEM_ZLIB)
 AC_SUBST(SYSTEM_BZ2)
 
diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
index 898c237..7d98859 100644
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
@@ -62,8 +62,10 @@
 static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr);
 static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
                                 png_uint_32 row_num, int pass);
+#ifdef APNG
 static void PNGAPI frame_info_callback(png_structp png_ptr,
                                          png_uint_32 frame_num);
+#endif
 static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
 static void PNGAPI error_callback(png_structp png_ptr,
                                   png_const_charp error_msg);
@@ -89,7 +91,10 @@ nsPNGDecoder::nsPNGDecoder() :
   mPNG(nsnull), mInfo(nsnull),
   mCMSLine(nsnull), interlacebuf(nsnull),
   mInProfile(nsnull), mTransform(nsnull),
-  mChannels(0), mError(PR_FALSE), mFrameIsHidden(PR_FALSE)
+  mChannels(0), mError(PR_FALSE)
+#ifdef APNG
+  , mFrameIsHidden(PR_FALSE)
+#endif
 {
 }
 
@@ -120,8 +125,10 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
   if (NS_FAILED(rv))
     longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
 
+#ifdef APNG
   if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL))
     SetAnimFrameInfo();
+#endif
   
   mImage->AppendFrame(mFrame);
   
@@ -137,6 +144,7 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
   mFrameHasNoAlpha = PR_TRUE;
 }
 
+#ifdef APNG
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::SetAnimFrameInfo()
 {
@@ -176,6 +184,7 @@ void nsPNGDecoder::SetAnimFrameInfo()
   /*else // 'over' is the default for a gfxImageFrame
       mFrame->SetBlendMethod(imgIContainer::kBlendOver); */
 }
+#endif
 
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::EndImageFrame()
@@ -689,12 +698,15 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
     }
   }
 
+#ifdef APNG
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL))
     png_set_progressive_frame_fn(png_ptr, frame_info_callback, NULL);
   
   if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) {
     decoder->mFrameIsHidden = PR_TRUE;
-  } else {
+  } else
+#endif
+  {
     decoder->CreateFrame(0, 0, width, height, decoder->format);
   }
   
@@ -714,7 +726,7 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
       longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
     }
   }
-
+  
 #ifdef PNG_USER_MEM_SUPPORTED
   /* Revert to the default memory allocator */
   if (gfxPlatform::GetCMSMode() != eCMSMode_Off)
@@ -739,8 +751,10 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
    */
   png_set_crc_action(png_ptr, NULL, PNG_CRC_ERROR_QUIT);
     
+#ifdef APNG
   if (png_get_first_frame_is_hidden(png_ptr, info_ptr))
     decoder->mFrame = nsnull;
+#endif
   
   return;
 }
@@ -778,9 +792,11 @@ row_callback(png_structp png_ptr, png_bytep new_row,
    */
   nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
   
+#ifdef APNG
   // skip this frame
   if (decoder->mFrameIsHidden)
     return;
+#endif
 
   PRInt32 height;
   decoder->mFrame->GetHeight(&height);
@@ -888,6 +904,7 @@ row_callback(png_structp png_ptr, png_bytep new_row,
   }
 }
 
+#ifdef APNG
 // got the header of a new frame that's coming
 void
 frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
@@ -897,11 +914,15 @@ frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
   
   nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
   
+#ifdef APNG
   // old frame is done
   if (!decoder->mFrameIsHidden)
+#endif
     decoder->EndImageFrame();
   
+#ifdef APNG
   decoder->mFrameIsHidden = PR_FALSE;
+#endif
   
   x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
   y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
@@ -910,6 +931,7 @@ frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
   
   decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
 }
+#endif
 
 void
 end_callback(png_structp png_ptr, png_infop info_ptr)
@@ -928,12 +950,14 @@ end_callback(png_structp png_ptr, png_infop info_ptr)
 
   nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
   
+#ifdef APNG
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
     PRInt32 num_plays = png_get_num_plays(png_ptr, info_ptr);
     decoder->mImage->SetLoopCount(num_plays - 1);
   }
   
   if (!decoder->mFrameIsHidden)
+#endif
     decoder->EndImageFrame();
   
   decoder->mImage->DecodingComplete();
diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.h b/modules/libpr0n/decoders/png/nsPNGDecoder.h
index e5b2743..f076d70 100644
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.h
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.h
@@ -73,7 +73,9 @@ public:
 
   void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, 
                    PRInt32 width, PRInt32 height, gfx_format format);
+#ifdef APNG
   void SetAnimFrameInfo();
+#endif
   
   void EndImageFrame();
 
@@ -94,7 +96,9 @@ public:
   PRUint8 mChannels;
   PRPackedBool mError;
   PRPackedBool mFrameHasNoAlpha;
+#ifdef APNG
   PRPackedBool mFrameIsHidden;
+#endif
 };
 
 #endif // nsPNGDecoder_h__
diff --git a/modules/libpr0n/encoders/png/nsPNGEncoder.cpp b/modules/libpr0n/encoders/png/nsPNGEncoder.cpp
index 26d1f70..6a5e083 100644
--- a/modules/libpr0n/encoders/png/nsPNGEncoder.cpp
+++ b/modules/libpr0n/encoders/png/nsPNGEncoder.cpp
@@ -51,7 +51,9 @@
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsPNGEncoder, imgIEncoder, nsIInputStream)
 
 nsPNGEncoder::nsPNGEncoder() : mPNG(nsnull), mPNGinfo(nsnull),
+#ifdef APNG
                                mIsAnimation(PR_FALSE),
+#endif
                                mImageBuffer(nsnull), mImageBufferSize(0),
                                mImageBufferUsed(0), mImageBufferReadPoint(0)
 {
@@ -109,9 +111,12 @@ NS_IMETHODIMP nsPNGEncoder::StartImageEncode(PRUint32 aWidth,
                                              PRUint32 aInputFormat,
                                              const nsAString& aOutputOptions)
 {
-  PRBool useTransparency = PR_TRUE, skipFirstFrame = PR_FALSE;
+  PRBool useTransparency = PR_TRUE;
+#ifdef APNG
+  PRBool skipFirstFrame = PR_FALSE;
   PRUint32 numFrames = 1;
   PRUint32 numPlays = 0; // For animations, 0 == forever
+#endif
 
   // can't initialize more than once
   if (mImageBuffer != nsnull)
@@ -124,14 +129,19 @@ NS_IMETHODIMP nsPNGEncoder::StartImageEncode(PRUint32 aWidth,
     return NS_ERROR_INVALID_ARG;
 
   // parse and check any provided output options
-  nsresult rv = ParseOptions(aOutputOptions, &useTransparency, &skipFirstFrame,
-                             &numFrames, &numPlays, nsnull, nsnull,
-                             nsnull, nsnull, nsnull);
+  nsresult rv = ParseOptions(aOutputOptions, &useTransparency,
+#ifdef APNG
+                             &skipFirstFrame, &numFrames, &numPlays,
+			     nsnull, nsnull, nsnull,
+#endif
+			     nsnull, nsnull);
   if (rv != NS_OK) { return rv; }
 
+#ifdef APNG
   if (numFrames > 1) {
     mIsAnimation = PR_TRUE;
   }
+#endif
 
   // initialize
   mPNG = png_create_write_struct(PNG_LIBPNG_VER_STRING,
@@ -181,10 +191,12 @@ NS_IMETHODIMP nsPNGEncoder::StartImageEncode(PRUint32 aWidth,
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                PNG_FILTER_TYPE_DEFAULT);
 
+#ifdef APNG
   if (mIsAnimation) {
     png_set_first_frame_is_hidden(mPNG, mPNGinfo, skipFirstFrame);
     png_set_acTL(mPNG, mPNGinfo, numFrames, numPlays);
   }
+#endif
 
   // XXX: support PLTE, gAMA, tRNS, bKGD?
 
@@ -203,9 +215,11 @@ NS_IMETHODIMP nsPNGEncoder::AddImageFrame(const PRUint8* aData,
                                           const nsAString& aFrameOptions)
 {
   PRBool useTransparency= PR_TRUE;
+#ifdef APNG
   PRUint32 delay_ms = 500;
   PRUint32 dispose_op = PNG_DISPOSE_OP_NONE;
   PRUint32 blend_op = PNG_BLEND_OP_SOURCE;
+#endif
   PRUint32 x_offset = 0, y_offset = 0;
 
   // must be initialized
@@ -229,17 +243,22 @@ NS_IMETHODIMP nsPNGEncoder::AddImageFrame(const PRUint8* aData,
   }
 
   // parse and check any provided output options
-  nsresult rv = ParseOptions(aFrameOptions, &useTransparency, nsnull,
-                             nsnull, nsnull, &dispose_op, &blend_op,
-                             &delay_ms, &x_offset, &y_offset);
+  nsresult rv = ParseOptions(aFrameOptions, &useTransparency,
+#ifdef APNG
+                             nsnull, nsnull, nsnull, &dispose_op,
+			     &blend_op, &delay_ms,
+#endif
+                             &x_offset, &y_offset);
   if (rv != NS_OK) { return rv; }
 
+#ifdef APNG
   if (mIsAnimation) {
     // XXX the row pointers arg (#3) is unused, can it be removed?
     png_write_frame_head(mPNG, mPNGinfo, nsnull,
                          aWidth, aHeight, x_offset, y_offset,
                          delay_ms, 1000, dispose_op, blend_op);
   }
+#endif
 
   // Stride is the padded width of each row, so it better be longer (I'm afraid
   // people will not understand what stride means, so check it well)
@@ -287,9 +306,11 @@ NS_IMETHODIMP nsPNGEncoder::AddImageFrame(const PRUint8* aData,
     return NS_ERROR_INVALID_ARG;
   }
 
+#ifdef APNG
   if (mIsAnimation) {
     png_write_frame_tail(mPNG, mPNGinfo);
   }
+#endif
 
   return NS_OK;
 }
@@ -325,12 +346,14 @@ NS_IMETHODIMP nsPNGEncoder::EndImageEncode()
 nsresult
 nsPNGEncoder::ParseOptions(const nsAString& aOptions,
                            PRBool* useTransparency,
+#ifdef APNG
                            PRBool* skipFirstFrame,
                            PRUint32* numFrames,
                            PRUint32* numPlays,
                            PRUint32* frameDispose,
                            PRUint32* frameBlend,
                            PRUint32* frameDelay,
+#endif
                            PRUint32* offsetX,
                            PRUint32* offsetY)
 {
@@ -359,6 +382,7 @@ nsPNGEncoder::ParseOptions(const nsAString& aOptions,
         return NS_ERROR_INVALID_ARG;
       }
 
+#ifdef APNG
     // skipfirstframe=[yes|no]
     } else if (nsCRT::strcmp(token, "skipfirstframe") == 0 && skipFirstFrame) {
       if (!value) { return NS_ERROR_INVALID_ARG; }
@@ -418,6 +442,7 @@ nsPNGEncoder::ParseOptions(const nsAString& aOptions,
       if (!value) { return NS_ERROR_INVALID_ARG; }
 
       if (PR_sscanf(value, "%u", frameDelay) != 1) { return NS_ERROR_INVALID_ARG; }
+#endif
 
     // xoffset=#
     } else if (nsCRT::strcmp(token, "xoffset") == 0 && offsetX) {
diff --git a/modules/libpr0n/encoders/png/nsPNGEncoder.h b/modules/libpr0n/encoders/png/nsPNGEncoder.h
index cc121d0..b6d8754 100644
--- a/modules/libpr0n/encoders/png/nsPNGEncoder.h
+++ b/modules/libpr0n/encoders/png/nsPNGEncoder.h
@@ -65,12 +65,14 @@ private:
 protected:
   nsresult ParseOptions(const nsAString& aOptions,
                            PRBool* useTransparency,
+#ifdef APNG
                            PRBool* skipFirstFrame,
                            PRUint32* numAnimatedFrames,
                            PRUint32* numIterations,
                            PRUint32* frameDispose,
                            PRUint32* frameBlend,
                            PRUint32* frameDelay,
+#endif
                            PRUint32* offsetX,
                            PRUint32* offsetY);
   void ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest,
@@ -83,7 +85,9 @@ protected:
   png_struct* mPNG;
   png_info* mPNGinfo;
 
+#ifdef APNG
   PRBool mIsAnimation;
+#endif
 
   // image buffer
   PRUint8* mImageBuffer;
