/* ************************************************************************** */
/* *             For conditions of distribution and use,                    * */
/* *                see copyright notice in libmng.h                        * */
/* ************************************************************************** */
/* *                                                                        * */
/* * project   : libmng                                                     * */
/* * file      : libmng_display.c          copyright (c) 2000 G.Juyn        * */
/* * version   : 1.0.2                                                      * */
/* *                                                                        * */
/* * purpose   : Display management (implementation)                        * */
/* *                                                                        * */
/* * author    : G.Juyn                                                     * */
/* * web       : http://www.3-t.com                                         * */
/* * email     : mailto:info@3-t.com                                        * */
/* *                                                                        * */
/* * comment   : implementation of the display management routines          * */
/* *                                                                        * */
/* * changes   : 0.5.1 - 05/08/2000 - G.Juyn                                * */
/* *             - changed strict-ANSI stuff                                * */
/* *             0.5.1 - 05/11/2000 - G.Juyn                                * */
/* *             - added callback error-reporting support                   * */
/* *             - fixed frame_delay misalignment                           * */
/* *             0.5.1 - 05/12/2000 - G.Juyn                                * */
/* *             - added sanity check for frozen status                     * */
/* *             - changed trace to macro for callback error-reporting      * */
/* *             0.5.1 - 05/13/2000 - G.Juyn                                * */
/* *             - changed display_mend to reset state to initial or SAVE   * */
/* *             - added eMNGma hack (will be removed in 1.0.0 !!!)         * */
/* *             - added TERM animation object pointer (easier reference)   * */
/* *             - added process_save & process_seek routines               * */
/* *             0.5.1 - 05/14/2000 - G.Juyn                                * */
/* *             - added save_state and restore_state for SAVE/SEEK/TERM    * */
/* *               processing                                               * */
/* *                                                                        * */
/* *             0.5.2 - 05/20/2000 - G.Juyn                                * */
/* *             - added JNG support (JHDR/JDAT)                            * */
/* *             0.5.2 - 05/23/2000 - G.Juyn                                * */
/* *             - fixed problem with DEFI clipping                         * */
/* *             0.5.2 - 05/30/2000 - G.Juyn                                * */
/* *             - added delta-image support (DHDR,PROM,IPNG,IJNG)          * */
/* *             0.5.2 - 05/31/2000 - G.Juyn                                * */
/* *             - fixed pointer confusion (contributed by Tim Rowley)      * */
/* *             0.5.2 - 06/03/2000 - G.Juyn                                * */
/* *             - fixed makeup for Linux gcc compile                       * */
/* *             0.5.2 - 06/05/2000 - G.Juyn                                * */
/* *             - added support for RGB8_A8 canvasstyle                    * */
/* *             0.5.2 - 06/09/2000 - G.Juyn                                * */
/* *             - fixed timer-handling to run with Mozilla (Tim Rowley)    * */
/* *             0.5.2 - 06/10/2000 - G.Juyn                                * */
/* *             - fixed some compilation-warnings (contrib Jason Morris)   * */
/* *                                                                        * */
/* *             0.5.3 - 06/12/2000 - G.Juyn                                * */
/* *             - fixed display of stored JNG images                       * */
/* *             0.5.3 - 06/13/2000 - G.Juyn                                * */
/* *             - fixed problem with BASI-IEND as object 0                 * */
/* *             0.5.3 - 06/16/2000 - G.Juyn                                * */
/* *             - changed progressive-display processing                   * */
/* *             0.5.3 - 06/17/2000 - G.Juyn                                * */
/* *             - changed delta-image processing                           * */
/* *             0.5.3 - 06/20/2000 - G.Juyn                                * */
/* *             - fixed some minor stuff                                   * */
/* *             0.5.3 - 06/21/2000 - G.Juyn                                * */
/* *             - added speed-modifier to timing routine                   * */
/* *             0.5.3 - 06/22/2000 - G.Juyn                                * */
/* *             - added support for PPLT chunk processing                  * */
/* *             0.5.3 - 06/29/2000 - G.Juyn                                * */
/* *             - swapped refresh parameters                               * */
/* *                                                                        * */
/* *             0.9.0 - 06/30/2000 - G.Juyn                                * */
/* *             - changed refresh parameters to 'x,y,width,height'         * */
/* *                                                                        * */
/* *             0.9.1 - 07/07/2000 - G.Juyn                                * */
/* *             - implemented support for freeze/reset/resume & go_xxxx    * */
/* *             0.9.1 - 07/08/2000 - G.Juyn                                * */
/* *             - added support for improved timing                        * */
/* *             0.9.1 - 07/14/2000 - G.Juyn                                * */
/* *             - changed EOF processing behavior                          * */
/* *             - fixed TERM delay processing                              * */
/* *             0.9.1 - 07/15/2000 - G.Juyn                                * */
/* *             - fixed freeze & reset processing                          * */
/* *             0.9.1 - 07/16/2000 - G.Juyn                                * */
/* *             - fixed storage of images during mng_read()                * */
/* *             - fixed support for mng_display() after mng_read()         * */
/* *             0.9.1 - 07/24/2000 - G.Juyn                                * */
/* *             - fixed reading of still-images                            * */
/* *                                                                        * */
/* *             0.9.2 - 08/05/2000 - G.Juyn                                * */
/* *             - changed file-prefixes                                    * */
/* *                                                                        * */
/* *             0.9.3 - 08/07/2000 - G.Juyn                                * */
/* *             - B111300 - fixup for improved portability                 * */
/* *             0.9.3 - 08/21/2000 - G.Juyn                                * */
/* *             - fixed TERM processing delay of 0 msecs                   * */
/* *             0.9.3 - 08/26/2000 - G.Juyn                                * */
/* *             - added MAGN chunk                                         * */
/* *             0.9.3 - 09/10/2000 - G.Juyn                                * */
/* *             - fixed problem with no refresh after TERM                 * */
/* *             - fixed DEFI behavior                                      * */
/* *             0.9.3 - 09/16/2000 - G.Juyn                                * */
/* *             - fixed timing & refresh behavior for single PNG/JNG       * */
/* *             0.9.3 - 09/19/2000 - G.Juyn                                * */
/* *             - refixed timing & refresh behavior for single PNG/JNG     * */
/* *             0.9.3 - 10/02/2000 - G.Juyn                                * */
/* *             - fixed timing again (this is getting boring...)           * */
/* *             - refixed problem with no refresh after TERM               * */
/* *             0.9.3 - 10/16/2000 - G.Juyn                                * */
/* *             - added JDAA chunk                                         * */
/* *             0.9.3 - 10/17/2000 - G.Juyn                                * */
/* *             - fixed support for bKGD                                   * */
/* *             0.9.3 - 10/18/2000 - G.Juyn                                * */
/* *             - fixed delta-processing behavior                          * */
/* *             0.9.3 - 10/19/2000 - G.Juyn                                * */
/* *             - added storage for pixel-/alpha-sampledepth for delta's   * */
/* *             0.9.3 - 10/27/2000 - G.Juyn                                * */
/* *             - fixed seperate read() & display() processing             * */
/* *                                                                        * */
/* *             0.9.4 - 10/31/2000 - G.Juyn                                * */
/* *             - fixed possible loop in display_resume() (Thanks Vova!)   * */
/* *             0.9.4 - 11/20/2000 - G.Juyn                                * */
/* *             - fixed unwanted repetition in mng_readdisplay()           * */
/* *             0.9.4 - 11/24/2000 - G.Juyn                                * */
/* *             - moved restore of object 0 to libmng_display              * */
/* *             - added restore of object 0 to TERM processing !!!         * */
/* *             - fixed TERM delay processing                              * */
/* *             - fixed TERM end processing (count = 0)                    * */
/* *             0.9.4 - 12/16/2000 - G.Juyn                                * */
/* *             - fixed mixup of data- & function-pointers (thanks Dimitri)* */
/* *             0.9.4 -  1/18/2001 - G.Juyn                                * */
/* *             - removed test filter-methods 1 & 65                       * */
/* *             - set default level-set for filtertype=64 to all zeroes    * */
/* *                                                                        * */
/* *             0.9.5 -  1/20/2001 - G.Juyn                                * */
/* *             - fixed compiler-warnings Mozilla (thanks Tim)             * */
/* *             0.9.5 -  1/23/2001 - G.Juyn                                * */
/* *             - fixed timing-problem with switching framing_modes        * */
/* *                                                                        * */
/* *             1.0.1 - 02/08/2001 - G.Juyn                                * */
/* *             - added MEND processing callback                           * */
/* *             1.0.1 - 02/13/2001 - G.Juyn                                * */
/* *             - fixed first FRAM_MODE=4 timing problem                   * */
/* *             1.0.1 - 04/21/2001 - G.Juyn                                * */
/* *             - fixed memory-leak for JNGs with alpha (Thanks Gregg!)    * */
/* *             - added BGRA8 canvas with premultiplied alpha              * */
/* *                                                                        * */
/* *             1.0.2 - 06/25/2001 - G.Juyn                                * */
/* *             - fixed memory-leak with delta-images (Thanks Michael!)    * */
/* *                                                                        * */
/* ************************************************************************** */

#include "libmng.h"
#include "libmng_data.h"
#include "libmng_error.h"
#include "libmng_trace.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "libmng_objects.h"
#include "libmng_object_prc.h"
#include "libmng_memory.h"
#include "libmng_zlib.h"
#include "libmng_jpeg.h"
#include "libmng_cms.h"
#include "libmng_pixels.h"
#include "libmng_display.h"

#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI)
#pragma option -A                      /* force ANSI-C */
#endif

/* ************************************************************************** */

#ifdef MNG_INCLUDE_DISPLAY_PROCS

/* ************************************************************************** */

