mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
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:
parent
542b79dc49
commit
ad3f376058
@ -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
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
//
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user