diff options
Diffstat (limited to 'src/kernel/tqmngio.cpp')
-rw-r--r-- | src/kernel/tqmngio.cpp | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/kernel/tqmngio.cpp b/src/kernel/tqmngio.cpp new file mode 100644 index 000000000..0f257ae88 --- /dev/null +++ b/src/kernel/tqmngio.cpp @@ -0,0 +1,460 @@ +/**************************************************************************** +** +** Implementation of MNG TQImage IOHandler +** +** Created : 970521 +** +** Copyright (C) 1997-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqdatetime.h" + +#ifndef TQT_NO_IMAGEIO_MNG + +#include "tqimage.h" +#include "tqasyncimageio.h" +#include "tqiodevice.h" +#include "tqmngio.h" + +// Define XMD_H prohibits the included headers of libmng.h to typedef INT32. +// This is needed for Borland with STL support, since in that case, INT32 is +// already defined by some Borland header. +#define XMD_H +#if defined(Q_OS_UNIXWARE) +# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this +#endif +#include <libmng.h> +#include <stdlib.h> + + +#ifndef TQT_NO_ASYNC_IMAGE_IO + +class TQMNGFormat : public TQImageFormat { +public: + TQMNGFormat(); + virtual ~TQMNGFormat(); + + int decode(TQImage& img, TQImageConsumer* consumer, + const uchar* buffer, int length); + + bool openstream() + { + // ### We should figure out how many loops an MNG has, but for now always assume infinite. + if (consumer) + consumer->setLooping(0); + return TRUE; + } + bool closestream( ) + { + if (consumer) + consumer->end(); + return TRUE; + } + bool readdata( mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead ) + { + uint m = ndata + nbuffer - ubuffer; + if ( iBuflen > m ) { + iBuflen = m; + } + *pRead = iBuflen; + uint n = nbuffer-ubuffer; + if ( iBuflen < n ) { + // enough in buffer + memcpy(pBuf, buffer+ubuffer, iBuflen); + ubuffer += iBuflen; + return TRUE; + } + if ( n ) { + // consume buffer + memcpy(pBuf, buffer+ubuffer, n ); + pBuf = (mng_ptr)((char*)pBuf + n); + iBuflen -= n; + ubuffer = nbuffer; + } + if ( iBuflen ) { + // fill from incoming data + memcpy(pBuf, data, iBuflen); + data += iBuflen; + ndata -= iBuflen; + } + return TRUE; + } + bool errorproc( mng_int32 iErrorcode, + mng_int8 /*iSeverity*/, + mng_chunkid iChunkname, + mng_uint32 /*iChunkseq*/, + mng_int32 iExtra1, + mng_int32 iExtra2, + mng_pchar zErrortext ) + { + tqWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d", + iErrorcode, zErrortext ? zErrortext : "", + (iChunkname>>24)&0xff, + (iChunkname>>16)&0xff, + (iChunkname>>8)&0xff, + (iChunkname>>0)&0xff, + iExtra1,iExtra2); + return TRUE; + } + bool processheader( mng_uint32 iWidth, mng_uint32 iHeight ) + { + image->create(iWidth,iHeight,32); + image->setAlphaBuffer(TRUE); + memset(image->bits(),0,iWidth*iHeight*4); + consumer->setSize(iWidth,iHeight); + mng_set_canvasstyle(handle, + TQImage::systemByteOrder() == TQImage::LittleEndian + ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8 ); + return TRUE; + } + mng_ptr getcanvasline( mng_uint32 iLinenr ) + { + return image->scanLine(iLinenr); + } + mng_bool refresh( mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h ) + { + TQRect r(x,y,w,h); + consumer->changed(r); + consumer->setFramePeriod(0); + consumer->frameDone(); + return TRUE; + } + mng_uint32 gettickcount( ) + { + return timer.elapsed() - losttime; + } + bool settimer( mng_uint32 iMsecs ) + { + consumer->setFramePeriod(iMsecs); + consumer->frameDone(); + state = Time; + losingtimer.start(); + losttime -= iMsecs; + return TRUE; + } + +private: + // Animation-level information + enum { MovieStart, Time, Data, Data2 } state; + + // Image-level information + mng_handle handle; + + // For storing unused data + uchar *buffer; + uint maxbuffer; + uint nbuffer; + + // Timing + TQTime timer; + TQTime losingtimer; + int losttime; + + void enlargeBuffer(uint n) + { + if ( n > maxbuffer ) { + maxbuffer = n; + buffer = (uchar*)realloc(buffer,n); + } + } + + // Temporary locals during single data-chunk processing + const uchar* data; + uint ndata; + uint ubuffer; + TQImageConsumer* consumer; + TQImage* image; +}; + +class TQMNGFormatType : public TQImageFormatType +{ + TQImageFormat* decoderFor(const uchar* buffer, int length); + const char* formatName() const; +}; + + +/* + \class TQMNGFormat tqmngio.h + \brief Incremental image decoder for MNG image format. + + \ingroup images + \ingroup graphics + + This subclass of TQImageFormat decodes MNG format images, + including animated MNGs. + + Animated MNG images are standard MNG images. The MNG standard + defines two extension chunks that are useful for animations: + + <dl> + <dt>gIFg - GIF-like Graphic Control Extension + <dd>Includes frame disposal, user input flag (we ignore this), + and inter-frame delay. + <dt>gIFx - GIF-like Application Extension + <dd>Multi-purpose, but we just use the Netscape extension + which specifies looping. + </dl> + + The subimages usually contain a offset chunk (oFFs) but need not. + + The first image defines the "screen" size. Any subsequent image that + doesn't fit is clipped. + +TODO: decide on this point. gIFg gives disposal types, so it can be done. + All images paste (\e not composite, just place all-channel copying) + over the previous image to produce a subsequent frame. +*/ + +/* + \class TQMNGFormatType tqasyncimageio.h + \brief Incremental image decoder for MNG image format. + + \ingroup images + \ingroup graphics + \ingroup io + + This subclass of TQImageFormatType recognizes MNG + format images, creating a TQMNGFormat when required. An instance + of this class is created automatically before any other factories, + so you should have no need for such objects. +*/ + +TQImageFormat* TQMNGFormatType::decoderFor( const uchar* buffer, int length ) +{ + if (length < 8) return 0; + + if ((buffer[0]==138 // MNG signature + && buffer[1]=='M' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10) + || (buffer[0]==139 // JNG signature + && buffer[1]=='J' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10) +#ifdef TQT_NO_IMAGEIO_PNG // if we don't have native PNG support use libmng + || (buffer[0]==137 // PNG signature + && buffer[1]=='P' + && buffer[2]=='N' + && buffer[3]=='G' + && buffer[4]==13 + && buffer[5]==10 + && buffer[6]==26 + && buffer[7]==10) +#endif + ) + return new TQMNGFormat; + return 0; +} + +const char* TQMNGFormatType::formatName() const +{ + return "MNG"; +} + + +/*! + Constructs a TQMNGFormat. +*/ +TQMNGFormat::TQMNGFormat() +{ + state = MovieStart; + handle = 0; + nbuffer = 0; + maxbuffer = 0; + buffer = 0; + losttime = 0; +} + +/* + Destroys a TQMNGFormat. +*/ +TQMNGFormat::~TQMNGFormat() +{ + // We're setting the consumer to 0 since it may have been + // deleted by read_async_image in tqimage.cpp + consumer = 0; + if (handle) mng_cleanup(&handle); +} + + +// C-callback to C++-member-function conversion +// +static mng_bool openstream( mng_handle handle ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->openstream(); +} +static mng_bool closestream( mng_handle handle ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->closestream(); +} +static mng_bool readdata( mng_handle handle, mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->readdata(pBuf,iBuflen,pRead); +} +static mng_bool errorproc( mng_handle handle, + mng_int32 iErrorcode, + mng_int8 iSeverity, + mng_chunkid iChunkname, + mng_uint32 iChunkseq, + mng_int32 iExtra1, + mng_int32 iExtra2, + mng_pchar zErrortext ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->errorproc(iErrorcode, + iSeverity,iChunkname,iChunkseq,iExtra1,iExtra2,zErrortext); +} +static mng_bool processheader( mng_handle handle, + mng_uint32 iWidth, mng_uint32 iHeight ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->processheader(iWidth,iHeight); +} +static mng_ptr getcanvasline( mng_handle handle, mng_uint32 iLinenr ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->getcanvasline(iLinenr); +} +static mng_bool refresh( mng_handle handle, + mng_uint32 iTop, + mng_uint32 iLeft, + mng_uint32 iBottom, + mng_uint32 iRight ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->refresh(iTop,iLeft,iBottom,iRight); +} +static mng_uint32 gettickcount( mng_handle handle ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->gettickcount(); +} +static mng_bool settimer( mng_handle handle, mng_uint32 iMsecs ) +{ + return ((TQMNGFormat*)mng_get_userdata(handle))->settimer(iMsecs); +} + +static mng_ptr memalloc( mng_size_t iLen ) +{ + return calloc(1,iLen); +} +static void memfree( mng_ptr iPtr, mng_size_t /*iLen*/ ) +{ + free(iPtr); +} + +/*! + This function decodes some data into image changes. + + Returns the number of bytes consumed. +*/ +int TQMNGFormat::decode( TQImage& img, TQImageConsumer* cons, + const uchar* buf, int length ) +{ + consumer = cons; + image = &img; + + data = buf; + ndata = length; + ubuffer = 0; + + if ( state == MovieStart ) { + handle = mng_initialize( (mng_ptr)this, ::memalloc, ::memfree, 0 ); + mng_set_suspensionmode( handle, MNG_TRUE ); + mng_setcb_openstream( handle, ::openstream ); + mng_setcb_closestream( handle, ::closestream ); + mng_setcb_readdata( handle, ::readdata ); + mng_setcb_errorproc( handle, ::errorproc ); + mng_setcb_processheader( handle, ::processheader ); + mng_setcb_getcanvasline( handle, ::getcanvasline ); + mng_setcb_refresh( handle, ::refresh ); + mng_setcb_gettickcount( handle, ::gettickcount ); + mng_setcb_settimer( handle, ::settimer ); + state = Data; + mng_readdisplay(handle); + losingtimer.start(); + } + + losttime += losingtimer.elapsed(); + if ( ndata || !length ) + mng_display_resume(handle); + losingtimer.start(); + + image = 0; + + nbuffer -= ubuffer; + if ( nbuffer ) { + // Move back unused tail + memcpy(buffer,buffer+ubuffer,nbuffer); + } + if ( ndata ) { + // Not all used. + enlargeBuffer(nbuffer+ndata); + memcpy(buffer+nbuffer,data,ndata); + nbuffer += ndata; + } + + return length; +} + +static TQMNGFormatType* globalMngFormatTypeObject = 0; + +#endif // TQT_NO_ASYNC_IMAGE_IO + +#ifndef TQT_NO_ASYNC_IMAGE_IO +void qCleanupMngIO() +{ + if ( globalMngFormatTypeObject ) { + delete globalMngFormatTypeObject; + globalMngFormatTypeObject = 0; + } +} +#endif + +void qInitMngIO() +{ + static bool done = FALSE; + if ( !done ) { + done = TRUE; +#ifndef TQT_NO_ASYNC_IMAGE_IO + globalMngFormatTypeObject = new TQMNGFormatType; + tqAddPostRoutine( qCleanupMngIO ); +#endif + } +} + +#endif // TQT_NO_IMAGEIO_MNG |