mng_retcode set_delay (mng_datap  pData,
                       mng_uint32 iInterval)
{
  if (!iInterval)                      /* at least 1 msec please! */
    iInterval = 1;

  if (!pData->fSettimer ((mng_handle)pData, iInterval))
    MNG_ERROR (pData, MNG_APPTIMERERROR)

  pData->bTimerset = MNG_TRUE;         /* and indicate so */

  return MNG_NOERROR;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * Progressive display refresh - does the call to the refresh callback    * */
/* * and sets the timer to allow the app to perform the actual refresh to   * */
/* * the screen (eg. process its main message-loop)                         * */
/* *                                                                        * */
/* ************************************************************************** */

mng_retcode display_progressive_refresh (mng_datap  pData,
                                         mng_uint32 iInterval)
{
  if (!pData->bSearching)              /* we mustn't be searching !!! */
  {
    if ((pData->bRunning) &&           /* let the app refresh first ? */
        (pData->iUpdatetop < pData->iUpdatebottom) && (pData->iUpdateleft < pData->iUpdateright))
    {
      if (!pData->fRefresh (((mng_handle)pData),
                            pData->iUpdateleft, pData->iUpdatetop,
                            pData->iUpdateright  - pData->iUpdateleft,
                            pData->iUpdatebottom - pData->iUpdatetop))
        MNG_ERROR (pData, MNG_APPMISCERROR)

      pData->iUpdateleft   = 0;        /* reset update-region */
      pData->iUpdateright  = 0;
      pData->iUpdatetop    = 0;
      pData->iUpdatebottom = 0;        /* reset refreshneeded indicator */
      pData->bNeedrefresh  = MNG_FALSE;
                                       /* interval requested ? */
      if ((!pData->bFreezing) && (iInterval))
      {                                /* setup the timer */
        mng_retcode iRetcode = set_delay (pData, iInterval);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
    }
  }

  return MNG_NOERROR;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * Generic display routines                                               * */
/* *                                                                        * */
/* ************************************************************************** */

mng_retcode interframe_delay (mng_datap pData)
{
  mng_uint32  iWaitfor = 0;
  mng_uint32  iInterval;
  mng_uint32  iRuninterval;
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_INTERFRAME_DELAY, MNG_LC_START)
#endif

  if (!pData->bSearching)              /* we mustn't be searching !!! */
  {                                    
    if (pData->iFramedelay > 0)        /* real delay ? */
    {
      if ((pData->bRunning) &&         /* let the app refresh first ? */
          (pData->iUpdatetop < pData->iUpdatebottom) && (pData->iUpdateleft < pData->iUpdateright))
        if (!pData->fRefresh (((mng_handle)pData),
                              pData->iUpdateleft,  pData->iUpdatetop,
                              pData->iUpdateright - pData->iUpdateleft,
                              pData->iUpdatebottom - pData->iUpdatetop))
          MNG_ERROR (pData, MNG_APPMISCERROR)

      pData->iUpdateleft   = 0;        /* reset update-region */
      pData->iUpdateright  = 0;
      pData->iUpdatetop    = 0;
      pData->iUpdatebottom = 0;        /* reset refreshneeded indicator */
      pData->bNeedrefresh  = MNG_FALSE;
                                       /* get current tickcount */
      pData->iRuntime = pData->fGettickcount ((mng_handle)pData);
                                       /* calculate interval since last sync-point */
      if (pData->iRuntime < pData->iSynctime)
        iRuninterval    = pData->iRuntime + ~pData->iSynctime + 1;
      else
        iRuninterval    = pData->iRuntime - pData->iSynctime;
                                       /* calculate actual run-time */
      if (pData->iRuntime < pData->iStarttime)
        pData->iRuntime = pData->iRuntime + ~pData->iStarttime + 1;
      else
        pData->iRuntime = pData->iRuntime - pData->iStarttime;

      if (pData->iTicks)               /* what are we aiming for */
      {
        switch (pData->iSpeed)         /* honor speed modifier */
        {
          case mng_st_fast :
            {
              iWaitfor = (mng_uint32)(( 500 * pData->iFramedelay) / pData->iTicks);
              break;
            }
          case mng_st_slow :
            {
              iWaitfor = (mng_uint32)((3000 * pData->iFramedelay) / pData->iTicks);
              break;
            }
          case mng_st_slowest :
            {
              iWaitfor = (mng_uint32)((8000 * pData->iFramedelay) / pData->iTicks);
              break;
            }
          default :
            {
              iWaitfor = (mng_uint32)((1000 * pData->iFramedelay) / pData->iTicks);
            }
        }
      }
      else
      {
        if (pData->eImagetype == mng_it_mng)
          iWaitfor = 1000;
        else
          iWaitfor = 1;
      }

      if (iWaitfor > iRuninterval)     /* delay necessary ? */
        iInterval = iWaitfor - iRuninterval;
      else
        iInterval = 1;                 /* force app to process messageloop */

      if (pData->bRunning)             /* set the timer ? */
      {
        iRetcode = set_delay (pData, iInterval);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
    }

    if (pData->bRunning)               /* increase frametime in advance */
      pData->iFrametime = pData->iFrametime + iWaitfor;
                                       /* setup for next delay */
    pData->iFramedelay = pData->iNextdelay;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_INTERFRAME_DELAY, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

void set_display_routine (mng_datap pData)
{                                        /* actively running ? */
  if ((pData->bRunning) && (!pData->bFreezing))
  {
    switch (pData->iCanvasstyle)         /* determine display routine */
    {
      case MNG_CANVAS_RGB8    : { pData->fDisplayrow = (mng_fptr)display_rgb8;     break; }
      case MNG_CANVAS_RGBA8   : { pData->fDisplayrow = (mng_fptr)display_rgba8;    break; }
      case MNG_CANVAS_ARGB8   : { pData->fDisplayrow = (mng_fptr)display_argb8;    break; }
      case MNG_CANVAS_RGB8_A8 : { pData->fDisplayrow = (mng_fptr)display_rgb8_a8;  break; }
      case MNG_CANVAS_BGR8    : { pData->fDisplayrow = (mng_fptr)display_bgr8;     break; }
      case MNG_CANVAS_BGRA8   : { pData->fDisplayrow = (mng_fptr)display_bgra8;    break; }
      case MNG_CANVAS_BGRA8PM : { pData->fDisplayrow = (mng_fptr)display_bgra8_pm; break; }
      case MNG_CANVAS_ABGR8   : { pData->fDisplayrow = (mng_fptr)display_abgr8;    break; }
/*      case MNG_CANVAS_RGB16   : { pData->fDisplayrow = (mng_fptr)display_rgb16;    break; } */
/*      case MNG_CANVAS_RGBA16  : { pData->fDisplayrow = (mng_fptr)display_rgba16;   break; } */
/*      case MNG_CANVAS_ARGB16  : { pData->fDisplayrow = (mng_fptr)display_argb16;   break; } */
/*      case MNG_CANVAS_BGR16   : { pData->fDisplayrow = (mng_fptr)display_bgr16;    break; } */
/*      case MNG_CANVAS_BGRA16  : { pData->fDisplayrow = (mng_fptr)display_bgra16;   break; } */
/*      case MNG_CANVAS_ABGR16  : { pData->fDisplayrow = (mng_fptr)display_abgr16;   break; } */
/*      case MNG_CANVAS_INDEX8  : { pData->fDisplayrow = (mng_fptr)display_index8;   break; } */
/*      case MNG_CANVAS_INDEXA8 : { pData->fDisplayrow = (mng_fptr)display_indexa8;  break; } */
/*      case MNG_CANVAS_AINDEX8 : { pData->fDisplayrow = (mng_fptr)display_aindex8;  break; } */
/*      case MNG_CANVAS_GRAY8   : { pData->fDisplayrow = (mng_fptr)display_gray8;    break; } */
/*      case MNG_CANVAS_GRAY16  : { pData->fDisplayrow = (mng_fptr)display_gray16;   break; } */
/*      case MNG_CANVAS_GRAYA8  : { pData->fDisplayrow = (mng_fptr)display_graya8;   break; } */
/*      case MNG_CANVAS_GRAYA16 : { pData->fDisplayrow = (mng_fptr)display_graya16;  break; } */
/*      case MNG_CANVAS_AGRAY8  : { pData->fDisplayrow = (mng_fptr)display_agray8;   break; } */
/*      case MNG_CANVAS_AGRAY16 : { pData->fDisplayrow = (mng_fptr)display_agray16;  break; } */
/*      case MNG_CANVAS_DX15    : { pData->fDisplayrow = (mng_fptr)display_dx15;     break; } */
/*      case MNG_CANVAS_DX16    : { pData->fDisplayrow = (mng_fptr)display_dx16;     break; } */
    }
  }

  return;
}

/* ************************************************************************** */

mng_retcode load_bkgdlayer (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_LOAD_BKGDLAYER, MNG_LC_START)
#endif
                                       /* actively running ? */
  if ((pData->bRunning) && (!pData->bFreezing))
  {
    mng_int32   iY;
    mng_retcode iRetcode;              /* save values */
    mng_int32   iDestl      = pData->iDestl;
    mng_int32   iDestr      = pData->iDestr;
    mng_int32   iDestt      = pData->iDestt;
    mng_int32   iDestb      = pData->iDestb;
    mng_int32   iSourcel    = pData->iSourcel;
    mng_int32   iSourcer    = pData->iSourcer;
    mng_int32   iSourcet    = pData->iSourcet;
    mng_int32   iSourceb    = pData->iSourceb;
    mng_int8    iPass       = pData->iPass;
    mng_int32   iRow        = pData->iRow;
    mng_int32   iRowinc     = pData->iRowinc;
    mng_int32   iCol        = pData->iCol;
    mng_int32   iColinc     = pData->iColinc;
    mng_int32   iRowsamples = pData->iRowsamples;
    mng_int32   iRowsize    = pData->iRowsize;
    mng_bool    bIsRGBA16   = pData->bIsRGBA16;
    mng_bool    bIsOpaque   = pData->bIsOpaque;
    mng_fptr    fCorrectrow = pData->fCorrectrow;

    pData->iDestl   = 0;               /* determine clipping region */
    pData->iDestt   = 0;
    pData->iDestr   = pData->iWidth;
    pData->iDestb   = pData->iHeight;

    if (pData->bFrameclipping)         /* frame clipping specified ? */
    {
      pData->iDestl = MAX_COORD (pData->iDestl,  pData->iFrameclipl);
      pData->iDestt = MAX_COORD (pData->iDestt,  pData->iFrameclipt);
      pData->iDestr = MIN_COORD (pData->iDestr,  pData->iFrameclipr);
      pData->iDestb = MIN_COORD (pData->iDestb,  pData->iFrameclipb);
    }
                                       /* anything to clear ? */
    if ((pData->iDestr >= pData->iDestl) && (pData->iDestb >= pData->iDestt))
    {
      pData->iPass       = -1;         /* these are the object's dimensions now */
      pData->iRow        = 0;
      pData->iRowinc     = 1;
      pData->iCol        = 0;
      pData->iColinc     = 1;
      pData->iRowsamples = pData->iWidth;
      pData->iRowsize    = pData->iRowsamples << 2;
      pData->bIsRGBA16   = MNG_FALSE;    /* let's keep it simple ! */
      pData->bIsOpaque   = MNG_TRUE;

      pData->iSourcel    = 0;          /* source relative to destination */
      pData->iSourcer    = pData->iDestr - pData->iDestl;
      pData->iSourcet    = 0;
      pData->iSourceb    = pData->iDestb - pData->iDestt;

      set_display_routine (pData);     /* determine display routine */
                                       /* default restore using preset BG color */
      pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgcolor;

      if (((pData->eImagetype == mng_it_png) || (pData->eImagetype == mng_it_jng)) &&
          (pData->bUseBKGD))
      {                                /* prefer bKGD in PNG/JNG */
        mng_imagep pImage = (mng_imagep)pData->pCurrentobj;

        if (!pImage)
          pImage = (mng_imagep)pData->pObjzero;

        if (pImage->pImgbuf->bHasBKGD)
          pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bkgd;
      }

      if (pData->fGetbkgdline)         /* background-canvas-access callback set ? */
      {
        switch (pData->iBkgdstyle)
        {
          case MNG_CANVAS_RGB8    : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_rgb8;    break; }
          case MNG_CANVAS_BGR8    : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgr8;    break; }
  /*        case MNG_CANVAS_RGB16   : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_rgb16;   break; } */
  /*        case MNG_CANVAS_BGR16   : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgr16;   break; } */
  /*        case MNG_CANVAS_INDEX8  : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_index8;  break; } */
  /*        case MNG_CANVAS_GRAY8   : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_gray8;   break; } */
  /*        case MNG_CANVAS_GRAY16  : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_gray16;  break; } */
  /*        case MNG_CANVAS_DX15    : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_dx15;    break; } */
  /*        case MNG_CANVAS_DX16    : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_dx16;    break; } */
        }
      }

      if (pData->bHasBACK)
      {                                /* background image ? */
        if ((pData->iBACKmandatory & 0x02) && (pData->iBACKimageid))
          pData->fRestbkgdrow = (mng_fptr)restore_bkgd_backimage;
        else                           /* background color ? */
        if (pData->iBACKmandatory & 0x01)
          pData->fRestbkgdrow = (mng_fptr)restore_bkgd_backcolor;

      }

      pData->fCorrectrow = MNG_NULL;   /* default no color-correction */


      /* TODO: determine color correction; this is tricky;
         the BACK color is treated differently as the image;
         it probably requires a rewrite of the logic here... */


                                       /* get a temporary row-buffer */
      MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize)

      iY       = pData->iDestt;        /* this is where we start */
      iRetcode = MNG_NOERROR;          /* so far, so good */

      while ((!iRetcode) && (iY < pData->iDestb))
      {                                /* restore a background row */
        iRetcode = ((mng_restbkgdrow)pData->fRestbkgdrow) (pData);
                                       /* color correction ? */
        if ((!iRetcode) && (pData->fCorrectrow))
          iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData);

        if (!iRetcode)                 /* so... display it */
          iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData);

        if (!iRetcode)
          iRetcode = next_row (pData); /* adjust variables for next row */

        iY++;                          /* and next line */
      }
                                       /* drop the temporary row-buffer */
      MNG_FREE (pData, pData->pRGBArow, pData->iRowsize)

      if (iRetcode)                    /* on error bail out */
        return iRetcode;

    }

    pData->iDestl      = iDestl;       /* restore values */
    pData->iDestr      = iDestr;
    pData->iDestt      = iDestt;
    pData->iDestb      = iDestb;
    pData->iSourcel    = iSourcel;
    pData->iSourcer    = iSourcer;
    pData->iSourcet    = iSourcet;
    pData->iSourceb    = iSourceb;
    pData->iPass       = iPass;
    pData->iRow        = iRow;
    pData->iRowinc     = iRowinc;
    pData->iCol        = iCol;
    pData->iColinc     = iColinc;
    pData->iRowsamples = iRowsamples;
    pData->iRowsize    = iRowsize;
    pData->bIsRGBA16   = bIsRGBA16;
    pData->bIsOpaque   = bIsOpaque;
    pData->fCorrectrow = fCorrectrow;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_LOAD_BKGDLAYER, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode clear_canvas (mng_datap pData)
{
  mng_int32   iY;
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_CLEAR_CANVAS, MNG_LC_START)
#endif

  pData->iDestl      = 0;              /* clipping region is full canvas! */
  pData->iDestt      = 0;
  pData->iDestr      = pData->iWidth;
  pData->iDestb      = pData->iHeight;

  pData->iSourcel    = 0;              /* source is same as destination */
  pData->iSourcer    = pData->iWidth;
  pData->iSourcet    = 0;
  pData->iSourceb    = pData->iHeight;

  pData->iPass       = -1;             /* these are the object's dimensions now */
  pData->iRow        = 0;
  pData->iRowinc     = 1;
  pData->iCol        = 0;
  pData->iColinc     = 1;
  pData->iRowsamples = pData->iWidth;
  pData->iRowsize    = pData->iRowsamples << 2;
  pData->bIsRGBA16   = MNG_FALSE;      /* let's keep it simple ! */
  pData->bIsOpaque   = MNG_TRUE;

  set_display_routine (pData);         /* determine display routine */
                                       /* get a temporary row-buffer */
                                       /* it's transparent black by default!! */
  MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize)

  iY       = pData->iDestt;            /* this is where we start */
  iRetcode = MNG_NOERROR;              /* so far, so good */

  while ((!iRetcode) && (iY < pData->iDestb))
  {                                    /* clear a row then */
    iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData);

    if (!iRetcode)
      iRetcode = next_row (pData);     /* adjust variables for next row */

    iY++;                              /* and next line */
  }
                                       /* drop the temporary row-buffer */
  MNG_FREE (pData, pData->pRGBArow, pData->iRowsize)

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_CLEAR_CANVAS, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode next_frame (mng_datap  pData,
                        mng_uint8  iFramemode,
                        mng_uint8  iChangedelay,
                        mng_uint32 iDelay,
                        mng_uint8  iChangetimeout,
                        mng_uint32 iTimeout,
                        mng_uint8  iChangeclipping,
                        mng_uint8  iCliptype,
                        mng_int32  iClipl,
                        mng_int32  iClipr,
                        mng_int32  iClipt,
                        mng_int32  iClipb)
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_NEXT_FRAME, MNG_LC_START)
#endif

  if (!pData->iBreakpoint)             /* no previous break here ? */
  {
    mng_uint8 iOldmode = pData->iFramemode;
                                       /* interframe delay required ? */
    if ((iOldmode == 2) || (iOldmode == 4))
    {
/* changed here because FRAM 1/3 will delay themselves before each image */
      if ((pData->iFrameseq) && (iFramemode != 1) && (iFramemode != 3))
        iRetcode = interframe_delay (pData);
      else
        pData->iFramedelay = pData->iNextdelay;
    }
    else
    {                                  /* delay before inserting background layer? */
      if ((pData->bFramedone) && (iFramemode == 4))
        iRetcode = interframe_delay (pData);
    }

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
                                       /* now we'll assume we're in the next frame! */
    if (iFramemode)                    /* save the new framing mode ? */
    {
      pData->iFRAMmode  = iFramemode;
      pData->iFramemode = iFramemode;
    }
    else                               /* reload default */
      pData->iFramemode = pData->iFRAMmode;

    if (iChangedelay)                  /* delay changed ? */
    {
      pData->iNextdelay = iDelay;      /* for *after* next subframe */

      if ((iOldmode == 2) || (iOldmode == 4))
/*        pData->iFramedelay = iDelay; */
        pData->iFramedelay = pData->iFRAMdelay;

      if (iChangedelay == 2)           /* also overall ? */
        pData->iFRAMdelay = iDelay;
    }
    else
    {                                  /* reload default */
      pData->iNextdelay = pData->iFRAMdelay;

/*      if ((iOldmode == 2) || (iOldmode == 4))
        pData->iFramedelay = pData->iNextdelay; */
    }

    if (iChangetimeout)                /* timeout changed ? */
    {                                  /* for next subframe */
      pData->iFrametimeout = iTimeout;

      if ((iChangetimeout == 2) ||     /* also overall ? */
          (iChangetimeout == 4) ||
          (iChangetimeout == 6) ||
          (iChangetimeout == 8))
        pData->iFRAMtimeout = iTimeout;
    }
    else                               /* reload default */
      pData->iFrametimeout = pData->iFRAMtimeout;

    if (iChangeclipping)               /* clipping changed ? */
    {
      pData->bFrameclipping = MNG_TRUE;

      if (!iCliptype)                  /* absolute ? */
      {
        pData->iFrameclipl = iClipl;
        pData->iFrameclipr = iClipr;
        pData->iFrameclipt = iClipt;
        pData->iFrameclipb = iClipb;
      }
      else                             /* relative */
      {
        pData->iFrameclipl = pData->iFrameclipl + iClipl;
        pData->iFrameclipr = pData->iFrameclipr + iClipr;
        pData->iFrameclipt = pData->iFrameclipt + iClipt;
        pData->iFrameclipb = pData->iFrameclipb + iClipb;
      }

      if (iChangeclipping == 2)        /* also overall ? */
      {
        pData->bFRAMclipping = MNG_TRUE;

        if (!iCliptype)                /* absolute ? */
        {
          pData->iFRAMclipl = iClipl;
          pData->iFRAMclipr = iClipr;
          pData->iFRAMclipt = iClipt;
          pData->iFRAMclipb = iClipb;
        }
        else                           /* relative */
        {
          pData->iFRAMclipl = pData->iFRAMclipl + iClipl;
          pData->iFRAMclipr = pData->iFRAMclipr + iClipr;
          pData->iFRAMclipt = pData->iFRAMclipt + iClipt;
          pData->iFRAMclipb = pData->iFRAMclipb + iClipb;
        }
      }
    }
    else
    {                                  /* reload defaults */
      pData->bFrameclipping = pData->bFRAMclipping;
      pData->iFrameclipl    = pData->iFRAMclipl;
      pData->iFrameclipr    = pData->iFRAMclipr;
      pData->iFrameclipt    = pData->iFRAMclipt;
      pData->iFrameclipb    = pData->iFRAMclipb;
    }
  }

  if (!pData->bTimerset)               /* timer still off ? */
  {
    if ((pData->iFramemode == 4) ||    /* insert background layer after a new frame */
        (!pData->iLayerseq))           /* and certainly before the very first layer */
      iRetcode = load_bkgdlayer (pData);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

    if ((pData->bDisplaying) && (pData->bRunning))
    {
      pData->iFrameseq++;              /* count the frame ! */
      pData->bFramedone = MNG_TRUE;    /* and indicate we've done one */
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_NEXT_FRAME, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode next_layer (mng_datap pData)
{
  mng_imagep  pImage;
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_NEXT_LAYER, MNG_LC_START)
#endif

  if (!pData->iBreakpoint)             /* no previous break here ? */
  {                                    /* interframe delay required ? */
    if ((pData->eImagetype == mng_it_mng) && (pData->iLayerseq) &&
        ((pData->iFramemode == 1) || (pData->iFramemode == 3)))
      iRetcode = interframe_delay (pData);
    else
      pData->iFramedelay = pData->iNextdelay;

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
  }

  if (!pData->bTimerset)               /* timer still off ? */
  {
    if (!pData->iLayerseq)             /* restore background for the very first layer ? */
    {                                  /* wait till IDAT/JDAT for PNGs & JNGs !!! */
      if ((pData->eImagetype == mng_it_png) || (pData->eImagetype == mng_it_jng))
        pData->bRestorebkgd = MNG_TRUE;
      else
      {                                /* for MNG we do it right away */
        iRetcode = load_bkgdlayer (pData);

        if (pData->bRunning)
          pData->iLayerseq++;          /* and it counts as a layer then ! */
      }
    }
    else
    if (pData->iFramemode == 3)        /* restore background for each layer ? */
      iRetcode = load_bkgdlayer (pData);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

    if (pData->bHasDHDR)               /* processing a delta-image ? */
      pImage = (mng_imagep)pData->pDeltaImage;
    else
      pImage = (mng_imagep)pData->pCurrentobj;

    if (!pImage)                       /* not an active object ? */
      pImage = (mng_imagep)pData->pObjzero;
                                       /* determine display rectangle */
    pData->iDestl   = MAX_COORD ((mng_int32)0,   pImage->iPosx);
    pData->iDestt   = MAX_COORD ((mng_int32)0,   pImage->iPosy);
                                       /* is it a valid buffer ? */
    if ((pImage->pImgbuf->iWidth) && (pImage->pImgbuf->iHeight))
    {
      pData->iDestr = MIN_COORD ((mng_int32)pData->iWidth,
                                 pImage->iPosx + (mng_int32)pImage->pImgbuf->iWidth );
      pData->iDestb = MIN_COORD ((mng_int32)pData->iHeight,
                                 pImage->iPosy + (mng_int32)pImage->pImgbuf->iHeight);
    }
    else                               /* it's a single image ! */
    {
      pData->iDestr = MIN_COORD ((mng_int32)pData->iWidth,
                                 (mng_int32)pData->iDatawidth );
      pData->iDestb = MIN_COORD ((mng_int32)pData->iHeight,
                                 (mng_int32)pData->iDataheight);
    }

    if (pData->bFrameclipping)         /* frame clipping specified ? */
    {
      pData->iDestl = MAX_COORD (pData->iDestl,  pData->iFrameclipl);
      pData->iDestt = MAX_COORD (pData->iDestt,  pData->iFrameclipt);
      pData->iDestr = MIN_COORD (pData->iDestr,  pData->iFrameclipr);
      pData->iDestb = MIN_COORD (pData->iDestb,  pData->iFrameclipb);
    }

    if (pImage->bClipped)              /* is the image clipped itself ? */
    {
      pData->iDestl = MAX_COORD (pData->iDestl,  pImage->iClipl);
      pData->iDestt = MAX_COORD (pData->iDestt,  pImage->iClipt);
      pData->iDestr = MIN_COORD (pData->iDestr,  pImage->iClipr);
      pData->iDestb = MIN_COORD (pData->iDestb,  pImage->iClipb);
    }
                                       /* determine source starting point */
    pData->iSourcel = MAX_COORD ((mng_int32)0,   pData->iDestl - pImage->iPosx);
    pData->iSourcet = MAX_COORD ((mng_int32)0,   pData->iDestt - pImage->iPosy);

    if ((pImage->pImgbuf->iWidth) && (pImage->pImgbuf->iHeight))
    {                                  /* and maximum size  */
      pData->iSourcer = MIN_COORD ((mng_int32)pImage->pImgbuf->iWidth,
                                   pData->iSourcel + pData->iDestr - pData->iDestl);
      pData->iSourceb = MIN_COORD ((mng_int32)pImage->pImgbuf->iHeight,
                                   pData->iSourcet + pData->iDestb - pData->iDestt);
    }
    else                               /* it's a single image ! */
    {
      pData->iSourcer = pData->iSourcel + pData->iDestr - pData->iDestl;
      pData->iSourceb = pData->iSourcet + pData->iDestb - pData->iDestt;
    }

    if (pData->bRunning)
      pData->iLayerseq++;              /* count the layer ! */
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_NEXT_LAYER, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode display_image (mng_datap  pData,
                           mng_imagep pImage,
                           mng_bool   bLayeradvanced)
{
  mng_retcode iRetcode;
  
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_DISPLAY_IMAGE, MNG_LC_START)
#endif
                                       /* actively running ? */
  if ((pData->bRunning) && (!pData->bFreezing))
  {
    if ( (!pData->iBreakpoint) &&      /* needs magnification ? */
         ( (pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY) ) )
    {
      iRetcode = magnify_imageobject (pData, pImage);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
  }

  pData->pRetrieveobj = pImage;        /* so retrieve-row and color-correction can find it */

  if (!bLayeradvanced)                 /* need to advance the layer ? */
  {
    mng_imagep pSave    = pData->pCurrentobj;
    pData->pCurrentobj  = pImage;
    next_layer (pData);                /* advance to next layer */
    pData->pCurrentobj  = pSave;
  }
                                       /* need to restore the background ? */
  if ((!pData->bTimerset) && (pData->bRestorebkgd))
  {
    mng_imagep pSave    = pData->pCurrentobj;
    pData->pCurrentobj  = pImage;
    pData->bRestorebkgd = MNG_FALSE;
    iRetcode            = load_bkgdlayer (pData);
    pData->pCurrentobj  = pSave;

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

    if (pData->bRunning)
      pData->iLayerseq++;              /* and it counts as a layer then ! */
  }
                                       /* actively running ? */
  if ((pData->bRunning) && (!pData->bFreezing))
  {
    if (!pData->bTimerset)             /* all systems still go ? */
    {
      pData->iBreakpoint = 0;          /* let's make absolutely sure... */
                                       /* anything to display ? */
      if ((pData->iDestr >= pData->iDestl) && (pData->iDestb >= pData->iDestt))
      {
        mng_int32 iY;

        set_display_routine (pData);   /* determine display routine */
                                       /* and image-buffer retrieval routine */
        switch (pImage->pImgbuf->iColortype)
        {
          case  0 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_g16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_g8;

                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }

          case  2 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_rgb16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_rgb8;

                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }


          case  3 : { pData->fRetrieverow   = (mng_fptr)retrieve_idx8;
                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }


          case  4 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_ga16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_ga8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }


          case  6 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_rgba16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_rgba8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }

          case  8 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_g16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_g8;

                      pData->bIsOpaque      = MNG_TRUE;
                      break;
                    }

          case 10 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_rgb16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_rgb8;

                      pData->bIsOpaque      = MNG_TRUE;
                      break;
                    }


          case 12 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_ga16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_ga8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }


          case 14 : { if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)retrieve_rgba16;
                      else
                        pData->fRetrieverow = (mng_fptr)retrieve_rgba8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }

        }

        pData->iPass       = -1;       /* these are the object's dimensions now */
        pData->iRow        = pData->iSourcet;
        pData->iRowinc     = 1;
        pData->iCol        = 0;
        pData->iColinc     = 1;
        pData->iRowsamples = pImage->pImgbuf->iWidth;
        pData->iRowsize    = pData->iRowsamples << 2;
        pData->bIsRGBA16   = MNG_FALSE;
                                       /* adjust for 16-bit object ? */
        if (pImage->pImgbuf->iBitdepth > 8)
        {
          pData->bIsRGBA16 = MNG_TRUE;
          pData->iRowsize  = pData->iRowsamples << 3;
        }

        pData->fCorrectrow = MNG_NULL; /* default no color-correction */

