From ad3f3760580e3647dc87891553be59e756e1a5f1 Mon Sep 17 00:00:00 2001 From: "dbaron%dbaron.org" Date: Mon, 13 Feb 2006 00:25:59 +0000 Subject: [PATCH] Make the icon decoder allow 8-bit alpha in addition to 1-bit alpha (and a little further cleanup), and make the GTK icon code go through the icon decoder instead of PNG. b=326714 r=biesi sr=roc --- modules/libpr0n/decoders/icon/Makefile.in | 10 +- .../decoders/icon/beos/nsIconChannel.cpp | 9 +- .../decoders/icon/gtk/nsIconChannel.cpp | 101 +++++++++--------- .../decoders/icon/mac/nsIconChannel.cpp | 1 + .../libpr0n/decoders/icon/nsIconDecoder.cpp | 62 +++++------ modules/libpr0n/decoders/icon/nsIconDecoder.h | 9 +- .../libpr0n/decoders/icon/nsIconModule.cpp | 6 +- .../decoders/icon/os2/nsIconChannel.cpp | 4 +- 8 files changed, 103 insertions(+), 99 deletions(-) diff --git a/modules/libpr0n/decoders/icon/Makefile.in b/modules/libpr0n/decoders/icon/Makefile.in index 1dac37e5e36e..4548f316d72d 100644 --- a/modules/libpr0n/decoders/icon/Makefile.in +++ b/modules/libpr0n/decoders/icon/Makefile.in @@ -91,8 +91,16 @@ CPPSRCS = \ nsIconProtocolHandler.cpp \ $(NULL) +ifdef MOZ_ENABLE_GNOMEUI +USE_ICON_DECODER = 1 +endif ifeq (,$(filter-out Darwin OS2 BeOS,$(OS_ARCH))) -CPPSRCS += nsIconDecoder.cpp +USE_ICON_DECODER = 1 +endif + +ifdef USE_ICON_DECODER +CPPSRCS += nsIconDecoder.cpp +DEFINES += -DUSE_ICON_DECODER endif XPIDLSRCS = nsIIconURI.idl diff --git a/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp b/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp index c4b7d92f4499..c7d182a0d2bc 100644 --- a/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp +++ b/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp @@ -314,16 +314,17 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc return NS_ERROR_NOT_AVAILABLE; // Got a bitmap and color space info - convert data to mozilla's icon format - PRUint32 iconLength = 2 + iconSize * (iconSize * 3 + alphaBytesPerRow); + PRUint32 iconLength = 3 + iconSize * (iconSize * 3 + alphaBytesPerRow); uint8 *buffer = new uint8[iconLength]; if (!buffer) return NS_ERROR_OUT_OF_MEMORY; - buffer[0] = iconSize; - buffer[1] = iconSize; + uint8* destByte = buffer; + *(destByte++) = iconSize; + *(destByte++) = iconSize; + *(destByte++) = 1; // alpha bits per pixel // RGB data - uint8* destByte = buffer + 2; uint8* sourceByte = (uint8*)nativeIcon.Bits(); for(PRUint32 iconRow = 0; iconRow < iconSize; iconRow++) { diff --git a/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp b/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp index c5ff09569989..eee00335245b 100644 --- a/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp +++ b/modules/libpr0n/decoders/icon/gtk/nsIconChannel.cpp @@ -63,6 +63,7 @@ extern "C" { #include "nsEscape.h" #include "nsNetUtil.h" #include "nsIURL.h" +#include "nsStringStream.h" #include "nsIconChannel.h" @@ -70,60 +71,58 @@ NS_IMPL_ISUPPORTS2(nsIconChannel, nsIRequest, nsIChannel) -/** - * Given a path to a PNG Image, creates a channel from it. - * Note that the channel will delete the file when it's done with it. - * - * (When this function fails, the file will NOT be deleted) - */ static nsresult -pngfile_to_channel(const char* aFilename, nsIChannel** aChannel) { - // Now we have to create an uri for the file... - nsCOMPtr lf; - nsresult rv = NS_NewNativeLocalFile(nsDependentCString(aFilename), PR_FALSE, - getter_AddRefs(lf)); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr is; - rv = NS_NewLocalFileInputStream(getter_AddRefs(is), lf, -1, -1, - nsIFileInputStream::DELETE_ON_CLOSE); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr realURI; - rv = NS_NewFileURI(getter_AddRefs(realURI), lf); - if (NS_FAILED(rv)) - return rv; - - rv = NS_NewInputStreamChannel(aChannel, realURI, is, - NS_LITERAL_CSTRING("image/png")); - return rv; -} - -static nsresult -moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIChannel **aChannel) +moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI *aURI, + nsIChannel **aChannel) { - char tmpfile[] = "/tmp/moziconXXXXXX"; - int fd = mkstemp(tmpfile); - if (fd == -1) { - return NS_ERROR_UNEXPECTED; + int width = gdk_pixbuf_get_width(aPixbuf); + int height = gdk_pixbuf_get_height(aPixbuf); + NS_ENSURE_TRUE(height < 256 && width < 256 && height > 0 && width > 0 && + gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && + gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && + gdk_pixbuf_get_has_alpha(aPixbuf) && + gdk_pixbuf_get_n_channels(aPixbuf) == 4, + NS_ERROR_UNEXPECTED); + + const int n_channels = 4; + gsize buf_size = 3 + n_channels * height * width; + PRUint8 * const buf = (PRUint8*)NS_Alloc(buf_size); + NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); + PRUint8 *out = buf; + + *(out++) = width; + *(out++) = height; + *(out++) = 8; // bits of alpha per pixel + + const guchar * const pixels = gdk_pixbuf_get_pixels(aPixbuf); + int rowextra = gdk_pixbuf_get_rowstride(aPixbuf) - width * n_channels; + + // encode the RGB data and the A data + const guchar * in = pixels; + PRUint8 *alpha_out = out + height * width * 3; +#ifdef DEBUG + PRUint8 * const alpha_start = alpha_out; +#endif + for (int y = 0; y < height; ++y, in += rowextra) { + for (int x = 0; x < width; ++x) { + *(out++) = *(in++); // R + *(out++) = *(in++); // G + *(out++) = *(in++); // B + *(alpha_out++) = *(in++); // A + } } - GError *err = NULL; - gboolean ok = gdk_pixbuf_save(aPixbuf, tmpfile, "png", &err, NULL); - if (!ok) { - close(fd); - remove(tmpfile); - if (err) - g_error_free(err); - return NS_ERROR_UNEXPECTED; - } + NS_ASSERTION(out == alpha_start && alpha_out == buf + buf_size, + "size miscalculation"); - nsresult rv = pngfile_to_channel(tmpfile, aChannel); - close(fd); - if (NS_FAILED(rv)) - remove(tmpfile); + nsresult rv; + nsCOMPtr stream; + rv = NS_NewByteInputStream(getter_AddRefs(stream), (char*)buf, buf_size, + NS_ASSIGNMENT_ADOPT); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_NewInputStreamChannel(aChannel, aURI, stream, + NS_LITERAL_CSTRING("image/icon")); return rv; } @@ -322,7 +321,7 @@ nsIconChannel::InitWithGnome() // XXX Respect icon state - rv = moz_gdk_pixbuf_to_channel(scaled, getter_AddRefs(mRealChannel)); + rv = moz_gdk_pixbuf_to_channel(scaled, mURI, getter_AddRefs(mRealChannel)); gdk_pixbuf_unref(scaled); return rv; } @@ -374,7 +373,7 @@ nsIconChannel::Init(nsIURI* aURI) { if (!icon) return NS_ERROR_NOT_AVAILABLE; - nsresult rv = moz_gdk_pixbuf_to_channel(icon, getter_AddRefs(mRealChannel)); + nsresult rv = moz_gdk_pixbuf_to_channel(icon, mURI, getter_AddRefs(mRealChannel)); gdk_pixbuf_unref(icon); diff --git a/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp b/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp index 05bc09c88a87..e0822a207b9a 100644 --- a/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp +++ b/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp @@ -455,6 +455,7 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc nsCString iconBuffer; iconBuffer.Assign((char) numPixelsInRow); iconBuffer.Append((char) numPixelsInRow); + iconBuffer.Append((char) 1); // alpha bits per pixel CTabHandle cTabHandle = nsnull; CTabPtr colTable = nsnull; diff --git a/modules/libpr0n/decoders/icon/nsIconDecoder.cpp b/modules/libpr0n/decoders/icon/nsIconDecoder.cpp index 13ef9427d3d8..21406e36a58f 100644 --- a/modules/libpr0n/decoders/icon/nsIconDecoder.cpp +++ b/modules/libpr0n/decoders/icon/nsIconDecoder.cpp @@ -99,35 +99,35 @@ NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR { nsresult rv; - char *buf = (char *)PR_Malloc(count); + PRUint8 * const buf = (PRUint8 *)PR_Malloc(count); if (!buf) return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */ // read the data from the input stram... PRUint32 readLen; - rv = inStr->Read(buf, count, &readLen); + rv = inStr->Read((char*)buf, count, &readLen); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(readLen >= 3, NS_ERROR_UNEXPECTED); // w, h, alphaBits - char *data = buf; - - if (NS_FAILED(rv)) return rv; + PRUint8 * const buf_end = buf + readLen; + PRUint8 *data = buf; // since WriteFrom is only called once, go ahead and fire the on start notifications.. mObserver->OnStartDecode(nsnull); - PRUint32 i = 0; // Read size - PRInt32 w, h; - w = data[0]; - h = data[1]; - - data += 2; - - readLen -= i + 2; + PRInt32 w = *(data++); + PRInt32 h = *(data++); + PRUint8 alphaBits = *(data++); + NS_ENSURE_TRUE(w > 0 && h > 0 && (alphaBits == 1 || alphaBits == 8), + NS_ERROR_UNEXPECTED); mImage->Init(w, h, mObserver); if (mObserver) mObserver->OnStartContainer(nsnull, mImage); - rv = mFrame->Init(0, 0, w, h, gfxIFormats::RGB_A1, 24); + gfx_format format = alphaBits == 1 ? gfx_format(gfxIFormats::RGB_A1) + : gfx_format(gfxIFormats::RGB_A8); + rv = mFrame->Init(0, 0, w, h, format, 24); if (NS_FAILED(rv)) return rv; @@ -141,33 +141,21 @@ NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR mFrame->GetAlphaBytesPerRow(&abpr); mFrame->GetWidth(&width); mFrame->GetHeight(&height); + + NS_ENSURE_TRUE(buf_end - data >= PRInt32(bpr + abpr) * height, + NS_ERROR_UNEXPECTED); - i = 0; - PRInt32 rownum = 0; // XXX this better not have a decimal - - PRInt32 wroteLen = 0; + PRInt32 rownum; + for (rownum = 0; rownum < height; ++rownum, data += bpr) + mFrame->SetImageData(data, bpr, rownum * bpr); - do - { - PRUint8 *line = (PRUint8*)data + i*bpr; - mFrame->SetImageData(line, bpr, (rownum++)*bpr); + for (rownum = 0; rownum < height; ++rownum, data += abpr) + mFrame->SetAlphaData(data, abpr, rownum * abpr); - nsIntRect r(0, rownum, width, 1); - mObserver->OnDataAvailable(nsnull, mFrame, &r); + nsIntRect r(0, 0, width, height); + mObserver->OnDataAvailable(nsnull, mFrame, &r); - wroteLen += bpr ; - i++; - } while(rownum < height); - - - // now we want to send in the alpha data... - for (rownum = 0; rownum < height; rownum ++) - { - PRUint8 * line = (PRUint8*) data + abpr * rownum + height*bpr; - mFrame->SetAlphaData(line, abpr, (rownum)*abpr); - } - - PR_FREEIF(buf); + PR_Free(buf); return NS_OK; } diff --git a/modules/libpr0n/decoders/icon/nsIconDecoder.h b/modules/libpr0n/decoders/icon/nsIconDecoder.h index ced3dc161bdc..0d2926e2472b 100644 --- a/modules/libpr0n/decoders/icon/nsIconDecoder.h +++ b/modules/libpr0n/decoders/icon/nsIconDecoder.h @@ -68,8 +68,13 @@ // 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. -// Followed by 3 bytes per pixel for the color bitmap row after row. (for heigh * width * 3 bytes) -// Followed by bit mask data (used for transparency on the alpha channel). +// The third byte contains the number of bits per pixel in the alpha +// channel (either 1 or 8). +// Followed by 3 bytes per pixel for the color bitmap row after row, +// from top to bottom, with pixels left to right within rows, and +// RGB order within pixels, in platform endianness. +// Followed by alpha data (1 or 8 bits per pixel, see above) in the +// same order as the RGB data, and also in platform endianness. // // ////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/libpr0n/decoders/icon/nsIconModule.cpp b/modules/libpr0n/decoders/icon/nsIconModule.cpp index f92a90a17b91..f48d78638a87 100644 --- a/modules/libpr0n/decoders/icon/nsIconModule.cpp +++ b/modules/libpr0n/decoders/icon/nsIconModule.cpp @@ -40,7 +40,7 @@ #include "nsIGenericFactory.h" #include "nsIModule.h" -#if defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef USE_ICON_DECODER #include "nsIconDecoder.h" #endif #include "nsIconProtocolHandler.h" @@ -53,14 +53,14 @@ */ #define NS_ICONPROTOCOL_CID { 0xd0f9db12, 0x249c, 0x11d5, { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } } -#if defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef USE_ICON_DECODER NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconDecoder) #endif NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconProtocolHandler) static const nsModuleComponentInfo components[] = { -#if defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef USE_ICON_DECODER { "icon decoder", NS_ICONDECODER_CID, "@mozilla.org/image/decoder;2?type=image/icon", diff --git a/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp b/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp index 4c090f1e1265..bf8c3fd87b49 100644 --- a/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp +++ b/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp @@ -324,7 +324,7 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc PRUint32 cyOut = (fShrink ? BMHeader.cy / 2 : BMHeader.cy); PRUint32 cbColor = ALIGNEDBPR( cxOut, 24) * cyOut; PRUint32 cbMask = ALIGNEDBPR( cxOut, 1) * cyOut; - PRUint32 cbOutBuf = 2 + cbColor + cbMask; + PRUint32 cbOutBuf = 3 + cbColor + cbMask; pOutBuf = (PRUint8*)nsMemory::Alloc(cbOutBuf); if (!pOutBuf) break; @@ -353,6 +353,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc PRUint8* outPtr = pOutBuf; *outPtr++ = (PRUint8)cxOut; *outPtr++ = (PRUint8)cyOut; + // then the number of bits of alpha per pixel + *outPtr++ = (PRUint8)1; // convert the color bitmap pBMInfo->cbImage = cbInBuf;