Mozilla/mozilla/modules/libimg/mngcom/nsMNGDecoder.cpp
tor%cs.brown.edu cd57a86bb7 Update libmng snapshot. Not in default build.
git-svn-id: svn://10.0.0.236/trunk@73305 18797224-902f-48f8-a5cc-f745e15eee43
2000-06-27 14:40:32 +00:00

458 lines
12 KiB
C++

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Tim Rowley, tor@cs.brown.edu, original author
*/
#include "nsMNGDecoder.h"
#include "nsIImgDCallbk.h"
#include "nsMemory.h"
#include "libmng.h"
// Define this if you just want an RGB (no alpha) target
//#define NO_ALPHA
#ifdef NO_ALPHA
#define CHANNELS 3
#else
#define CHANNELS 4
#endif
// Decrease this to a sane value after this bug is fixed:
// http://bugzilla.mozilla.org/show_bug.cgi?id=41831
#define MOZ_MNG_BUFSIZE 262144
typedef struct ipng_str {
mng_handle handle;
PRUint32 width;
PRUint32 height;
PRUint8 *image; /* RGBA full image buffer */
PRUint8 *rowbuf; /* ImgDCBHaveRow is destructive. Grrr... */
void *timer_id;
PRUint8 writeBuffer[MOZ_MNG_BUFSIZE]; /* Circular buffer */
PRUint32 bytesBuffered;
PRUint32 writeStart;
PRUint32 bytesNeeded; /* number of bytes libmng wants (to know when */
/* we can call read_resume) */
il_container *ic;
} imng_struct, *imng_structp;
#define EXTRACT_STRUCTS \
il_container *ic = (il_container *)mng_get_userdata(handle); \
imng_structp imng_p = (imng_structp)ic->ds
#ifdef DEBUG_tor
#define dprintf(x) fprintf x
#else
#define dprintf(x)
#endif
// Callbacks for libmng
//===========================================================
static mng_bool
il_mng_openstream(mng_handle handle)
{
return MNG_TRUE;
}
static mng_bool
il_mng_closestream(mng_handle handle)
{
return MNG_TRUE;
}
static mng_bool
il_mng_readdata(mng_handle handle, mng_ptr buf,
mng_uint32 size, mng_uint32 *read)
{
// dprintf((stderr, "=== readdata(%d)\n", size));
EXTRACT_STRUCTS;
if (imng_p->bytesBuffered >= size) {
int32 endChunk = (MOZ_MNG_BUFSIZE-imng_p->writeStart);
memcpy(buf, imng_p->writeBuffer+imng_p->writeStart,
PR_MIN(endChunk, size));
if (endChunk < size)
memcpy((PRUint8 *)buf+endChunk, imng_p->writeBuffer, size-endChunk);
imng_p->bytesBuffered -= size;
imng_p->writeStart = (imng_p->writeStart+size) % MOZ_MNG_BUFSIZE;
imng_p->bytesNeeded = 0;
*read = size;
return MNG_TRUE;
} else {
imng_p->bytesNeeded = size;
*read = 0;
return MNG_FALSE;
}
}
static mng_bool
il_mng_processheader(mng_handle handle, mng_uint32 width, mng_uint32 height)
{
dprintf((stderr, "=== processheader(%d %d)\n", width, height));
EXTRACT_STRUCTS;
imng_p->width = width;
imng_p->height = height;
ic->src_header->width = width;
ic->src_header->height = height;
#ifndef NO_ALPHA
if (mng_get_simplicity(handle) & MNG_SIMPLICITY_TRANSPARENCY) {
dprintf((stderr, "--- MNG ALPHA\n"));
ic->image->header.alpha_bits = 8;
} else {
ic->image->header.alpha_bits = 1;
}
ic->image->header.alpha_shift = 0;
ic->image->header.is_interleaved_alpha = TRUE;
#endif
imng_p->image =
(unsigned char*)nsMemory::Alloc(CHANNELS*width*height);
memset(imng_p->image, 0, CHANNELS*width*height);
imng_p->rowbuf = (unsigned char*)nsMemory::Alloc(CHANNELS*width);
ic->imgdcb->ImgDCBImageSize();
ic->imgdcb->ImgDCBSetupColorspaceConverter();
return MNG_TRUE;
}
static mng_ptr
il_mng_getcanvasline(mng_handle handle, mng_uint32 iLinenr)
{
EXTRACT_STRUCTS;
return imng_p->image+CHANNELS*imng_p->width*iLinenr;
}
static mng_bool
il_mng_refresh(mng_handle handle,
mng_uint32 top, mng_uint32 left,
mng_uint32 bottom, mng_uint32 right)
{
// dprintf((stderr, "=== refresh(top=%d left=%d bottom=%d right=%d)\n",
// top, left, bottom, right));
EXTRACT_STRUCTS;
for (int y=top; y<bottom; y++) {
memcpy(imng_p->rowbuf,
imng_p->image+y*CHANNELS*imng_p->width,
CHANNELS*imng_p->width);
ic->imgdcb->ImgDCBHaveRow(0 /* color index data */,
imng_p->rowbuf /* rgb[a] */,
0 /* x-offset */,
imng_p->width /* width in pixels */,
y /* start row */,
1 /* row duplication count */,
ilErase /* draw mode */,
0 /* pass */);
}
return MNG_TRUE;
}
static mng_uint32
il_mng_gettickcount(mng_handle handle)
{
// dprintf((stderr, "=== gettickcount()\n"));
return PR_IntervalToMilliseconds(PR_IntervalNow());
}
static void
il_mng_timeout_func(void *data)
{
mng_handle handle = (mng_handle)data;
EXTRACT_STRUCTS;
// dprintf((stderr, "il_mng_timeout_func\n"));
imng_p->timer_id = 0;
mng_display_resume(handle);
}
static mng_bool
il_mng_settimer(mng_handle handle, mng_uint32 msec)
{
dprintf((stderr, "=== settimer(%d)\n", msec));
EXTRACT_STRUCTS;
imng_p->timer_id =
ic->imgdcb->ImgDCBSetTimeout(il_mng_timeout_func,
(void *)handle,
msec);
return MNG_TRUE;
}
static mng_ptr
il_mng_alloc(mng_uint32 size)
{
// dprintf((stderr, "=== malloc(%d)\n", size));
void *ptr = nsMemory::Alloc(size);
memset(ptr, 0, size);
return ptr;
}
static void
il_mng_free(mng_ptr ptr, mng_uint32 size)
{
// dprintf((stderr, "=== free(%d)\n", size));
nsMemory::Free(ptr);
}
// Boilerplate methods... *yawn*
//===========================================================
MNGDecoder::MNGDecoder(il_container* aContainer)
{
dprintf((stderr, "MNG::MNGDecoder()\n"));
NS_INIT_REFCNT();
ilContainer = aContainer;
}
MNGDecoder::~MNGDecoder(void)
{
dprintf((stderr, "MNG::~MNGDecoder()\n"));
}
NS_IMPL_ISUPPORTS1(MNGDecoder, nsIImgDecoder)
NS_METHOD
MNGDecoder::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
dprintf((stderr, "MNG::Create()\n"));
nsresult rv;
if (aOuter) return NS_ERROR_NO_AGGREGATION;
il_container *ic = new il_container();
if (!ic) return NS_ERROR_OUT_OF_MEMORY;
MNGDecoder *decoder = new MNGDecoder(ic);
if (!decoder) {
delete ic;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(decoder);
rv = decoder->QueryInterface(aIID, aResult);
NS_RELEASE(decoder);
/* why are we creating and destroying this object for no reason? */
delete ic; /* is a place holder */
return rv;
}
// Hooking mozilla and libmng together...
//===========================================================
NS_IMETHODIMP
MNGDecoder::ImgDInit()
{
dprintf((stderr, "MNG::ImgDInit()\n"));
int ret;
if( ilContainer != NULL ) {
imng_structp imng_p;
imng_p = (imng_structp) nsMemory::Alloc(sizeof(imng_struct));
memset(imng_p, 0, sizeof(imng_struct));
if (!imng_p)
return PR_FALSE;
ilContainer->image->header.width = ilContainer->dest_width;
ilContainer->image->header.height = ilContainer->dest_height;
ilContainer->ds = imng_p;
imng_p->ic = ilContainer;
/* Initialize the container's source image header. */
/* Always decode to 24 bit pixdepth */
NI_ColorSpace *src_color_space = ilContainer->src_header->color_space;
src_color_space->type = NI_TrueColor;
src_color_space->pixmap_depth = 24;
src_color_space->bit_alloc.index_depth = 0;
/* pass ic as user data */
imng_p->handle =
mng_initialize(ilContainer, il_mng_alloc, il_mng_free, NULL);
////////////
// Gamma correction - gross hack, but it's what mozilla's PNG
// decoder does and nobody has complained yet...
double LUT_exponent, CRT_exponent = 2.2, display_exponent;
/* set up gamma correction for Mac, Unix and (Win32 and everything else)
* using educated guesses for display-system exponents; do preferences
* later */
#if defined(XP_MAC)
LUT_exponent = 1.8 / 2.61;
#elif defined(XP_UNIX)
# if defined(__sgi)
LUT_exponent = 1.0 / 1.7; /* typical default for SGI console */
# elif defined(NeXT)
LUT_exponent = 1.0 / 2.2; /* typical default for NeXT cube */
# else
LUT_exponent = 1.0; /* default for most other Unix workstations */
# endif
#else
LUT_exponent = 1.0; /* virtually all PCs and most other systems */
#endif
/* (alternatively, could check for SCREEN_GAMMA environment variable) */
display_exponent = LUT_exponent * CRT_exponent;
mng_set_dfltimggamma(imng_p->handle, 0.45455);
mng_set_displaygamma(imng_p->handle, display_exponent);
////////////
#ifndef NO_ALPHA
mng_set_canvasstyle(imng_p->handle, MNG_CANVAS_RGBA8);
#endif
mng_setcb_openstream(imng_p->handle, il_mng_openstream);
mng_setcb_closestream(imng_p->handle, il_mng_closestream);
mng_setcb_readdata(imng_p->handle, il_mng_readdata);
mng_setcb_processheader(imng_p->handle, il_mng_processheader);
mng_setcb_getcanvasline(imng_p->handle, il_mng_getcanvasline);
mng_setcb_refresh(imng_p->handle, il_mng_refresh);
mng_setcb_gettickcount(imng_p->handle, il_mng_gettickcount);
mng_setcb_settimer(imng_p->handle, il_mng_settimer);
mng_setcb_memalloc(imng_p->handle, il_mng_alloc);
mng_setcb_memfree(imng_p->handle, il_mng_free);
dprintf((stderr, "starting mng_readdisplay...\n"));
mng_retcode ret = mng_readdisplay(imng_p->handle);
dprintf((stderr, "readdisplay() return was %d\n", ret));
}
return NS_OK;
}
NS_IMETHODIMP
MNGDecoder::ImgDWriteReady(PRUint32 *max_read)
{
dprintf((stderr, "MNG::ImgDWriteReady() = "));
imng_structp imng_p = (imng_structp)ilContainer->ds;
*max_read = MOZ_MNG_BUFSIZE-imng_p->bytesBuffered;
dprintf((stderr, "%d\n", *max_read));
return NS_OK;
}
NS_IMETHODIMP
MNGDecoder::ImgDWrite(const unsigned char *buf, int32 len)
{
dprintf((stderr, "MNG::ImgDWrite(%d)\n", len));
if (ilContainer != NULL) {
imng_structp imng_p = (imng_structp)ilContainer->ds;
if (len>MOZ_MNG_BUFSIZE-imng_p->bytesBuffered) {
fprintf(stderr, "MNG too large - abort, abort!\n");
fprintf(stderr, " http://bugzilla.mozilla.org/show_bug.cgi?id=41831\n");
return NS_ERROR_FAILURE;
}
int32 endChunk =
(MOZ_MNG_BUFSIZE-(imng_p->writeStart+imng_p->bytesBuffered));
memcpy(imng_p->writeBuffer+imng_p->writeStart+imng_p->bytesBuffered,
buf, PR_MIN(endChunk,len));
if (endChunk < len)
memcpy(imng_p->writeBuffer, buf+endChunk, len-endChunk);
imng_p->bytesBuffered += len;
if (imng_p->bytesNeeded &&
(imng_p->bytesBuffered >= imng_p->bytesNeeded)) {
dprintf((stderr, "\tresuming read...\n"));
mng_retcode ret = mng_read_resume(imng_p->handle);
dprintf((stderr, "\tread_resume() return was %d\n", ret));
}
}
return NS_OK;
}
NS_IMETHODIMP
MNGDecoder::ImgDComplete()
{
dprintf((stderr, "MNG::ImgDComplete()\n"));
return NS_OK;
}
NS_IMETHODIMP
MNGDecoder::ImgDAbort()
{
dprintf((stderr, "MNG::ImgDAbort()\n"));
int ret;
if( ilContainer != NULL ) {
imng_structp imng_p = (imng_structp)ilContainer->ds;
if (!imng_p)
return NS_OK;
if (imng_p->timer_id) {
ilContainer->imgdcb->ImgDCBClearTimeout(imng_p->timer_id);
imng_p->timer_id = 0;
}
mng_display_freeze(imng_p->handle);
mng_cleanup(&imng_p->handle);
nsMemory::Free(imng_p->image);
nsMemory::Free(imng_p->rowbuf);
nsMemory::Free(imng_p);
imng_p = NULL;
}
return NS_OK;
}