#ifdef MNG_NO_CMS
        iRetcode = MNG_NOERROR;
#else
#if defined(MNG_FULL_CMS)              /* determine color-management routine */
        iRetcode = init_full_cms_object   (pData);
#elif defined(MNG_GAMMA_ONLY)
        iRetcode = init_gamma_only_object (pData);
#elif defined(MNG_APP_CMS)
        iRetcode = init_app_cms_object    (pData);
#endif
        if (iRetcode)                  /* on error bail out */
          return iRetcode;
#endif /* MNG_NO_CMS */
                                       /* get a temporary row-buffer */
        MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize)

        iY = pData->iSourcet;          /* this is where we start */

        while ((!iRetcode) && (iY < pData->iSourceb))
        {                              /* get a row */
          iRetcode = ((mng_retrieverow)pData->fRetrieverow) (pData);
                                       /* color correction ? */
          if ((!iRetcode) && (pData->fCorrectrow))
            iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData);

          if (!iRetcode)               /* so... display it */
            iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData);

          if (!iRetcode)               /* adjust variables for next row */
            iRetcode = next_row (pData);

          iY++;                        /* and next line */
        }
                                       /* drop the temporary row-buffer */
        MNG_FREE (pData, pData->pRGBArow, pData->iRowsize)

        if (iRetcode)                  /* on error bail out */
          return iRetcode;

#if defined(MNG_INCLUDE_LCMS)          /* cleanup cms stuff */
        iRetcode = mng_clear_cms (pData);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
#endif
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_DISPLAY_IMAGE, MNG_LC_END)
#endif

  return MNG_NOERROR;                  /* whehehe, this is good ! */
}

/* ************************************************************************** */

mng_retcode execute_delta_image (mng_datap  pData,
                                 mng_imagep pTarget,
                                 mng_imagep pDelta)
{
  mng_imagedatap pBuftarget = pTarget->pImgbuf;
  mng_imagedatap pBufdelta  = pDelta->pImgbuf;
  mng_uint32     iY;
  mng_retcode    iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_EXECUTE_DELTA_IMAGE, MNG_LC_START)
#endif
                                       /* actively running ? */
  if ((pData->bRunning) && (!pData->bFreezing))
  {
    if (pBufdelta->bHasPLTE)           /* palette in delta ? */
    {
      mng_uint32 iX;
                                       /* new palette larger than old one ? */
      if ((!pBuftarget->bHasPLTE) || (pBuftarget->iPLTEcount < pBufdelta->iPLTEcount))
        pBuftarget->iPLTEcount = pBufdelta->iPLTEcount;
                                       /* it's definitely got a PLTE now */
      pBuftarget->bHasPLTE = MNG_TRUE;

      for (iX = 0; iX < pBufdelta->iPLTEcount; iX++)
      {
        pBuftarget->aPLTEentries[iX].iRed   = pBufdelta->aPLTEentries[iX].iRed;
        pBuftarget->aPLTEentries[iX].iGreen = pBufdelta->aPLTEentries[iX].iGreen;
        pBuftarget->aPLTEentries[iX].iBlue  = pBufdelta->aPLTEentries[iX].iBlue;
      }
    }

    if (pBufdelta->bHasTRNS)           /* cheap transparency in delta ? */
    {
      switch (pData->iColortype)       /* drop it into the target */
      {
        case 0: {                      /* gray */
                  pBuftarget->iTRNSgray  = pBufdelta->iTRNSgray;
                  pBuftarget->iTRNSred   = 0;
                  pBuftarget->iTRNSgreen = 0;
                  pBuftarget->iTRNSblue  = 0;
                  pBuftarget->iTRNScount = 0;
                  break;
                }
        case 2: {                      /* rgb */
                  pBuftarget->iTRNSgray  = 0;
                  pBuftarget->iTRNSred   = pBufdelta->iTRNSred;
                  pBuftarget->iTRNSgreen = pBufdelta->iTRNSgreen;
                  pBuftarget->iTRNSblue  = pBufdelta->iTRNSblue;
                  pBuftarget->iTRNScount = 0;
                  break;
                }
        case 3: {                      /* indexed */
                  pBuftarget->iTRNSgray  = 0;
                  pBuftarget->iTRNSred   = 0;
                  pBuftarget->iTRNSgreen = 0;
                  pBuftarget->iTRNSblue  = 0;
                                       /* existing range smaller than new one ? */
                  if ((!pBuftarget->bHasTRNS) || (pBuftarget->iTRNScount < pBufdelta->iTRNScount))
                    pBuftarget->iTRNScount = pBufdelta->iTRNScount;

                  MNG_COPY (pBuftarget->aTRNSentries, pBufdelta->aTRNSentries, pBufdelta->iTRNScount)
                  break;
                }
      }

      pBuftarget->bHasTRNS = MNG_TRUE; /* tell it it's got a tRNS now */
    }

    if (pBufdelta->bHasBKGD)           /* bkgd in source ? */
    {                                  /* drop it onto the target */
      pBuftarget->bHasBKGD   = MNG_TRUE;
      pBuftarget->iBKGDindex = pBufdelta->iBKGDindex;
      pBuftarget->iBKGDgray  = pBufdelta->iBKGDgray;
      pBuftarget->iBKGDred   = pBufdelta->iBKGDred;
      pBuftarget->iBKGDgreen = pBufdelta->iBKGDgreen;
      pBuftarget->iBKGDblue  = pBufdelta->iBKGDblue;
    }

    if (pBufdelta->bHasGAMA)           /* gamma in source ? */
    {
      pBuftarget->bHasGAMA = MNG_TRUE; /* drop it onto the target */
      pBuftarget->iGamma   = pBufdelta->iGamma;
    }

    if (pBufdelta->bHasCHRM)           /* chroma in delta ? */
    {                                  /* drop it onto the target */
      pBuftarget->bHasCHRM       = MNG_TRUE;
      pBuftarget->iWhitepointx   = pBufdelta->iWhitepointx;
      pBuftarget->iWhitepointy   = pBufdelta->iWhitepointy;
      pBuftarget->iPrimaryredx   = pBufdelta->iPrimaryredx;
      pBuftarget->iPrimaryredy   = pBufdelta->iPrimaryredy;
      pBuftarget->iPrimarygreenx = pBufdelta->iPrimarygreenx;
      pBuftarget->iPrimarygreeny = pBufdelta->iPrimarygreeny;
      pBuftarget->iPrimarybluex  = pBufdelta->iPrimarybluex;
      pBuftarget->iPrimarybluey  = pBufdelta->iPrimarybluey;
    }

    if (pBufdelta->bHasSRGB)           /* sRGB in delta ? */
    {                                  /* drop it onto the target */
      pBuftarget->bHasSRGB         = MNG_TRUE;
      pBuftarget->iRenderingintent = pBufdelta->iRenderingintent;
    }

    if (pBufdelta->bHasICCP)           /* ICC profile in delta ? */
    {
      pBuftarget->bHasICCP = MNG_TRUE; /* drop it onto the target */

      if (pBuftarget->pProfile)        /* profile existed ? */
        MNG_FREEX (pData, pBuftarget->pProfile, pBuftarget->iProfilesize)
                                       /* allocate a buffer & copy it */
      MNG_ALLOC (pData, pBuftarget->pProfile, pBufdelta->iProfilesize)
      MNG_COPY  (pBuftarget->pProfile, pBufdelta->pProfile, pBufdelta->iProfilesize)
                                       /* store it's length as well */
      pBuftarget->iProfilesize = pBufdelta->iProfilesize;
    }
                                       /* need to execute delta pixels ? */
    if ((!pData->bDeltaimmediate) && (pData->iDeltatype != MNG_DELTATYPE_NOCHANGE))
    {
      pData->fScalerow = MNG_NULL;     /* not needed by default */

      switch (pBuftarget->iBitdepth)   /* determine scaling routine */
      {


      }

      pData->fDeltarow = MNG_NULL;     /* let's assume there's nothing to do */

      switch (pBuftarget->iColortype)  /* determine delta processing routine */
      {
        case  0 : ;
        case  8 : {                     /* gray */
                    if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE          ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3) ||
                          (pBufdelta->iColortype == 8))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  1 : { pData->fDeltarow = (mng_fptr)delta_g1_g1;   break; }
                          case  2 : { pData->fDeltarow = (mng_fptr)delta_g2_g2;   break; }
                          case  4 : { pData->fDeltarow = (mng_fptr)delta_g4_g4;   break; }
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_g8_g8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_g16_g16; break; }
                        }
                      }
                    }

                    break;
                  }

        case  2 : ;
        case 10 : {                     /* rgb */
                    if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE          ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 2) || (pBufdelta->iColortype == 10))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_rgb8_rgb8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_rgb16_rgb16; break; }
                        }
                      }
                    }

                    break;
                  }

        case  3 : {                     /* indexed; abuse gray routines */
                    if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE          ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  1 : { pData->fDeltarow = (mng_fptr)delta_g1_g1; break; }
                          case  2 : { pData->fDeltarow = (mng_fptr)delta_g2_g2; break; }
                          case  4 : { pData->fDeltarow = (mng_fptr)delta_g4_g4; break; }
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_g8_g8; break; }
                        }
                      }
                    }

                    break;
                  }

        case  4 : ;
        case 12 : {                     /* gray + alpha */
                    if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE          ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 4) || (pBufdelta->iColortype == 12))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_ga8_ga8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_ga16; break; }
                        }
                      }
                    }
                    else
                    if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3) ||
                          (pBufdelta->iColortype == 8))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_ga8_g8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_g16; break; }
                        }
                      }
                    }
                    else
                    if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_ga8_a8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_a16; break; }
                        }
                      }
                    }

                    break;
                  }

        case  6 : ;
        case 14 : {                     /* rgb + alpha */
                    if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE          ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 6) || (pBufdelta->iColortype == 14))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_rgba8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_rgba16; break; }
                        }
                      }
                    }
                    else
                    if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 2) || (pBufdelta->iColortype == 10))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_rgb8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_rgb16; break; }
                        }
                      }
                    }
                    else
                    if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
                        (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
                    {
                      if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3))
                      {
                        switch (pBuftarget->iBitdepth)
                        {
                          case  8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_a8;   break; }
                          case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_a16; break; }
                        }
                      }
                    }

                    break;
                  }

      }

      if (pData->fDeltarow)            /* do we need to take action ? */
      {
        pData->iPass        = -1;      /* setup row dimensions and stuff */
        pData->iRow         = pData->iDeltaBlocky;
        pData->iRowinc      = 1;
        pData->iCol         = pData->iDeltaBlockx;
        pData->iColinc      = 1;
        pData->iRowsamples  = pBufdelta->iWidth;
        pData->iRowsize     = pBuftarget->iRowsize;
                                       /* indicate where to retrieve & where to store */
        pData->pRetrieveobj = (mng_objectp)pDelta;
        pData->pStoreobj    = (mng_objectp)pTarget;

        if (pData->pRGBArow)           /* prevent duplicate allocation! */
          MNG_FREE (pData, pData->pRGBArow, (pData->iDatawidth << 3))
                                       /* get a temporary row-buffer */
        MNG_ALLOC (pData, pData->pRGBArow, pBufdelta->iRowsize)

        iY       = 0;                  /* this is where we start */
        iRetcode = MNG_NOERROR;        /* still oke for now */

        while ((!iRetcode) && (iY < pBufdelta->iHeight))
        {                              /* get a row */
          mng_uint8p pWork = pBufdelta->pImgdata + (iY * pBufdelta->iRowsize);

          MNG_COPY (pData->pRGBArow, pWork, pBufdelta->iRowsize);

          if (pData->fScalerow)        /* scale it (if necessary) */
            iRetcode = ((mng_scalerow)pData->fScalerow) (pData);

          if (!iRetcode)               /* and... execute it */
            iRetcode = ((mng_deltarow)pData->fDeltarow) (pData);

          if (!iRetcode)               /* adjust variables for next row */
            iRetcode = next_row (pData);

          iY++;                        /* and next line */
        }
                                       /* drop the temporary row-buffer */
        MNG_FREE (pData, pData->pRGBArow, pBufdelta->iRowsize)

        if (iRetcode)                  /* on error bail out */
          return iRetcode;

      }
      else
        MNG_ERROR (pData, MNG_INVALIDDELTA)

    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_EXECUTE_DELTA_IMAGE, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode save_state (mng_datap pData)
{
  mng_savedatap pSave;
  mng_imagep    pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_SAVE_STATE, MNG_LC_START)
