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

This commit is contained in:
dbaron%dbaron.org 2006-02-13 00:25:59 +00:00
parent 542b79dc49
commit ad3f376058
8 changed files with 103 additions and 99 deletions

View File

@ -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

View File

@ -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++)
{

View File

@ -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<nsILocalFile> lf;
nsresult rv = NS_NewNativeLocalFile(nsDependentCString(aFilename), PR_FALSE,
getter_AddRefs(lf));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIInputStream> is;
rv = NS_NewLocalFileInputStream(getter_AddRefs(is), lf, -1, -1,
nsIFileInputStream::DELETE_ON_CLOSE);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURI> 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<nsIInputStream> 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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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.
//
//
//////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -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",

View File

@ -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;