#endif

  if (pData->pSavedata)                /* sanity check */
    MNG_ERROR (pData, MNG_INTERNALERROR)
                                       /* get a buffer for saving */
  MNG_ALLOC (pData, pData->pSavedata, sizeof (mng_savedata))

  pSave = pData->pSavedata;            /* address it more directly */
                                       /* and copy global data from the main struct */
#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE)
  pSave->bHasglobalPLTE       = pData->bHasglobalPLTE;
  pSave->bHasglobalTRNS       = pData->bHasglobalTRNS;
  pSave->bHasglobalGAMA       = pData->bHasglobalGAMA;
  pSave->bHasglobalCHRM       = pData->bHasglobalCHRM;
  pSave->bHasglobalSRGB       = pData->bHasglobalSRGB;
  pSave->bHasglobalICCP       = pData->bHasglobalICCP;
  pSave->bHasglobalBKGD       = pData->bHasglobalBKGD;
#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */

  pSave->iBACKred             = pData->iBACKred;
  pSave->iBACKgreen           = pData->iBACKgreen;
  pSave->iBACKblue            = pData->iBACKblue;
  pSave->iBACKmandatory       = pData->iBACKmandatory;
  pSave->iBACKimageid         = pData->iBACKimageid;
  pSave->iBACKtile            = pData->iBACKtile;

  pSave->iFRAMmode            = pData->iFRAMmode;
  pSave->iFRAMdelay           = pData->iFRAMdelay;
  pSave->iFRAMtimeout         = pData->iFRAMtimeout;
  pSave->bFRAMclipping        = pData->bFRAMclipping;
  pSave->iFRAMclipl           = pData->iFRAMclipl;
  pSave->iFRAMclipr           = pData->iFRAMclipr;
  pSave->iFRAMclipt           = pData->iFRAMclipt;
  pSave->iFRAMclipb           = pData->iFRAMclipb;

  pSave->iGlobalPLTEcount     = pData->iGlobalPLTEcount;

  MNG_COPY (pSave->aGlobalPLTEentries, pData->aGlobalPLTEentries, sizeof (mng_rgbpaltab))

  pSave->iGlobalTRNSrawlen    = pData->iGlobalTRNSrawlen;
  MNG_COPY (pSave->aGlobalTRNSrawdata, pData->aGlobalTRNSrawdata, 256)

  pSave->iGlobalGamma         = pData->iGlobalGamma;

  pSave->iGlobalWhitepointx   = pData->iGlobalWhitepointx;
  pSave->iGlobalWhitepointy   = pData->iGlobalWhitepointy;
  pSave->iGlobalPrimaryredx   = pData->iGlobalPrimaryredx;
  pSave->iGlobalPrimaryredy   = pData->iGlobalPrimaryredy;
  pSave->iGlobalPrimarygreenx = pData->iGlobalPrimarygreenx;
  pSave->iGlobalPrimarygreeny = pData->iGlobalPrimarygreeny;
  pSave->iGlobalPrimarybluex  = pData->iGlobalPrimarybluex;
  pSave->iGlobalPrimarybluey  = pData->iGlobalPrimarybluey;

  pSave->iGlobalRendintent    = pData->iGlobalRendintent;

  pSave->iGlobalProfilesize   = pData->iGlobalProfilesize;

  if (pSave->iGlobalProfilesize)       /* has a profile ? */
  {                                    /* then copy that ! */
    MNG_ALLOC (pData, pSave->pGlobalProfile, pSave->iGlobalProfilesize)
    MNG_COPY (pSave->pGlobalProfile, pData->pGlobalProfile, pSave->iGlobalProfilesize)
  }

  pSave->iGlobalBKGDred       = pData->iGlobalBKGDred;
  pSave->iGlobalBKGDgreen     = pData->iGlobalBKGDgreen;
  pSave->iGlobalBKGDblue      = pData->iGlobalBKGDblue;

                                       /* freeze current image objects */
  pImage = (mng_imagep)pData->pFirstimgobj;

  while (pImage)
  {                                    /* freeze the object AND it's buffer */
    pImage->bFrozen          = MNG_TRUE;
    pImage->pImgbuf->bFrozen = MNG_TRUE;
                                       /* neeeext */
    pImage = (mng_imagep)pImage->sHeader.pNext;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_SAVE_STATE, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode mng_reset_objzero (mng_datap pData)
{
  mng_imagep  pImage   = (mng_imagep)pData->pObjzero;
  mng_retcode iRetcode = reset_object_details (pData, pImage, 0, 0, 0,
                                               0, 0, 0, 0, MNG_TRUE);

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

  pImage->bVisible             = MNG_TRUE;
  pImage->bViewable            = MNG_TRUE;
  pImage->iPosx                = 0;
  pImage->iPosy                = 0;
  pImage->bClipped             = MNG_FALSE;
  pImage->iClipl               = 0;
  pImage->iClipr               = 0;
  pImage->iClipt               = 0;
  pImage->iClipb               = 0;
  pImage->iMAGN_MethodX        = 0;
  pImage->iMAGN_MethodY        = 0;
  pImage->iMAGN_MX             = 0;
  pImage->iMAGN_MY             = 0;
  pImage->iMAGN_ML             = 0;
  pImage->iMAGN_MR             = 0;
  pImage->iMAGN_MT             = 0;
  pImage->iMAGN_MB             = 0;

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode restore_state (mng_datap pData)
{
  mng_savedatap pSave;
  mng_imagep    pImage;
  mng_retcode   iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_RESTORE_STATE, MNG_LC_START)
#endif
                                       /* restore object 0 status !!! */
  iRetcode = mng_reset_objzero (pData);

  if (iRetcode)                        /* on error bail out */
    return iRetcode;
                                       /* fresh cycle; fake no frames done yet */
  pData->bFramedone             = MNG_FALSE;

  if (pData->pSavedata)                /* do we have a saved state ? */
  {
    pSave = pData->pSavedata;          /* address it more directly */
                                       /* and copy it back to the main struct */
#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE)
    pData->bHasglobalPLTE       = pSave->bHasglobalPLTE;
    pData->bHasglobalTRNS       = pSave->bHasglobalTRNS;
    pData->bHasglobalGAMA       = pSave->bHasglobalGAMA;
    pData->bHasglobalCHRM       = pSave->bHasglobalCHRM;
    pData->bHasglobalSRGB       = pSave->bHasglobalSRGB;
    pData->bHasglobalICCP       = pSave->bHasglobalICCP;
    pData->bHasglobalBKGD       = pSave->bHasglobalBKGD;
#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */

    pData->iBACKred             = pSave->iBACKred;
    pData->iBACKgreen           = pSave->iBACKgreen;
    pData->iBACKblue            = pSave->iBACKblue;
    pData->iBACKmandatory       = pSave->iBACKmandatory;
    pData->iBACKimageid         = pSave->iBACKimageid;
    pData->iBACKtile            = pSave->iBACKtile;

    pData->iFRAMmode            = pSave->iFRAMmode;
    pData->iFRAMdelay           = pSave->iFRAMdelay;
    pData->iFRAMtimeout         = pSave->iFRAMtimeout;
    pData->bFRAMclipping        = pSave->bFRAMclipping;
    pData->iFRAMclipl           = pSave->iFRAMclipl;
    pData->iFRAMclipr           = pSave->iFRAMclipr;
    pData->iFRAMclipt           = pSave->iFRAMclipt;
    pData->iFRAMclipb           = pSave->iFRAMclipb;
                                       /* also the next subframe parms */
    pData->iFramemode           = pSave->iFRAMmode;
    pData->iFramedelay          = pSave->iFRAMdelay;
    pData->iFrametimeout        = pSave->iFRAMtimeout;
    pData->bFrameclipping       = pSave->bFRAMclipping;
    pData->iFrameclipl          = pSave->iFRAMclipl;
    pData->iFrameclipr          = pSave->iFRAMclipr;
    pData->iFrameclipt          = pSave->iFRAMclipt;
    pData->iFrameclipb          = pSave->iFRAMclipb;

    pData->iNextdelay           = pSave->iFRAMdelay;

    pData->iGlobalPLTEcount     = pSave->iGlobalPLTEcount;
    MNG_COPY (pData->aGlobalPLTEentries, pSave->aGlobalPLTEentries, sizeof (mng_rgbpaltab))

    pData->iGlobalTRNSrawlen    = pSave->iGlobalTRNSrawlen;
    MNG_COPY (pData->aGlobalTRNSrawdata, pSave->aGlobalTRNSrawdata, 256)

    pData->iGlobalGamma         = pSave->iGlobalGamma;

    pData->iGlobalWhitepointx   = pSave->iGlobalWhitepointx;
    pData->iGlobalWhitepointy   = pSave->iGlobalWhitepointy;
    pData->iGlobalPrimaryredx   = pSave->iGlobalPrimaryredx;
    pData->iGlobalPrimaryredy   = pSave->iGlobalPrimaryredy;
    pData->iGlobalPrimarygreenx = pSave->iGlobalPrimarygreenx;
    pData->iGlobalPrimarygreeny = pSave->iGlobalPrimarygreeny;
    pData->iGlobalPrimarybluex  = pSave->iGlobalPrimarybluex;
    pData->iGlobalPrimarybluey  = pSave->iGlobalPrimarybluey;

    pData->iGlobalRendintent    = pSave->iGlobalRendintent;

    pData->iGlobalProfilesize   = pSave->iGlobalProfilesize;

    if (pData->iGlobalProfilesize)     /* has a profile ? */
    {                                  /* then copy that ! */
      MNG_ALLOC (pData, pData->pGlobalProfile, pData->iGlobalProfilesize)
      MNG_COPY (pData->pGlobalProfile, pSave->pGlobalProfile, pData->iGlobalProfilesize)
    }

    pData->iGlobalBKGDred       = pSave->iGlobalBKGDred;
    pData->iGlobalBKGDgreen     = pSave->iGlobalBKGDgreen;
    pData->iGlobalBKGDblue      = pSave->iGlobalBKGDblue;
  }
  else                                 /* no saved-data; so reset the lot */
  {
#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE)
    pData->bHasglobalPLTE       = MNG_FALSE;
    pData->bHasglobalTRNS       = MNG_FALSE;
    pData->bHasglobalGAMA       = MNG_FALSE;
    pData->bHasglobalCHRM       = MNG_FALSE;
    pData->bHasglobalSRGB       = MNG_FALSE;
    pData->bHasglobalICCP       = MNG_FALSE;
    pData->bHasglobalBKGD       = MNG_FALSE;
#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */

    if (!pData->bEMNGMAhack)             /* TODO: remove line in 1.0.0 !!! */
    {                                    /* TODO: remove line in 1.0.0 !!! */
    pData->iBACKred             = 0;
    pData->iBACKgreen           = 0;
    pData->iBACKblue            = 0;
    pData->iBACKmandatory       = 0;
    pData->iBACKimageid         = 0;
    pData->iBACKtile            = 0;
    }                                    /* TODO: remove line in 1.0.0 !!! */

    pData->iFRAMmode            = 1;
    pData->iFRAMdelay           = 1;
    pData->iFRAMtimeout         = 0x7fffffffl;
    pData->bFRAMclipping        = MNG_FALSE;
    pData->iFRAMclipl           = 0;
    pData->iFRAMclipr           = 0;
    pData->iFRAMclipt           = 0;
    pData->iFRAMclipb           = 0;
                                         /* also the next subframe parms */
    pData->iFramemode           = 1;
    pData->iFramedelay          = 1;
    pData->iFrametimeout        = 0x7fffffffl;
    pData->bFrameclipping       = MNG_FALSE;
    pData->iFrameclipl          = 0;
    pData->iFrameclipr          = 0;
    pData->iFrameclipt          = 0;
    pData->iFrameclipb          = 0;

    pData->iNextdelay           = 1;

    pData->iGlobalPLTEcount     = 0;

    pData->iGlobalTRNSrawlen    = 0;

    pData->iGlobalGamma         = 0;

    pData->iGlobalWhitepointx   = 0;
    pData->iGlobalWhitepointy   = 0;
    pData->iGlobalPrimaryredx   = 0;
    pData->iGlobalPrimaryredy   = 0;
    pData->iGlobalPrimarygreenx = 0;
    pData->iGlobalPrimarygreeny = 0;
    pData->iGlobalPrimarybluex  = 0;
    pData->iGlobalPrimarybluey  = 0;

    pData->iGlobalRendintent    = 0;

    if (pData->iGlobalProfilesize)       /* free a previous profile ? */
      MNG_FREE (pData, pData->pGlobalProfile, pData->iGlobalProfilesize)

    pData->iGlobalProfilesize   = 0;

    pData->iGlobalBKGDred       = 0;
    pData->iGlobalBKGDgreen     = 0;
    pData->iGlobalBKGDblue      = 0;
  }

  if (!pData->bEMNGMAhack)             /* TODO: remove line in 1.0.0 !!! */
  {                                    /* TODO: remove line in 1.0.0 !!! */
                                       /* drop un-frozen image objects */
  pImage = (mng_imagep)pData->pFirstimgobj;

  while (pImage)
  {                                    /* is it un-frozen ? */
    if (!pImage->bFrozen)
    {
      mng_imagep  pPrev = (mng_imagep)pImage->sHeader.pPrev;
      mng_imagep  pNext = (mng_imagep)pImage->sHeader.pNext;

      if (pPrev)                       /* unlink it */
        pPrev->sHeader.pNext = pNext;
      else
        pData->pFirstimgobj  = pNext;

      if (pNext)
        pNext->sHeader.pPrev = pPrev;
      else
        pData->pLastimgobj   = pPrev;

      if (pImage->pImgbuf->bFrozen)    /* buffer frozen ? */
      {
        if (pImage->pImgbuf->iRefcount <= 2)
          MNG_ERROR (pData, MNG_INTERNALERROR)
                                       /* decrease ref counter */
        pImage->pImgbuf->iRefcount--;
                                       /* just cleanup the object then */
        MNG_FREEX (pData, pImage, sizeof (mng_image))
      }
      else
      {                                /* free the image buffer */
        iRetcode = free_imagedataobject (pData, pImage->pImgbuf);
                                       /* and cleanup the object */
        MNG_FREEX (pData, pImage, sizeof (mng_image))

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }

      pImage = pNext;                  /* this is the next */
    }
    else                               /* neeeext */
      pImage = (mng_imagep)pImage->sHeader.pNext;

  }
  }                                    /* TODO: remove line in 1.0.0 !!! */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_RESTORE_STATE, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * General display processing routine                                     * */
/* *                                                                        * */
/* ************************************************************************** */

mng_retcode process_display (mng_datap pData)
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY, MNG_LC_START)
#endif

  if (!pData->iBreakpoint)             /* not broken previously ? */
  {
    if ((pData->iRequestframe) || (pData->iRequestlayer) || (pData->iRequesttime))
    {
      pData->bSearching = MNG_TRUE;    /* indicate we're searching */

      iRetcode = clear_canvas (pData); /* make the canvas virgin black ?!? */

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
                                       /* let's start from the top, shall we */
      pData->pCurraniobj = pData->pFirstaniobj;
    }
  }

  do                                   /* process the objects */
  {
    if (pData->bSearching)             /* are we looking sor something ? */
    {
      if ((pData->iRequestframe) &&
          (pData->iRequestframe < ((mng_object_headerp)pData->pCurraniobj)->iFramenr))
      {
        pData->iRequestframe = 0;      /* found the frame ! */
        pData->bSearching    = MNG_FALSE;
      }
      else
      if ((pData->iRequestlayer) &&
          (pData->iRequestlayer < ((mng_object_headerp)pData->pCurraniobj)->iLayernr))
      {
        pData->iRequestlayer = 0;      /* found the layer ! */
        pData->bSearching    = MNG_FALSE;
      }
      else
      if ((pData->iRequesttime) &&
          (pData->iRequesttime < ((mng_object_headerp)pData->pCurraniobj)->iPlaytime))
      {
        pData->iRequesttime  = 0;      /* found the playtime ! */
        pData->bSearching    = MNG_FALSE;
      }
    }
                                       /* do we need to finish something first ? */
    if ((pData->iBreakpoint) && (pData->iBreakpoint < 99))
    {
      switch (pData->iBreakpoint)      /* return to broken display routine */
      {
        case 1  : { iRetcode = process_display_fram2 (pData); break; }
        case 3  : ;                    /* same as 4 !!! */
        case 4  : { iRetcode = process_display_show  (pData); break; }
        case 5  : { iRetcode = process_display_clon2 (pData); break; }
        case 9  : { iRetcode = process_display_magn2 (pData); break; }
        default : MNG_ERROR (pData, MNG_INTERNALERROR)
      }
    }
    else
    {
      if (pData->pCurraniobj)
        iRetcode = ((mng_object_headerp)pData->pCurraniobj)->fProcess (pData, pData->pCurraniobj);
    }

    if (!pData->bTimerset)             /* reset breakpoint flag ? */
      pData->iBreakpoint = 0;
                                       /* can we advance to next object ? */
    if ((!iRetcode) && (pData->pCurraniobj) &&
        (!pData->bTimerset) && (!pData->bSectionwait))
    {
      pData->pCurraniobj = ((mng_object_headerp)pData->pCurraniobj)->pNext;
                                       /* MEND processing to be done ? */
      if ((pData->eImagetype == mng_it_mng) && (!pData->pCurraniobj))
        iRetcode = process_display_mend (pData);

      if (!pData->pCurraniobj)         /* refresh after last image ? */
        pData->bNeedrefresh = MNG_TRUE;
    }
  }                                    /* until error or a break or no more objects */
  while ((!iRetcode) && (pData->pCurraniobj) &&
         (!pData->bTimerset) && (!pData->bSectionwait) && (!pData->bFreezing));

  if (iRetcode)                        /* on error bail out */
    return iRetcode;
                                       /* refresh needed ? */
  if ((!pData->bTimerset) && (pData->bNeedrefresh))
  {
    iRetcode = display_progressive_refresh (pData, 1);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
  }
                                       /* timer break ? */
  if ((pData->bTimerset) && (!pData->iBreakpoint))
    pData->iBreakpoint = 99;
  else
  if (!pData->bTimerset)
    pData->iBreakpoint = 0;            /* reset if no timer break */

  if ((!pData->bTimerset) && (!pData->pCurraniobj))
    pData->bRunning = MNG_FALSE;       /* all done now ! */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * Chunk display processing routines                                      * */
/* *                                                                        * */
/* ************************************************************************** */

mng_retcode process_display_ihdr (mng_datap pData)
{                                      /* address the current "object" if any */
  mng_imagep pImage = (mng_imagep)pData->pCurrentobj;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IHDR, MNG_LC_START)
#endif

  if (!pData->bHasDHDR)
  {
    pData->fInitrowproc = MNG_NULL;    /* do nothing by default */
    pData->fDisplayrow  = MNG_NULL;
    pData->fCorrectrow  = MNG_NULL;
    pData->fStorerow    = MNG_NULL;
    pData->fProcessrow  = MNG_NULL;
    pData->fDifferrow   = MNG_NULL;
    pData->pStoreobj    = MNG_NULL;
  }

  if (!pData->iBreakpoint)             /* not previously broken ? */
  {
    mng_retcode iRetcode = MNG_NOERROR;

    if (pData->bHasDHDR)               /* is a delta-image ? */
    {
      if (pData->iDeltatype == MNG_DELTATYPE_REPLACE)
        iRetcode = reset_object_details (pData, (mng_imagep)pData->pDeltaImage,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iBitdepth, pData->iColortype,
                                         pData->iCompression, pData->iFilter,
                                         pData->iInterlace, MNG_TRUE);
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
      {
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iBitdepth;
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iBitdepth;
      }
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iBitdepth;
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iBitdepth;
        
                                       /* process immediatly if bitdepth & colortype are equal */
      pData->bDeltaimmediate =
        (mng_bool)((pData->iBitdepth  == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iBitdepth ) &&
                   (pData->iColortype == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iColortype)    );
    }
    else
    {
      if (pImage)                      /* update object buffer ? */
        iRetcode = reset_object_details (pData, pImage,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iBitdepth, pData->iColortype,
                                         pData->iCompression, pData->iFilter,
                                         pData->iInterlace, MNG_TRUE);
      else
        iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iBitdepth, pData->iColortype,
                                         pData->iCompression, pData->iFilter,
                                         pData->iInterlace, MNG_TRUE);
    }

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
  }

  if (!pData->bHasDHDR)
  {
    if (pImage)                        /* real object ? */
      pData->pStoreobj = pImage;       /* tell the row routines */
    else                               /* otherwise use object 0 */
      pData->pStoreobj = pData->pObjzero;
                                       /* display "on-the-fly" ? */
    if ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) &&
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) &&
         ( (pData->eImagetype == mng_it_png         ) ||
           (((mng_imagep)pData->pStoreobj)->bVisible)    )       )
    {
      next_layer (pData);              /* that's a new layer then ! */

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 2;
      else
      {
        pData->iBreakpoint = 0;
                                       /* anything to display ? */
        if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt))
          set_display_routine (pData); /* then determine display routine */
      }
    }
  }

  if (!pData->bTimerset)               /* no timer break ? */
  {
    switch (pData->iColortype)         /* determine row initialization routine */
    {
      case 0 : {                       /* gray */
                 switch (pData->iBitdepth)
                 {
                   case  1 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_g1_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_g1_i;

                               break;
                             }
                   case  2 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_g2_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_g2_i;

                               break;
                             }
                   case  4 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_g4_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_g4_i;

                               break;
                             }
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_g8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_g8_i;

                               break;
                             }
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_g16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_g16_i;

                               break;
                             }
                 }

                 break;
               }
      case 2 : {                       /* rgb */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_rgb8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_rgb8_i;

                               break;
                             }
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_rgb16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_rgb16_i;

                               break;
                             }
                 }

                 break;
               }
      case 3 : {                       /* indexed */
                 switch (pData->iBitdepth)
                 {
                   case  1 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_idx1_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_idx1_i;

                               break;
                             }
                   case  2 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_idx2_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_idx2_i;

                               break;
                             }
                   case  4 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_idx4_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_idx4_i;

                               break;
                             }
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_idx8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_idx8_i;

                               break;
                             }
                 }

                 break;
               }
      case 4 : {                       /* gray+alpha */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_ga8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_ga8_i;

                               break;
                             }
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_ga16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_ga16_i;

                               break;
                             }
                 }

                 break;
               }
      case 6 : {                       /* rgb+alpha */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_rgba8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_rgba8_i;

                               break;
                             }
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)init_rgba16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)init_rgba16_i;

                               break;
                             }
                 }

                 break;
               }
    }

    pData->iFilterofs = 0;             /* determine filter characteristics */
    pData->iLevel0    = 0;             /* default levels */
    pData->iLevel1    = 0;    
    pData->iLevel2    = 0;
    pData->iLevel3    = 0;
                                       /* leveling & differing ? */
/*    if (pData->iFilter & 0x40)
    {
      switch (pData->iColortype)
      {
        case 0 : {
                   if (pData->iBitdepth <= 8)
                     pData->iFilterofs = 1;
                   else
                     pData->iFilterofs = 2;

                   break;
                 }
        case 2 : {
                   if (pData->iBitdepth <= 8)
                     pData->iFilterofs = 3;
                   else
                     pData->iFilterofs = 6;

                   break;
                 }
        case 3 : {
                   pData->iFilterofs = 1;
                   break;
                 }
        case 4 : {
                   if (pData->iBitdepth <= 8)
                     pData->iFilterofs = 2;
                   else
                     pData->iFilterofs = 4;

                   break;
                 }
        case 6 : {
                   if (pData->iBitdepth <= 8)
                     pData->iPixelofs  = 5;
                   else
                     pData->iFilterofs = 8;

                   break;
                 }
      }
    } */
                                       /* no adaptive filtering ? */
/*    if (pData->iFilter & 0x01)
      pData->iPixelofs = pData->iFilterofs;
    else */
      pData->iPixelofs = pData->iFilterofs + 1;

  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IHDR, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_idat (mng_datap  pData,
                                  mng_uint32 iRawlen,
                                  mng_uint8p pRawdata)
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IDAT, MNG_LC_START)
#endif

  if (pData->bRestorebkgd)             /* need to restore the background ? */
  {
    pData->bRestorebkgd = MNG_FALSE;
    iRetcode            = load_bkgdlayer (pData);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

    if ((pData->bDisplaying) && (pData->bRunning))
      pData->iLayerseq++;              /* and it counts as a layer then ! */
  }

  if (pData->fInitrowproc)             /* need to initialize row processing? */
  {
    iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData);
    pData->fInitrowproc = MNG_NULL;    /* only call this once !!! */
  }

  if ((!iRetcode) && (!pData->bInflating))
                                       /* initialize inflate */
    iRetcode = mngzlib_inflateinit (pData);

  if (!iRetcode)                       /* all ok? then inflate, my man */
    iRetcode = mngzlib_inflaterows (pData, iRawlen, pRawdata);

  if (iRetcode)                        /* on error bail out */
    return iRetcode;
    
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IDAT, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_iend (mng_datap pData)
{
  mng_retcode iRetcode, iRetcode2;
  mng_bool bDodisplay = MNG_FALSE;
  mng_bool bMagnify   = MNG_FALSE;
  mng_bool bCleanup   = (mng_bool)(pData->iBreakpoint != 0);

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IEND, MNG_LC_START)
#endif

#ifdef MNG_INCLUDE_JNG                 /* progressive+alpha JNG can be displayed now */
  if ( (pData->bHasJHDR                                         ) &&
       ( (pData->bJPEGprogressive) || (pData->bJPEGprogressive2)) &&
       ( (pData->eImagetype == mng_it_jng         ) ||
         (((mng_imagep)pData->pStoreobj)->bVisible)             ) &&
       ( (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) ||
         (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA)    )    )
    bDodisplay = MNG_TRUE;
#endif

  if ( (pData->pStoreobj) &&           /* on-the-fly magnification ? */
       ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX) ||
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY)    ) )
    bMagnify = MNG_TRUE;

  if ((pData->bHasBASI) ||             /* was it a BASI stream */
      (bDodisplay)      ||             /* or should we display the JNG */
      (bMagnify)        ||             /* or should we magnify it */
                                       /* or did we get broken here last time ? */
      ((pData->iBreakpoint) && (pData->iBreakpoint != 8)))
  {
    mng_imagep pImage = (mng_imagep)pData->pCurrentobj;

    if (!pImage)                       /* or was it object 0 ? */
      pImage = (mng_imagep)pData->pObjzero;
                                       /* display it now then ? */
    if ((pImage->bVisible) && (pImage->bViewable))
    {                                  /* ok, so do it */
      iRetcode = display_image (pData, pImage, bDodisplay);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 6;
    }
  }
  else
  if ((pData->bHasDHDR) ||             /* was it a DHDR stream */
      (pData->iBreakpoint == 8))       /* or did we get broken here last time ? */
  {
    mng_imagep pImage = (mng_imagep)pData->pDeltaImage;

    if (!pData->iBreakpoint)
    {                                  /* perform the delta operations needed */
      iRetcode = execute_delta_image (pData, pImage, (mng_imagep)pData->pObjzero);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
                                       /* display it now then ? */
    if ((pImage->bVisible) && (pImage->bViewable))
    {                                  /* ok, so do it */
      iRetcode = display_image (pData, pImage, MNG_FALSE);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 8;
    }
  }

  if (!pData->bTimerset)               /* can we continue ? */
  {
    pData->iBreakpoint = 0;            /* clear this flag now ! */
                                       /* cleanup object 0 */
    reset_object_details (pData, (mng_imagep)pData->pObjzero,
                          0, 0, 0, 0, 0, 0, 0, MNG_TRUE);

    if (pData->bInflating)             /* if we've been inflating */
    {                                  /* cleanup row-processing, */
      iRetcode  = cleanup_rowproc (pData);
                                       /* also cleanup inflate! */
      iRetcode2 = mngzlib_inflatefree (pData);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
      if (iRetcode2)
        return iRetcode2;
    }

#ifdef MNG_INCLUDE_JNG
    if (pData->bJPEGdecompress)        /* if we've been decompressing JDAT */
    {                                  /* cleanup row-processing, */
      iRetcode  = cleanup_rowproc (pData);
                                       /* also cleanup decompress! */
      iRetcode2 = mngjpeg_decompressfree (pData);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
      if (iRetcode2)
        return iRetcode2;
    }

    if (pData->bJPEGdecompress2)       /* if we've been decompressing JDAA */
    {                                  /* cleanup row-processing, */
      iRetcode  = cleanup_rowproc (pData);
                                       /* also cleanup decompress! */
      iRetcode2 = mngjpeg_decompressfree2 (pData);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
      if (iRetcode2)
        return iRetcode2;
    }
#endif

    if (bCleanup)                      /* if we got broken last time we need to cleanup */
    {
      pData->bHasIHDR = MNG_FALSE;     /* IEND signals the end for most ... */
      pData->bHasBASI = MNG_FALSE;
      pData->bHasDHDR = MNG_FALSE;
#ifdef MNG_INCLUDE_JNG
      pData->bHasJHDR = MNG_FALSE;
      pData->bHasJSEP = MNG_FALSE;
      pData->bHasJDAA = MNG_FALSE;
      pData->bHasJDAT = MNG_FALSE;
#endif
      pData->bHasPLTE = MNG_FALSE;
      pData->bHasTRNS = MNG_FALSE;
      pData->bHasGAMA = MNG_FALSE;
      pData->bHasCHRM = MNG_FALSE;
      pData->bHasSRGB = MNG_FALSE;
      pData->bHasICCP = MNG_FALSE;
      pData->bHasBKGD = MNG_FALSE;
      pData->bHasIDAT = MNG_FALSE;
    }
                                       /* if the image was displayed on the fly, */
                                       /* we'll have to make the app refresh */
    if ((pData->eImagetype != mng_it_mng) && (pData->fDisplayrow))
      pData->bNeedrefresh = MNG_TRUE;
     
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IEND, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_mend (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_START)
#endif
                                       /* TERM processed ? */
  if ((pData->bDisplaying) && (pData->bRunning) &&
      (pData->bHasTERM) && (pData->pTermaniobj))
  {
    mng_retcode   iRetcode;
    mng_ani_termp pTERM;
                                       /* get the right animation object ! */
    pTERM = (mng_ani_termp)pData->pTermaniobj;

    pData->iIterations++;              /* increase iteration count */

    switch (pTERM->iTermaction)        /* determine what to do! */
    {
      case 0 : {                       /* show last frame indefinitly */
                 break;                /* piece of cake, that is... */
               }

      case 1 : {                       /* cease displaying anything */
                 pData->bFrameclipping = MNG_FALSE;
                 load_bkgdlayer (pData);
                 break;
               }

      case 2 : {                       /* show first image after TERM */

                 /* TODO: something */

                 break;
               }

      case 3 : {                       /* repeat */
                 if ((pTERM->iItermax) && (pTERM->iItermax < 0x7FFFFFFF))
                   pTERM->iItermax--;

                 if (pTERM->iItermax)  /* go back to TERM ? */
                 {                     /* restore to initial or SAVE state */
                   iRetcode = restore_state (pData);

                   if (iRetcode)       /* on error bail out */
                     return iRetcode;
                                       /* notify the app ? */
                   if (pData->fProcessmend)
                   {
                     mng_bool bOke = pData->fProcessmend ((mng_handle)pData,
                                                          pData->iIterations,
                                                          pTERM->iItermax);
                     if (!bOke)        /* stop here and now ? */ 
                       break;
                   }
                                       /* restart from TERM chunk */
                   pData->pCurraniobj = pTERM;

                   if (pTERM->iDelay)  /* set the delay (?) */
                   {
                     mng_uint32 iWaitfor = 1000;
                                       /* what are we aiming for */
                     if (pData->iTicks)
                     {                 /* honor speed modifier */
                       switch (pData->iSpeed)
                       {
                         case mng_st_fast :
                           {
                             iWaitfor = (mng_uint32)(( 500 * pTERM->iDelay) / pData->iTicks);
                             break;
                           }
                         case mng_st_slow :
                           {
                             iWaitfor = (mng_uint32)((3000 * pTERM->iDelay) / pData->iTicks);
                             break;
                           }
                         case mng_st_slowest :
                           {
                             iWaitfor = (mng_uint32)((8000 * pTERM->iDelay) / pData->iTicks);
                             break;
                           }
                         default :
                           {
                             iWaitfor = (mng_uint32)((1000 * pTERM->iDelay) / pData->iTicks);
                           }
                       }
                     }

                     iRetcode = display_progressive_refresh (pData, iWaitfor);

                     if (iRetcode)     /* on error bail out */
                       return iRetcode;
                   }
                 }
                 else
                 {
                   switch (pTERM->iIteraction)
                   {
                     case 0 : {        /* show last frame indefinitly */
                                break; /* piece of cake, that is... */
                              }

                     case 1 : {        /* cease displaying anything */
                                pData->bFrameclipping = MNG_FALSE;
                                load_bkgdlayer (pData);
                                break;
                              }

                     case 2 : {        /* show first image after TERM */

                                /* TODO: something */

                                break;
                              }

                   }
                 }

                 break;
               }

    }
  }

  if (!pData->pCurraniobj)             /* always let the app refresh at the end ! */
    pData->bNeedrefresh = MNG_TRUE;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_defi (mng_datap pData)
{
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DEFI, MNG_LC_START)
#endif

  if (!pData->iDEFIobjectid)           /* object id=0 ? */
  {
    pImage             = (mng_imagep)pData->pObjzero;

    if (pData->bDEFIhasdonotshow)
      pImage->bVisible = (mng_bool)(pData->iDEFIdonotshow == 0);

    if (pData->bDEFIhasloca)
    {
      pImage->iPosx    = pData->iDEFIlocax;
      pImage->iPosy    = pData->iDEFIlocay;
    }

    if (pData->bDEFIhasclip)
    {
      pImage->bClipped = pData->bDEFIhasclip;
      pImage->iClipl   = pData->iDEFIclipl;
      pImage->iClipr   = pData->iDEFIclipr;
      pImage->iClipt   = pData->iDEFIclipt;
      pImage->iClipb   = pData->iDEFIclipb;
    }

    pData->pCurrentobj = 0;            /* not a real object ! */
  }
  else
  {                                    /* already exists ? */
    pImage = (mng_imagep)find_imageobject (pData, pData->iDEFIobjectid);

    if (!pImage)                       /* if not; create new */
    {
      mng_retcode iRetcode = create_imageobject (pData, pData->iDEFIobjectid,
                                                 (mng_bool)(pData->iDEFIconcrete == 1),
                                                 (mng_bool)(pData->iDEFIdonotshow == 0),
                                                 MNG_FALSE, 0, 0, 0, 0, 0, 0, 0,
                                                 pData->iDEFIlocax, pData->iDEFIlocay,
                                                 pData->bDEFIhasclip,
                                                 pData->iDEFIclipl, pData->iDEFIclipr,
                                                 pData->iDEFIclipt, pData->iDEFIclipb,
                                                 &pImage);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
    else
    {                                  /* exists; then set new info */
      if (pData->bDEFIhasdonotshow)
        pImage->bVisible = (mng_bool)(pData->iDEFIdonotshow == 0);

      pImage->bViewable  = MNG_FALSE;

      if (pData->bDEFIhasloca)
      {
        pImage->iPosx    = pData->iDEFIlocax;
        pImage->iPosy    = pData->iDEFIlocay;
      }

      if (pData->bDEFIhasclip)
      {
        pImage->bClipped = pData->bDEFIhasclip;
        pImage->iClipl   = pData->iDEFIclipl;
        pImage->iClipr   = pData->iDEFIclipr;
        pImage->iClipt   = pData->iDEFIclipt;
        pImage->iClipb   = pData->iDEFIclipb;
      }

      if (pData->bDEFIhasconcrete)
        pImage->pImgbuf->bConcrete = (mng_bool)(pData->iDEFIconcrete == 1);
    }

    pData->pCurrentobj = pImage;       /* others may want to know this */
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DEFI, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_basi (mng_datap  pData,
                                  mng_uint16 iRed,
                                  mng_uint16 iGreen,
                                  mng_uint16 iBlue,
                                  mng_bool   bHasalpha,
                                  mng_uint16 iAlpha,
                                  mng_uint8  iViewable)
{                                      /* address the current "object" if any */
  mng_imagep     pImage = (mng_imagep)pData->pCurrentobj;
  mng_uint8p     pWork;
  mng_uint32     iX;
  mng_imagedatap pBuf;
  mng_retcode    iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_BASI, MNG_LC_START)
#endif

  if (!pImage)                         /* or is it an "on-the-fly" image ? */
    pImage = (mng_imagep)pData->pObjzero;
                                       /* address the object-buffer */
  pBuf               = pImage->pImgbuf;

  pData->fDisplayrow = MNG_NULL;       /* do nothing by default */
  pData->fCorrectrow = MNG_NULL;
  pData->fStorerow   = MNG_NULL;
  pData->fProcessrow = MNG_NULL;
                                       /* set parms now that they're known */
  iRetcode = reset_object_details (pData, pImage, pData->iDatawidth,
                                   pData->iDataheight, pData->iBitdepth,
                                   pData->iColortype, pData->iCompression,
                                   pData->iFilter, pData->iInterlace, MNG_FALSE);
  if (iRetcode)                        /* on error bail out */
    return iRetcode;
                                       /* save the viewable flag */
  pImage->bViewable = (mng_bool)(iViewable == 1);
  pBuf->bViewable   = pImage->bViewable;
  pData->pStoreobj  = pImage;          /* let row-routines know which object */

  pWork = pBuf->pImgdata;              /* fill the object-buffer with the specified
                                          "color" sample */
  switch (pData->iColortype)           /* depending on color_type & bit_depth */
  {
    case 0 : {                         /* gray */
               if (pData->iBitdepth == 16)
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   mng_put_uint16 (pWork, iRed);
                   pWork += 2;
                 }
               }
               else
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   *pWork = (mng_uint8)iRed;
                   pWork++;
                 }
               }
                                       /* force tRNS ? */
               if ((bHasalpha) && (!iAlpha))
               {
                 pBuf->bHasTRNS  = MNG_TRUE;
                 pBuf->iTRNSgray = iRed;
               }

               break;
             }

    case 2 : {                         /* rgb */
               if (pData->iBitdepth == 16)
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   mng_put_uint16 (pWork,   iRed  );
                   mng_put_uint16 (pWork+2, iGreen);
                   mng_put_uint16 (pWork+4, iBlue );
                   pWork += 6;
                 }
               }
               else
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iGreen;
                   *(pWork+2) = (mng_uint8)iBlue;
                   pWork += 3;
                 }
               }
                                       /* force tRNS ? */
               if ((bHasalpha) && (!iAlpha))
               {
                 pBuf->bHasTRNS   = MNG_TRUE;
                 pBuf->iTRNSred   = iRed;
                 pBuf->iTRNSgreen = iGreen;
                 pBuf->iTRNSblue  = iBlue;
               }

               break;
             }

    case 3 : {                         /* indexed */
               pBuf->bHasPLTE = MNG_TRUE;

               switch (pData->iBitdepth)
               {
                 case 1  : { pBuf->iPLTEcount =   2; break; }
                 case 2  : { pBuf->iPLTEcount =   4; break; }
                 case 4  : { pBuf->iPLTEcount =  16; break; }
                 case 8  : { pBuf->iPLTEcount = 256; break; }
                 default : { pBuf->iPLTEcount =   1; break; }
               }

               pBuf->aPLTEentries [0].iRed   = (mng_uint8)iRed;
               pBuf->aPLTEentries [0].iGreen = (mng_uint8)iGreen;
               pBuf->aPLTEentries [0].iBlue  = (mng_uint8)iBlue;

               for (iX = 1; iX < pBuf->iPLTEcount; iX++)
               {
                 pBuf->aPLTEentries [iX].iRed   = 0;
                 pBuf->aPLTEentries [iX].iGreen = 0;
                 pBuf->aPLTEentries [iX].iBlue  = 0;
               }
                                       /* force tRNS ? */
               if ((bHasalpha) && (iAlpha < 255))
               {
                 pBuf->bHasTRNS         = MNG_TRUE;
                 pBuf->iTRNScount       = 1;
                 pBuf->aTRNSentries [0] = (mng_uint8)iAlpha;
               }

               break;
             }

    case 4 : {                         /* gray+alpha */
               if (pData->iBitdepth == 16)
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   mng_put_uint16 (pWork,   iRed);
                   mng_put_uint16 (pWork+2, iAlpha);
                   pWork += 4;
                 }
               }
               else
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iAlpha;
                   pWork += 2;
                 }
               }

               break;
             }

    case 6 : {                         /* rgb+alpha */
               if (pData->iBitdepth == 16)
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   mng_put_uint16 (pWork,   iRed);
                   mng_put_uint16 (pWork+2, iGreen);
                   mng_put_uint16 (pWork+4, iBlue);
                   mng_put_uint16 (pWork+6, iAlpha);
                   pWork += 8;
                 }
               }
               else
               {
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
                 {
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iGreen;
                   *(pWork+2) = (mng_uint8)iBlue;
                   *(pWork+3) = (mng_uint8)iAlpha;
                   pWork += 4;
                 }
               }

               break;
             }

  }

  switch (pData->iColortype)           /* determine row initialization routine */
  {                                    /* just to accomodate IDAT if it arrives */
    case 0 : {                         /* gray */
               switch (pData->iBitdepth)
               {
                 case  1 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_g1_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_g1_i;

                             break;
                           }
                 case  2 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_g2_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_g2_i;

                             break;
                           }
                 case  4 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_g4_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_g4_i;

                             break;
                           }
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_g8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_g8_i;

                             break;
                           }
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_g16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_g16_i;

                             break;
                           }
               }

               break;
             }
    case 2 : {                         /* rgb */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_rgb8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_rgb8_i;

                             break;
                           }
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_rgb16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_rgb16_i;

                             break;
                           }
               }

               break;
             }
    case 3 : {                         /* indexed */
               switch (pData->iBitdepth)
               {
                 case  1 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_idx1_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_idx1_i;

                             break;
                           }
                 case  2 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_idx2_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_idx2_i;

                             break;
                           }
                 case  4 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_idx4_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_idx4_i;

                             break;
                           }
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_idx8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_idx8_i;

                             break;
                           }
               }

               break;
             }
    case 4 : {                         /* gray+alpha */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_ga8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_ga8_i;

                             break;
                           }
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_ga16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_ga16_i;

                             break;
                           }
               }

               break;
             }
    case 6 : {                         /* rgb+alpha */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_rgba8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_rgba8_i;

                             break;
                           }
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)init_rgba16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)init_rgba16_i;

                             break;
                           }
               }

               break;
             }
  }

  pData->iFilterofs = 0;               /* determine filter characteristics */
  pData->iLevel0    = 0;               /* default levels */
  pData->iLevel1    = 0;
  pData->iLevel2    = 0;
  pData->iLevel3    = 0;
                                       /* leveling & differing ? */
/*  if (pData->iFilter & 0x40)
  {
    switch (pData->iColortype)
    {
      case 0 : {
                 if (pData->iBitdepth <= 8)
                   pData->iFilterofs = 1;
                 else
                   pData->iFilterofs = 2;

                 break;
               }
      case 2 : {
                 if (pData->iBitdepth <= 8)
                   pData->iFilterofs = 3;
                 else
                   pData->iFilterofs = 6;

                 break;
               }
      case 3 : {
                 pData->iFilterofs = 1;
                 break;
               }
      case 4 : {
                 if (pData->iBitdepth <= 8)
                   pData->iFilterofs = 2;
                 else
                   pData->iFilterofs = 4;

                 break;
               }
      case 6 : {
                 if (pData->iBitdepth <= 8)
                   pData->iPixelofs  = 5;
                 else
                   pData->iFilterofs = 8;

                 break;
               }
    }
  } */
                                       /* no adaptive filtering ? */
/*  if (pData->iFilter & 0x01)
    pData->iPixelofs = pData->iFilterofs;
  else */
    pData->iPixelofs = pData->iFilterofs + 1;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_BASI, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_clon (mng_datap  pData,
                                  mng_uint16 iSourceid,
                                  mng_uint16 iCloneid,
                                  mng_uint8  iClonetype,
                                  mng_bool   bHasdonotshow,
                                  mng_uint8  iDonotshow,
                                  mng_uint8  iConcrete,
                                  mng_bool   bHasloca,
                                  mng_uint8  iLocationtype,
                                  mng_int32  iLocationx,
                                  mng_int32  iLocationy)
{
  mng_imagep  pSource, pClone;
  mng_bool    bVisible, bAbstract;
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_START)
#endif
                                       /* locate the source object first */
  pSource = find_imageobject (pData, iSourceid);
                                       /* check if the clone exists */
  pClone  = find_imageobject (pData, iCloneid);

  if (!pSource)                        /* source must exist ! */
    MNG_ERROR (pData, MNG_OBJECTUNKNOWN);

  if (pClone)                          /* clone must not exist ! */
    MNG_ERROR (pData, MNG_OBJECTEXISTS);

  if (bHasdonotshow)                   /* DoNotShow flag filled ? */
    bVisible = (mng_bool)(iDonotshow == 0);
  else
    bVisible = pSource->bVisible;

  bAbstract  = (mng_bool)(iConcrete == 1);

  switch (iClonetype)                  /* determine action to take */
  {
    case 0 : {                         /* full clone */
               iRetcode = clone_imageobject (pData, iCloneid, MNG_FALSE,
                                             bVisible, bAbstract, bHasloca,
                                             iLocationtype, iLocationx, iLocationy,
                                             pSource, &pClone);
               break;
             }

    case 1 : {                         /* partial clone */
               iRetcode = clone_imageobject (pData, iCloneid, MNG_TRUE,
                                             bVisible, bAbstract, bHasloca,
                                             iLocationtype, iLocationx, iLocationy,
                                             pSource, &pClone);
               break;
             }

    case 2 : {                         /* renumber object */
               iRetcode = renum_imageobject (pData, pSource, iCloneid,
                                             bVisible, bAbstract, bHasloca,
                                             iLocationtype, iLocationx, iLocationy);
               pClone   = pSource;
               break;
             }

  }

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

                                       /* display on the fly ? */
  if ((pClone->bViewable) && (pClone->bVisible))
  {
    pData->pLastclone = pClone;        /* remember in case of timer break ! */
                                       /* display it */
    display_image (pData, pClone, MNG_FALSE);

    if (pData->bTimerset)              /* timer break ? */
      pData->iBreakpoint = 5;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_clon2 (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_START)
#endif
                                       /* only called after timer break ! */
  display_image (pData, (mng_imagep)pData->pLastclone, MNG_FALSE);
  pData->iBreakpoint = 0;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_disc (mng_datap   pData,
                                  mng_uint32  iCount,
                                  mng_uint16p pIds)
{
  mng_uint32 iX;
  mng_imagep pImage;
  mng_uint32 iRetcode;
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DISC, MNG_LC_START)
#endif

  if (iCount)                          /* specific list ? */
  {
    mng_uint16p pWork = pIds;

    for (iX = 0; iX < iCount; iX++)    /* iterate the list */
    {
      pImage = find_imageobject (pData, *pWork++);

      if (pImage)                      /* found the object ? */
      {                                /* then drop it */
        iRetcode = free_imageobject (pData, pImage);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
    }
  }
  else                                 /* empty: drop all un-frozen objects */
  {
    mng_imagep pNext = (mng_imagep)pData->pFirstimgobj;

    while (pNext)                      /* any left ? */
    {
      pImage = pNext;
      pNext  = pImage->sHeader.pNext;

      if (!pImage->bFrozen)            /* not frozen ? */
      {                                /* then drop it */
        iRetcode = free_imageobject (pData, pImage);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DISC, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_fram (mng_datap  pData,
                                  mng_uint8  iFramemode,
                                  mng_uint8  iChangedelay,
                                  mng_uint32 iDelay,
                                  mng_uint8  iChangetimeout,
                                  mng_uint32 iTimeout,
                                  mng_uint8  iChangeclipping,
                                  mng_uint8  iCliptype,
                                  mng_int32  iClipl,
                                  mng_int32  iClipr,
                                  mng_int32  iClipt,
                                  mng_int32  iClipb)
{
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_START)
#endif
                                       /* advance a frame then */
  iRetcode = next_frame (pData, iFramemode, iChangedelay, iDelay,
                         iChangetimeout, iTimeout, iChangeclipping,
                         iCliptype, iClipl, iClipr, iClipt, iClipb);

  if (pData->bTimerset)                /* timer break ? */
    pData->iBreakpoint = 1;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_END)
#endif

  return iRetcode;
}

/* ************************************************************************** */

mng_retcode process_display_fram2 (mng_datap pData)
{
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_START)
#endif
                                       /* again; after the break */
  iRetcode = next_frame (pData, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  pData->iBreakpoint = 0;              /* not again! */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_END)
#endif

  return iRetcode;
}

/* ************************************************************************** */

mng_retcode process_display_move (mng_datap  pData,
                                  mng_uint16 iFromid,
                                  mng_uint16 iToid,
                                  mng_uint8  iMovetype,
                                  mng_int32  iMovex,
                                  mng_int32  iMovey)
{
  mng_uint16 iX;
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MOVE, MNG_LC_START)
#endif
                                       /* iterate the list */
  for (iX = iFromid; iX <= iToid; iX++)
  {
    if (!iX)                           /* object id=0 ? */
      pImage = (mng_imagep)pData->pObjzero;
    else
      pImage = find_imageobject (pData, iX);

    if (pImage)                        /* object exists ? */
    {
      switch (iMovetype)
      {
        case 0 : {                     /* absolute */
                   pImage->iPosx = iMovex;
                   pImage->iPosy = iMovey;
                   break;
                 }
        case 1 : {                     /* relative */
                   pImage->iPosx = pImage->iPosx + iMovex;
                   pImage->iPosy = pImage->iPosy + iMovey;
                   break;
                 }
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MOVE, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_clip (mng_datap  pData,
                                  mng_uint16 iFromid,
                                  mng_uint16 iToid,
                                  mng_uint8  iCliptype,
                                  mng_int32  iClipl,
                                  mng_int32  iClipr,
                                  mng_int32  iClipt,
                                  mng_int32  iClipb)
{
  mng_uint16 iX;
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLIP, MNG_LC_START)
#endif
                                       /* iterate the list */
  for (iX = iFromid; iX <= iToid; iX++)
  {
    if (!iX)                           /* object id=0 ? */
      pImage = (mng_imagep)pData->pObjzero;
    else
      pImage = find_imageobject (pData, iX);

    if (pImage)                        /* object exists ? */
    {
      switch (iCliptype)
      {
        case 0 : {                     /* absolute */
                   pImage->bClipped = MNG_TRUE;
                   pImage->iClipl   = iClipl;
                   pImage->iClipr   = iClipr;
                   pImage->iClipt   = iClipt;
                   pImage->iClipb   = iClipb;
                   break;
                 }
        case 1 : {                    /* relative */
                   pImage->bClipped = MNG_TRUE;
                   pImage->iClipl   = pImage->iClipl + iClipl;
                   pImage->iClipr   = pImage->iClipr + iClipr;
                   pImage->iClipt   = pImage->iClipt + iClipt;
                   pImage->iClipb   = pImage->iClipb + iClipb;
                   break;
                 }
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLIP, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_show (mng_datap pData)
{
  mng_int16  iX, iS, iFrom, iTo;
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SHOW, MNG_LC_START)
#endif

  /* TODO: optimization for the cases where "abs (iTo - iFrom)" is rather high;
     especially where ((iFrom==1) && (iTo==65535)); eg. an empty SHOW !!! */

  if (pData->iBreakpoint == 3)         /* previously broken during cycle-mode ? */
  {
    pImage = find_imageobject (pData, pData->iSHOWnextid);

    if (pImage)                        /* still there ? */
      display_image (pData, pImage, MNG_FALSE);

    pData->iBreakpoint = 0;            /* let's not go through this again! */
  }
  else
  {
    if (pData->iBreakpoint)            /* previously broken at other point ? */
    {                                  /* restore last parms */
      iFrom = (mng_int16)pData->iSHOWfromid;
      iTo   = (mng_int16)pData->iSHOWtoid;
      iX    = (mng_int16)pData->iSHOWnextid;
      iS    = (mng_int16)pData->iSHOWskip;
    }
    else
    {                                  /* regular sequence ? */
      if (pData->iSHOWtoid >= pData->iSHOWfromid)
        iS  = 1;
      else                             /* reverse sequence ! */
        iS  = -1;

      iFrom = (mng_int16)pData->iSHOWfromid;
      iTo   = (mng_int16)pData->iSHOWtoid;
      iX    = iFrom;

      pData->iSHOWfromid = (mng_uint16)iFrom;
      pData->iSHOWtoid   = (mng_uint16)iTo;
      pData->iSHOWskip   = iS;
    }
                                       /* cycle mode ? */
    if ((pData->iSHOWmode == 6) || (pData->iSHOWmode == 7))
    {
      mng_uint16 iTrigger = 0;
      mng_uint16 iFound   = 0;
      mng_uint16 iPass    = 0;
      mng_imagep pFound   = 0;

      do
      {
        iPass++;                       /* lets prevent endless loops when there
                                          are no potential candidates in the list! */

        if (iS > 0)                    /* forward ? */
        {
          for (iX = iFrom; iX <= iTo; iX += iS)
          {
            pImage = find_imageobject (pData, (mng_uint16)iX);

            if (pImage)                  /* object exists ? */
            {
              if (iFound)                /* already found a candidate ? */
                pImage->bVisible = MNG_FALSE;
              else
              if (iTrigger)              /* found the trigger ? */
              {
                pImage->bVisible = MNG_TRUE;
                iFound           = iX;
                pFound           = pImage;
              }
              else
              if (pImage->bVisible)      /* ok, this is the trigger */
              {
                pImage->bVisible = MNG_FALSE;
                iTrigger         = iX;
              }
            }
          }
        }
        else
        {
          for (iX = iFrom; iX >= iTo; iX += iS)
          {
            pImage = find_imageobject (pData, (mng_uint16)iX);

            if (pImage)                  /* object exists ? */
            {
              if (iFound)                /* already found a candidate ? */
                pImage->bVisible = MNG_FALSE;
              else
              if (iTrigger)              /* found the trigger ? */
              {
                pImage->bVisible = MNG_TRUE;
                iFound           = iX;
                pFound           = pImage;
              }
              else
              if (pImage->bVisible)      /* ok, this is the trigger */
              {
                pImage->bVisible = MNG_FALSE;
                iTrigger         = iX;
              }
            }
          }
        }

        if (!iTrigger)                 /* did not find a trigger ? */
          iTrigger = 1;                /* then fake it so the first image
                                          gets nominated */
      }                                /* cycle back to beginning ? */
      while ((iPass < 2) && (iTrigger) && (!iFound));

      pData->iBreakpoint = 0;          /* just a sanity precaution */
                                       /* display it ? */
      if ((pData->iSHOWmode == 6) && (pFound))
      {
        display_image (pData, pFound, MNG_FALSE);

        if (pData->bTimerset)          /* timer set ? */
        {
          pData->iBreakpoint = 3;
          pData->iSHOWnextid = iFound; /* save it for after the break */
        }
      }
    }
    else
    {
      do
      {
        pImage = find_imageobject (pData, iX);

        if (pImage)                    /* object exists ? */
        {
          if (pData->iBreakpoint)      /* did we get broken last time ? */
          {                            /* could only happen in the display routine */
            display_image (pData, pImage, MNG_FALSE);
            pData->iBreakpoint = 0;    /* only once inside this loop please ! */
          }
          else
          {
            switch (pData->iSHOWmode)  /* do what ? */
            {
              case 0 : {
                         pImage->bVisible = MNG_TRUE;
                         display_image (pData, pImage, MNG_FALSE);
                         break;
                       }
              case 1 : {
                         pImage->bVisible = MNG_FALSE;
                         break;
                       }
              case 2 : {
                         if (pImage->bVisible)
                           display_image (pData, pImage, MNG_FALSE);
                         break;
                       }
              case 3 : {
                         pImage->bVisible = MNG_TRUE;
                         break;
                       }
              case 4 : {
                         pImage->bVisible = (mng_bool)(!pImage->bVisible);
                         if (pImage->bVisible)
                           display_image (pData, pImage, MNG_FALSE);
                         break;
                       }
              case 5 : {
                         pImage->bVisible = (mng_bool)(!pImage->bVisible);
                       }
            }
          }
        }

        if (!pData->bTimerset)         /* next ? */
          iX += iS;

      }                                /* continue ? */
      while ((!pData->bTimerset) && (((iS > 0) && (iX <= iTo)) ||
                                     ((iS < 0) && (iX >= iTo))    ));

      if (pData->bTimerset)            /* timer set ? */
      {
        pData->iBreakpoint = 4;
        pData->iSHOWnextid = iX;       /* save for next time */
      }
      else
        pData->iBreakpoint = 0;
        
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SHOW, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_save (mng_datap pData)
{
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SAVE, MNG_LC_START)
#endif

  iRetcode = save_state (pData);       /* save the current state */

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SAVE, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_seek (mng_datap pData)
{
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_START)
#endif

  iRetcode = restore_state (pData);    /* restore the initial or SAVE state */

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

#ifdef MNG_INCLUDE_JNG
mng_retcode process_display_jhdr (mng_datap pData)
{                                      /* address the current "object" if any */
  mng_imagep  pImage   = (mng_imagep)pData->pCurrentobj;
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JHDR, MNG_LC_START)
#endif

  if (!pData->bHasDHDR)
  {
    pData->fInitrowproc  = MNG_NULL;   /* do nothing by default */
    pData->fDisplayrow   = MNG_NULL;
    pData->fCorrectrow   = MNG_NULL;
    pData->fStorerow     = MNG_NULL;
    pData->fProcessrow   = MNG_NULL;
    pData->fDifferrow    = MNG_NULL;
    pData->fStorerow2    = MNG_NULL;
    pData->fStorerow3    = MNG_NULL;

    pData->pStoreobj     = MNG_NULL;   /* initialize important work-parms */

    pData->iJPEGrow      = 0;
    pData->iJPEGalpharow = 0;
    pData->iJPEGrgbrow   = 0;
    pData->iRowmax       = 0;          /* so init_rowproc does the right thing ! */
  }

  if (!pData->iBreakpoint)             /* not previously broken ? */
  {
    if (pData->bHasDHDR)               /* delta-image ? */
    {
      if (pData->iDeltatype == MNG_DELTATYPE_REPLACE)
      {
        iRetcode = reset_object_details (pData, (mng_imagep)pData->pDeltaImage,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iJHDRimgbitdepth, pData->iJHDRcolortype,
                                         pData->iJHDRalphacompression, pData->iJHDRalphafilter,
                                         pData->iJHDRalphainterlace, MNG_TRUE);

        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphabitdepth    = pData->iJHDRalphabitdepth;
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iJHDRcompression  = pData->iJHDRimgcompression;
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iJHDRinterlace    = pData->iJHDRimginterlace;
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth;
      }
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
      {
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iJHDRimgbitdepth;
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth;
      }
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth;
      else
      if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
          (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
        ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iJHDRimgbitdepth;
        
    }
    else
    {
      if (pImage)                      /* update object buffer ? */
      {
        iRetcode = reset_object_details (pData, pImage,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iJHDRimgbitdepth, pData->iJHDRcolortype,
                                         pData->iJHDRalphacompression, pData->iJHDRalphafilter,
                                         pData->iJHDRalphainterlace, MNG_TRUE);

        pImage->pImgbuf->iAlphabitdepth    = pData->iJHDRalphabitdepth;
        pImage->pImgbuf->iJHDRcompression  = pData->iJHDRimgcompression;
        pImage->pImgbuf->iJHDRinterlace    = pData->iJHDRimginterlace;
        pImage->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth;
      }
      else                             /* update object 0 */
      {
        iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iJHDRimgbitdepth, pData->iJHDRcolortype,
                                         pData->iJHDRalphacompression, pData->iJHDRalphafilter,
                                         pData->iJHDRalphainterlace, MNG_TRUE);

        ((mng_imagep)pData->pObjzero)->pImgbuf->iAlphabitdepth    = pData->iJHDRalphabitdepth;
        ((mng_imagep)pData->pObjzero)->pImgbuf->iJHDRcompression  = pData->iJHDRimgcompression;
        ((mng_imagep)pData->pObjzero)->pImgbuf->iJHDRinterlace    = pData->iJHDRimginterlace;
        ((mng_imagep)pData->pObjzero)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth;
      }
    }

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
  }

  if (!pData->bHasDHDR)
  {                                    /* we're always storing a JPEG */
    if (pImage)                        /* real object ? */
      pData->pStoreobj = pImage;       /* tell the row routines */
    else                               /* otherwise use object 0 */
      pData->pStoreobj = pData->pObjzero;
                                       /* display "on-the-fly" ? */
    if ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) &&
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) &&
         ( (pData->eImagetype == mng_it_jng         ) ||
           (((mng_imagep)pData->pStoreobj)->bVisible)    )       )
    {
      next_layer (pData);              /* that's a new layer then ! */

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 7;
      else
      {
        pData->iBreakpoint = 0;
                                       /* anything to display ? */
        if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt))
        {
          set_display_routine (pData); /* then determine display routine */
                                       /* display from the object we store in */
          pData->pRetrieveobj = pData->pStoreobj;
        }
      }
    }
  }

  if (!pData->bTimerset)               /* no timer break ? */
  {                                    /* default row initialization ! */
    pData->fInitrowproc = (mng_fptr)init_rowproc;

    if ((!pData->bHasDHDR) || (pData->iDeltatype == MNG_DELTATYPE_REPLACE))
    {                                  /* 8-bit JPEG ? */
      if (pData->iJHDRimgbitdepth == 8)
      {                                /* intermediate row is 8-bit deep */
        pData->bIsRGBA16   = MNG_FALSE;
        pData->iRowsamples = pData->iDatawidth;

        switch (pData->iJHDRcolortype) /* determine pixel processing routines */
        {
          case MNG_COLORTYPE_JPEGGRAY :
               {
                 pData->fStorerow2   = (mng_fptr)store_jpeg_g8;
                 pData->fRetrieverow = (mng_fptr)retrieve_g8;
                 pData->bIsOpaque    = MNG_TRUE;
                 break;
               }
          case MNG_COLORTYPE_JPEGCOLOR :
               {
                 pData->fStorerow2   = (mng_fptr)store_jpeg_rgb8;
                 pData->fRetrieverow = (mng_fptr)retrieve_rgb8;
                 pData->bIsOpaque    = MNG_TRUE;
                 break;
               }
          case MNG_COLORTYPE_JPEGGRAYA :
               {
                 pData->fStorerow2   = (mng_fptr)store_jpeg_ga8;
                 pData->fRetrieverow = (mng_fptr)retrieve_ga8;
                 pData->bIsOpaque    = MNG_FALSE;
                 break;
               }
          case MNG_COLORTYPE_JPEGCOLORA :
               {
                 pData->fStorerow2   = (mng_fptr)store_jpeg_rgba8;
                 pData->fRetrieverow = (mng_fptr)retrieve_rgba8;
                 pData->bIsOpaque    = MNG_FALSE;
                 break;
               }
        }
      }
      else
      {
        pData->bIsRGBA16 = MNG_TRUE;   /* intermediate row is 16-bit deep */

        /* TODO: 12-bit JPEG */
        /* TODO: 8- + 12-bit JPEG (eg. type=20) */

      }
                                       /* possible IDAT alpha-channel ? */
      if (pData->iJHDRalphacompression == MNG_COMPRESSION_DEFLATE)
      {
                                       /* determine alpha processing routine */
        switch (pData->iJHDRalphabitdepth)
        {
          case  1 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a1_ni;  break; }
          case  2 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a2_ni;  break; }
          case  4 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a4_ni;  break; }
          case  8 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a8_ni;  break; }
          case 16 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a16_ni; break; }
        }                                        
      }
      else                             /* possible JDAA alpha-channel ? */
      if (pData->iJHDRalphacompression == MNG_COMPRESSION_BASELINEJPEG)
      {                                /* 8-bit JPEG ? */
        if (pData->iJHDRimgbitdepth == 8)
        {
          if (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA)
            pData->fStorerow3 = (mng_fptr)store_jpeg_g8_alpha;
          else
          if (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA)
            pData->fStorerow3 = (mng_fptr)store_jpeg_rgb8_alpha;
        }
        else
        {
          /* TODO: 12-bit JPEG with 8-bit JDAA */
        }
      }  
                                       /* initialize JPEG library */
      iRetcode = mngjpeg_initialize (pData);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
    else
    {                                  /* must be alpha add/replace !! */
      if ((pData->iDeltatype != MNG_DELTATYPE_BLOCKALPHAADD    ) &&
          (pData->iDeltatype != MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
        MNG_ERROR (pData, MNG_INVDELTATYPE)
                                       /* determine alpha processing routine */
      switch (pData->iJHDRalphabitdepth)
      {
        case  1 : { pData->fInitrowproc = (mng_fptr)init_g1_ni;  break; }
        case  2 : { pData->fInitrowproc = (mng_fptr)init_g2_ni;  break; }
        case  4 : { pData->fInitrowproc = (mng_fptr)init_g4_ni;  break; }
        case  8 : { pData->fInitrowproc = (mng_fptr)init_g8_ni;  break; }
        case 16 : { pData->fInitrowproc = (mng_fptr)init_g16_ni; break; }
      }
    }

    pData->iFilterofs = 0;             /* determine filter characteristics */
    pData->iLevel0    = 0;             /* default levels */
    pData->iLevel1    = 0;    
    pData->iLevel2    = 0;
    pData->iLevel3    = 0;
                                       /* leveling & differing ? */
/*    if (pData->iJHDRalphafilter & 0x40)
    {
       if (pData->iJHDRalphabitdepth <= 8)
         pData->iFilterofs = 1;
       else
         pData->iFilterofs = 2;

    } */
                                       /* no adaptive filtering ? */
/*    if (pData->iJHDRalphafilter & 0x01)
      pData->iPixelofs = pData->iFilterofs;
    else */
      pData->iPixelofs = pData->iFilterofs + 1;

  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JHDR, MNG_LC_END)
#endif

  return MNG_NOERROR;
}
#endif /* MNG_INCLUDE_JNG */

/* ************************************************************************** */

#ifdef MNG_INCLUDE_JNG
mng_retcode process_display_jdaa (mng_datap  pData,
                                  mng_uint32 iRawlen,
                                  mng_uint8p pRawdata)
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAA, MNG_LC_START)
#endif

  if (!pData->bJPEGdecompress2)        /* if we're not decompressing already */
  {
    if (pData->fInitrowproc)           /* initialize row-processing? */
    {
      iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData);
      pData->fInitrowproc = MNG_NULL;  /* only call this once !!! */
    }

    if (!iRetcode)                     /* initialize decompress */
      iRetcode = mngjpeg_decompressinit2 (pData);
  }

  if (!iRetcode)                       /* all ok? then decompress, my man */
    iRetcode = mngjpeg_decompressdata2 (pData, iRawlen, pRawdata);

  if (iRetcode)
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAA, MNG_LC_END)
#endif

  return MNG_NOERROR;
}
#endif /* MNG_INCLUDE_JNG */

/* ************************************************************************** */

#ifdef MNG_INCLUDE_JNG
mng_retcode process_display_jdat (mng_datap  pData,
                                  mng_uint32 iRawlen,
                                  mng_uint8p pRawdata)
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAT, MNG_LC_START)
#endif

  if (pData->bRestorebkgd)             /* need to restore the background ? */
  {
    pData->bRestorebkgd = MNG_FALSE;
    iRetcode            = load_bkgdlayer (pData);

    if ((pData->bDisplaying) && (pData->bRunning))
      pData->iLayerseq++;              /* and it counts as a layer then ! */

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
  }

  if (!pData->bJPEGdecompress)         /* if we're not decompressing already */
  {
    if (pData->fInitrowproc)           /* initialize row-processing? */
    {
      iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData);
      pData->fInitrowproc = MNG_NULL;  /* only call this once !!! */
    }

    if (!iRetcode)                     /* initialize decompress */
      iRetcode = mngjpeg_decompressinit (pData);
  }

  if (!iRetcode)                       /* all ok? then decompress, my man */
    iRetcode = mngjpeg_decompressdata (pData, iRawlen, pRawdata);

  if (iRetcode)
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAT, MNG_LC_END)
#endif

  return MNG_NOERROR;
}
#endif /* MNG_INCLUDE_JNG */

/* ************************************************************************** */

mng_retcode process_display_dhdr (mng_datap  pData,
                                  mng_uint16 iObjectid,
                                  mng_uint8  iImagetype,
                                  mng_uint8  iDeltatype,
                                  mng_uint32 iBlockwidth,
                                  mng_uint32 iBlockheight,
                                  mng_uint32 iBlockx,
                                  mng_uint32 iBlocky)
{
  mng_imagep  pImage;
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DHDR, MNG_LC_START)
#endif

  pData->fInitrowproc     = MNG_NULL;  /* do nothing by default */
  pData->fDisplayrow      = MNG_NULL;
  pData->fCorrectrow      = MNG_NULL;
  pData->fStorerow        = MNG_NULL;
  pData->fProcessrow      = MNG_NULL;
  pData->pStoreobj        = MNG_NULL;

  pData->fDeltagetrow     = MNG_NULL;
  pData->fDeltaaddrow     = MNG_NULL;
  pData->fDeltareplacerow = MNG_NULL;
  pData->fDeltaputrow     = MNG_NULL;

  pImage = find_imageobject (pData, iObjectid);

  if (pImage)                          /* object exists ? */
  {
    if (pImage->pImgbuf->bConcrete)    /* is it concrete ? */
    {                                  /* previous magnification to be done ? */
      if ((pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY))
      {
        iRetcode = magnify_imageobject (pData, pImage);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
                                       /* save delta fields */
      pData->pDeltaImage           = (mng_ptr)pImage;
      pData->iDeltaImagetype       = iImagetype;
      pData->iDeltatype            = iDeltatype;
      pData->iDeltaBlockwidth      = iBlockwidth;
      pData->iDeltaBlockheight     = iBlockheight;
      pData->iDeltaBlockx          = iBlockx;
      pData->iDeltaBlocky          = iBlocky;
                                       /* restore target-object fields */
      pData->iDatawidth            = pImage->pImgbuf->iWidth;
      pData->iDataheight           = pImage->pImgbuf->iHeight;
      pData->iBitdepth             = pImage->pImgbuf->iBitdepth;
      pData->iColortype            = pImage->pImgbuf->iColortype;
      pData->iCompression          = pImage->pImgbuf->iCompression;
      pData->iFilter               = pImage->pImgbuf->iFilter;
      pData->iInterlace            = pImage->pImgbuf->iInterlace;

#ifdef MNG_INCLUDE_JNG
      pData->iJHDRimgbitdepth      = pImage->pImgbuf->iBitdepth;
      pData->iJHDRcolortype        = pImage->pImgbuf->iColortype;
      pData->iJHDRimgcompression   = pImage->pImgbuf->iJHDRcompression;
      pData->iJHDRimginterlace     = pImage->pImgbuf->iJHDRinterlace;
      pData->iJHDRalphacompression = pImage->pImgbuf->iCompression;
      pData->iJHDRalphafilter      = pImage->pImgbuf->iFilter;
      pData->iJHDRalphainterlace   = pImage->pImgbuf->iInterlace;
      pData->iJHDRalphabitdepth    = pImage->pImgbuf->iAlphabitdepth;
#endif
                                       /* block size specified ? */
      if (iDeltatype != MNG_DELTATYPE_NOCHANGE)
      {
        pData->iDatawidth          = iBlockwidth;
        pData->iDataheight         = iBlockheight;
      }

      switch (iDeltatype)              /* determine nr of delta-channels */
      {
         case MNG_DELTATYPE_BLOCKALPHAADD : ;
         case MNG_DELTATYPE_BLOCKALPHAREPLACE :
              {
#ifdef MNG_INCLUDE_JNG
                if ((pData->iColortype     == MNG_COLORTYPE_GRAYA    ) ||
                    (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA)    )
                {
                  pData->iColortype     = MNG_COLORTYPE_GRAY;
                  pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY;
                }
                else
                if ((pData->iColortype     == MNG_COLORTYPE_RGBA      ) ||
                    (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA)    )
                {
                  pData->iColortype     = MNG_COLORTYPE_GRAY;
                  pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY;
                }
#else
                if (pData->iColortype      == MNG_COLORTYPE_GRAYA)
                  pData->iColortype     = MNG_COLORTYPE_GRAY;
                else
                if (pData->iColortype      == MNG_COLORTYPE_RGBA)
                  pData->iColortype     = MNG_COLORTYPE_GRAY;
#endif
                else                   /* target has no alpha; that sucks! */
                  MNG_ERROR (pData, MNG_TARGETNOALPHA)

                break;
              }

         case MNG_DELTATYPE_BLOCKCOLORADD : ;
         case MNG_DELTATYPE_BLOCKCOLORREPLACE :
              {
#ifdef MNG_INCLUDE_JNG
                if ((pData->iColortype     == MNG_COLORTYPE_GRAYA    ) ||
                    (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA)    )
                {
                  pData->iColortype     = MNG_COLORTYPE_GRAY;
                  pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY;
                }
                else
                if ((pData->iColortype     == MNG_COLORTYPE_RGBA      ) ||
                    (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA)    )
                {
                  pData->iColortype     = MNG_COLORTYPE_RGB;
                  pData->iJHDRcolortype = MNG_COLORTYPE_JPEGCOLOR;
                }
#else
                if (pData->iColortype == MNG_COLORTYPE_GRAYA)
                  pData->iColortype = MNG_COLORTYPE_GRAY;
                else
                if (pData->iColortype == MNG_COLORTYPE_RGBA)
                  pData->iColortype = MNG_COLORTYPE_RGB;
#endif                  
                else                   /* target has no alpha; that sucks! */
                  MNG_ERROR (pData, MNG_TARGETNOALPHA)

                break;
              }

      }
                                       /* full image replace ? */
      if (iDeltatype == MNG_DELTATYPE_REPLACE)
      {
        iRetcode = reset_object_details (pData, pImage,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iBitdepth, pData->iColortype,
                                         pData->iCompression, pData->iFilter,
                                         pData->iInterlace, MNG_FALSE);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;

        pData->pStoreobj = pImage;     /* and store straight into this object */
      }
      else
      {
        mng_imagedatap pBufzero, pBuf;
                                       /* we store in object 0 and process it later */
        pData->pStoreobj = pData->pObjzero;
                                       /* make sure to initialize object 0 then */
        iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero,
                                         pData->iDatawidth, pData->iDataheight,
                                         pData->iBitdepth, pData->iColortype,
                                         pData->iCompression, pData->iFilter,
                                         pData->iInterlace, MNG_TRUE);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;

        pBuf     = pImage->pImgbuf;    /* copy possible palette & cheap transparency */
        pBufzero = ((mng_imagep)pData->pObjzero)->pImgbuf;

        pBufzero->bHasPLTE = pBuf->bHasPLTE;
        pBufzero->bHasTRNS = pBuf->bHasTRNS;

        if (pBufzero->bHasPLTE)        /* copy palette ? */
        {
          mng_uint32 iX;

          pBufzero->iPLTEcount = pBuf->iPLTEcount;

          for (iX = 0; iX < pBuf->iPLTEcount; iX++)
          {
            pBufzero->aPLTEentries [iX].iRed   = pBuf->aPLTEentries [iX].iRed;
            pBufzero->aPLTEentries [iX].iGreen = pBuf->aPLTEentries [iX].iGreen;
            pBufzero->aPLTEentries [iX].iBlue  = pBuf->aPLTEentries [iX].iBlue;
          }
        }

        if (pBufzero->bHasTRNS)        /* copy cheap transparency ? */
        {
          pBufzero->iTRNSgray  = pBuf->iTRNSgray;
          pBufzero->iTRNSred   = pBuf->iTRNSred;
          pBufzero->iTRNSgreen = pBuf->iTRNSgreen;
          pBufzero->iTRNSblue  = pBuf->iTRNSblue;
          pBufzero->iTRNScount = pBuf->iTRNScount;

          MNG_COPY (pBufzero->aTRNSentries, pBuf->aTRNSentries,
                    sizeof (pBufzero->aTRNSentries))
        }
                                       /* process immediatly if bitdepth & colortype are equal */
        pData->bDeltaimmediate =
          (mng_bool)((pData->bDisplaying) && (pData->bRunning) &&
                     (pData->iBitdepth  == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iBitdepth ) &&
                     (pData->iColortype == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iColortype)    );
      }

      switch (pData->iColortype)       /* determine row initialization routine */
      {
        case 0 : {                     /* gray */
                   switch (pData->iBitdepth)
                   {
                     case  1 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_g1_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_g1_i;

                                 break;
                               }
                     case  2 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_g2_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_g2_i;

                                 break;
                               }
                     case  4 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_g4_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_g4_i;

                                 break;
                               }
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_g8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_g8_i;

                                 break;
                               }
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_g16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_g16_i;

                                 break;
                               }
                   }

                   break;
                 }
        case 2 : {                     /* rgb */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_rgb8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_rgb8_i;

                                 break;
                               }
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_rgb16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_rgb16_i;

                                 break;
                               }
                   }

                   break;
                 }
        case 3 : {                     /* indexed */
                   switch (pData->iBitdepth)
                   {
                     case  1 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_idx1_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_idx1_i;

                                 break;
                               }
                     case  2 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_idx2_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_idx2_i;

                                 break;
                               }
                     case  4 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_idx4_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_idx4_i;

                                 break;
                               }
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_idx8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_idx8_i;

                                 break;
                               }
                   }

                   break;
                 }
        case 4 : {                     /* gray+alpha */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_ga8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_ga8_i;

                                 break;
                               }
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_ga16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_ga16_i;

                                 break;
                               }
                   }

                   break;
                 }
        case 6 : {                     /* rgb+alpha */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_rgba8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_rgba8_i;

                                 break;
                               }
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)init_rgba16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)init_rgba16_i;

                                 break;
                               }
                   }

                   break;
                 }
      }
    }
    else
      MNG_ERROR (pData, MNG_OBJNOTCONCRETE)

  }
  else
    MNG_ERROR (pData, MNG_OBJECTUNKNOWN)

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DHDR, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_prom (mng_datap  pData,
                                  mng_uint8  iBitdepth,
                                  mng_uint8  iColortype,
                                  mng_uint8  iFilltype)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_START)
#endif


  /* TODO: everything */
  

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_ipng (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IPNG, MNG_LC_START)
#endif
                                       /* indicate it for what it is now */
  pData->iDeltaImagetype = MNG_IMAGETYPE_PNG;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IPNG, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_ijng (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IJNG, MNG_LC_START)
#endif
                                       /* indicate it for what it is now */
  pData->iDeltaImagetype = MNG_IMAGETYPE_JNG;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IJNG, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_pplt (mng_datap      pData,
                                  mng_uint8      iType,
                                  mng_uint32     iCount,
                                  mng_palette8ep paIndexentries,
                                  mng_uint8p     paAlphaentries,
                                  mng_uint8p     paUsedentries)
{
  mng_uint32     iX;
  mng_imagep     pImage = (mng_imagep)pData->pObjzero;
  mng_imagedatap pBuf   = pImage->pImgbuf;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PPLT, MNG_LC_START)
#endif

  switch (iType)
  {
    case MNG_DELTATYPE_REPLACERGB :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   = paIndexentries [iX].iRed;
            pBuf->aPLTEentries [iX].iGreen = paIndexentries [iX].iGreen;
            pBuf->aPLTEentries [iX].iBlue  = paIndexentries [iX].iBlue;
          }
        }

        break;
      }
    case MNG_DELTATYPE_DELTARGB :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iRed   +
                                           paIndexentries [iX].iRed  );
            pBuf->aPLTEentries [iX].iGreen =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iGreen +
                                           paIndexentries [iX].iGreen);
            pBuf->aPLTEentries [iX].iBlue  =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iBlue  +
                                           paIndexentries [iX].iBlue );
          }
        }

        break;
      }
    case MNG_DELTATYPE_REPLACEALPHA :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
            pBuf->aTRNSentries [iX] = paAlphaentries [iX];
        }

        break;
      }
    case MNG_DELTATYPE_DELTAALPHA :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
            pBuf->aTRNSentries [iX] =
                               (mng_uint8)(pBuf->aTRNSentries [iX] +
                                           paAlphaentries [iX]);
        }

        break;
      }
    case MNG_DELTATYPE_REPLACERGBA :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   = paIndexentries [iX].iRed;
            pBuf->aPLTEentries [iX].iGreen = paIndexentries [iX].iGreen;
            pBuf->aPLTEentries [iX].iBlue  = paIndexentries [iX].iBlue;
            pBuf->aTRNSentries [iX]        = paAlphaentries [iX];
          }
        }

        break;
      }
    case MNG_DELTATYPE_DELTARGBA :
      {
        for (iX = 0; iX < iCount; iX++)
        {
          if (paUsedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iRed   +
                                           paIndexentries [iX].iRed  );
            pBuf->aPLTEentries [iX].iGreen =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iGreen +
                                           paIndexentries [iX].iGreen);
            pBuf->aPLTEentries [iX].iBlue  =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iBlue  +
                                           paIndexentries [iX].iBlue );
            pBuf->aTRNSentries [iX] =
                               (mng_uint8)(pBuf->aTRNSentries [iX] +
                                           paAlphaentries [iX]);
          }
        }

        break;
      }
  }

  if ((iType != MNG_DELTATYPE_REPLACERGB) && (iType != MNG_DELTATYPE_DELTARGB))
  {
    if (pBuf->bHasTRNS)
    {
      if (iCount > pBuf->iTRNScount)
        pBuf->iTRNScount = iCount;
    }
    else
    {
      pBuf->iTRNScount = iCount;
      pBuf->bHasTRNS   = MNG_TRUE;
    }
  }

  if ((iType != MNG_DELTATYPE_REPLACEALPHA) && (iType != MNG_DELTATYPE_DELTAALPHA))
  {
    if (iCount > pBuf->iPLTEcount)
      pBuf->iPLTEcount = iCount;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PPLT, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_magn (mng_datap  pData,
                                  mng_uint16 iFirstid,
                                  mng_uint16 iLastid,
                                  mng_uint16 iMethodX,
                                  mng_uint16 iMX,
                                  mng_uint16 iMY,
                                  mng_uint16 iML,
                                  mng_uint16 iMR,
                                  mng_uint16 iMT,
                                  mng_uint16 iMB,
                                  mng_uint16 iMethodY)
{
  mng_uint16 iX;
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_START)
#endif
                                       /* iterate the object-ids */
  for (iX = iFirstid; iX <= iLastid; iX++)
  {
    if (iX == 0)                       /* process object 0 ? */
    {
      pImage = (mng_imagep)pData->pObjzero;

      pImage->iMAGN_MethodX = iMethodX;
      pImage->iMAGN_MethodY = iMethodY;
      pImage->iMAGN_MX      = iMX;
      pImage->iMAGN_MY      = iMY;
      pImage->iMAGN_ML      = iML;
      pImage->iMAGN_MR      = iMR;
      pImage->iMAGN_MT      = iMT;
      pImage->iMAGN_MB      = iMB;
    }
    else
    {
      pImage = find_imageobject (pData, iX);
                                       /* object exists & is not frozen ? */
      if ((pImage) && (!pImage->bFrozen))
      {                                /* previous magnification to be done ? */
        if ((pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY))
        {
          mng_retcode iRetcode = magnify_imageobject (pData, pImage);

          if (iRetcode)                /* on error bail out */
            return iRetcode;
        }

        pImage->iMAGN_MethodX = iMethodX;
        pImage->iMAGN_MethodY = iMethodY;
        pImage->iMAGN_MX      = iMX;
        pImage->iMAGN_MY      = iMY;
        pImage->iMAGN_ML      = iML;
        pImage->iMAGN_MR      = iMR;
        pImage->iMAGN_MT      = iMT;
        pImage->iMAGN_MB      = iMB;
      }
    }
  }

  iX = iFirstid;
                                       /* iterate again for showing */
  while ((iX <= iLastid) && (!pData->bTimerset))
  {
    if (iX)                            /* only real objects ! */
    {
      pImage = find_imageobject (pData, iX);
                                       /* object exists & is not frozen  &
                                          is visible & is viewable ? */
      if ((pImage) && (!pImage->bFrozen) &&
          (pImage->bVisible) && (pImage->bViewable))
        display_image (pData, pImage, MNG_FALSE);
    }

    iX++;
  }

  if (pData->bTimerset)                /* broken ? */
  {
    pData->iMAGNfromid = iFirstid;
    pData->iMAGNtoid   = iLastid;
    pData->iBreakpoint = 9;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

mng_retcode process_display_magn2 (mng_datap pData)
{
  mng_uint16 iX;
  mng_imagep pImage;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_START)
#endif

  iX = pData->iMAGNfromid;
                                       /* iterate again for showing */
  while ((iX <= pData->iMAGNtoid) && (!pData->bTimerset))
  {
    if (iX)                            /* only real objects ! */
    {
      pImage = find_imageobject (pData, iX);
                                       /* object exists & is not frozen  &
                                          is visible & is viewable ? */
      if ((pImage) && (!pImage->bFrozen) &&
          (pImage->bVisible) && (pImage->bViewable))
        display_image (pData, pImage, MNG_FALSE);
    }

    iX++;
  }

  if (pData->bTimerset)                /* broken ? */
    pData->iBreakpoint = 9;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_END)
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

#endif /* MNG_INCLUDE_DISPLAY_PROCS */

/* ************************************************************************** */
/* * end of file                                                            * */
/* ************************************************************************** */

