/* ************************************************************************** */
/* *             For conditions of distribution and use,                    * */
/* *                see copyright notice in libmng.h                        * */
/* ************************************************************************** */
/* *                                                                        * */
/* * project   : libmng                                                     * */
/* * file      : libmng_display.c          copyright (c) 2000-2007 G.Juyn   * */
/* * version   : 1.0.10                                                     * */
/* *                                                                        * */
/* * purpose   : Display management (implementation)                        * */
/* *                                                                        * */
/* * author    : G.Juyn                                                     * */
/* *                                                                        * */
/* * 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 separate 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!)    * */
/* *                                                                        * */
/* *             1.0.5 - 08/15/2002 - G.Juyn                                * */
/* *             - completed PROM support                                   * */
/* *             - completed delta-image support                            * */
/* *             1.0.5 - 08/19/2002 - G.Juyn                                * */
/* *             - B597134 - libmng pollutes the linker namespace           * */
/* *             1.0.5 - 09/13/2002 - G.Juyn                                * */
/* *             - fixed read/write of MAGN chunk                           * */
/* *             1.0.5 - 09/15/2002 - G.Juyn                                * */
/* *             - fixed LOOP iteration=0 special case                      * */
/* *             1.0.5 - 09/19/2002 - G.Juyn                                * */
/* *             - fixed color-correction for restore-background handling   * */
/* *             - optimized restore-background for bKGD cases              * */
/* *             - cleaned up some old stuff                                * */
/* *             1.0.5 - 09/20/2002 - G.Juyn                                * */
/* *             - finished support for BACK image & tiling                 * */
/* *             - added support for PAST                                   * */
/* *             1.0.5 - 09/22/2002 - G.Juyn                                * */
/* *             - added bgrx8 canvas (filler byte)                         * */
/* *             1.0.5 - 10/05/2002 - G.Juyn                                * */
/* *             - fixed dropping mix of frozen/unfrozen objects            * */
/* *             1.0.5 - 10/07/2002 - G.Juyn                                * */
/* *             - added proposed change in handling of TERM- & if-delay    * */
/* *             - added another fix for misplaced TERM chunk               * */
/* *             - completed support for condition=2 in TERM chunk          * */
/* *             1.0.5 - 10/18/2002 - G.Juyn                                * */
/* *             - fixed clipping-problem with BACK tiling (Thanks Sakura!) * */
/* *             1.0.5 - 10/20/2002 - G.Juyn                                * */
/* *             - fixed processing for multiple objects in MAGN            * */
/* *             - fixed display of visible target of PAST operation        * */
/* *             1.0.5 - 10/30/2002 - G.Juyn                                * */
/* *             - modified TERM/MEND processing for max(1, TERM_delay,     * */
/* *               interframe_delay)                                        * */
/* *             1.0.5 - 11/04/2002 - G.Juyn                                * */
/* *             - fixed layer- & frame-counting during read()              * */
/* *             - fixed goframe/golayer/gotime processing                  * */
/* *             1.0.5 - 01/19/2003 - G.Juyn                                * */
/* *             - B654627 - fixed SEGV when no gettickcount callback       * */
/* *             - B664383 - fixed typo                                     * */
/* *             - finalized changes in TERM/final_delay to elected proposal* */
/* *                                                                        * */
/* *             1.0.6 - 05/11/2003 - G. Juyn                               * */
/* *             - added conditionals around canvas update routines         * */
/* *             1.0.6 - 05/25/2003 - G.R-P                                 * */
/* *             - added MNG_SKIPCHUNK_cHNK footprint optimizations         * */
/* *             1.0.6 - 07/07/2003 - G.R-P                                 * */
/* *             - added conditionals around some JNG-supporting code       * */
/* *             - added conditionals around 16-bit supporting code         * */
/* *             - reversed some loops to use decrementing counter          * */
/* *             - combined init functions into one function                * */
/* *             1.0.6 - 07/10/2003 - G.R-P                                 * */
/* *             - replaced nested switches with simple init setup function * */
/* *             1.0.6 - 07/29/2003 - G.R-P                                 * */
/* *             - added conditionals around PAST chunk support             * */
/* *             1.0.6 - 08/17/2003 - G.R-P                                 * */
/* *             - added conditionals around non-VLC chunk support          * */
/* *                                                                        * */
/* *             1.0.7 - 11/27/2003 - R.A                                   * */
/* *             - added CANVAS_RGB565 and CANVAS_BGR565                    * */
/* *             1.0.7 - 12/06/2003 - R.A                                   * */
/* *             - added CANVAS_RGBA565 and CANVAS_BGRA565                  * */
/* *             1.0.7 - 01/25/2004 - J.S                                   * */
/* *             - added premultiplied alpha canvas' for RGBA, ARGB, ABGR   * */
/* *                                                                        * */
/* *             1.0.8 - 03/31/2004 - G.Juyn                                * */
/* *             - fixed problem with PAST usage where source > dest        * */
/* *             1.0.8 - 05/04/2004 - G.R-P.                                * */
/* *             - fixed misplaced 16-bit conditionals                      * */
/* *                                                                        * */
/* *             1.0.9 - 09/18/2004 - G.R-P.                                * */
/* *             - revised some SKIPCHUNK conditionals                      * */
/* *             1.0.9 - 10/10/2004 - G.R-P.                                * */
/* *             - added MNG_NO_1_2_4BIT_SUPPORT                            * */
/* *             1.0.9 - 10/14/2004 - G.Juyn                                * */
/* *             - added bgr565_a8 canvas-style (thanks to J. Elvander)     * */
/* *             1.0.9 - 12/11/2004 - G.Juyn                                * */
/* *             - added conditional MNG_OPTIMIZE_DISPLAYCALLS              * */
/* *             1.0.9 - 12/20/2004 - G.Juyn                                * */
/* *             - cleaned up macro-invocations (thanks to D. Airlie)       * */
/* *                                                                        * */
/* *             1.0.10 - 07/06/2005 - G.R-P.                               * */
/* *             - added more SKIPCHUNK conditionals                        * */
/* *             1.0.10 - 12/28/2005 - G.R-P.                               * */
/* *             - added missing SKIPCHUNK_MAGN conditional                 * */
/* *             1.0.10 - 03/07/2006 - (thanks to W. Manthey)               * */
/* *             - added CANVAS_RGB555 and CANVAS_BGR555                    * */
/* *             1.0.10 - 04/08/2007 - G.Juyn                               * */
/* *             - fixed several compiler warnings                          * */
/* *             1.0.10 - 04/08/2007 - G.Juyn                               * */
/* *             - added support for mPNG proposal                          * */
/* *             1.0.10 - 04/12/2007 - G.Juyn                               * */
/* *             - added support for ANG proposal                           * */
/* *                                                                        * */
/* ************************************************************************** */

#include "libmng.h"
#include "libmng_data.h"
#include "libmng_error.h"
#include "libmng_trace.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "libmng_chunks.h"
#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_LOCAL mng_retcode set_delay (mng_datap  pData,
                                 mng_uint32 iInterval)
{
  if (!iInterval)                      /* at least 1 msec please! */
    iInterval = 1;

  if (pData->bRunning)                 /* only when really displaying */
    if (!pData->fSettimer ((mng_handle)pData, iInterval))
      MNG_ERROR (pData, MNG_APPTIMERERROR);

#ifdef MNG_SUPPORT_DYNAMICMNG
  if ((!pData->bDynamic) || (pData->bRunning))
#else
  if (pData->bRunning)
#endif
    pData->bTimerset = MNG_TRUE;       /* and indicate so */

  return MNG_NOERROR;
}

/* ************************************************************************** */

MNG_LOCAL mng_uint32 calculate_delay (mng_datap  pData,
                                      mng_uint32 iDelay)
{
  mng_uint32 iTicks   = pData->iTicks;
  mng_uint32 iWaitfor = 1;             /* default non-MNG delay */

  if (!iTicks)                         /* tick_count not specified ? */
    if (pData->eImagetype == mng_it_mng)
      iTicks = 1000;

  if (iTicks)
  {
    switch (pData->iSpeed)             /* honor speed modifier */
    {
      case mng_st_fast :
        {
          iWaitfor = (mng_uint32)(( 500 * iDelay) / iTicks);
          break;
        }
      case mng_st_slow :
        {
          iWaitfor = (mng_uint32)((3000 * iDelay) / iTicks);
          break;
        }
      case mng_st_slowest :
        {
          iWaitfor = (mng_uint32)((8000 * iDelay) / iTicks);
          break;
        }
      default :
        {
          iWaitfor = (mng_uint32)((1000 * iDelay) / iTicks);
        }
    }
  }

  return iWaitfor;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * 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 mng_display_progressive_refresh (mng_datap  pData,
                                             mng_uint32 iInterval)
{
  {                                    /* let the app refresh first ? */
    if ((pData->bRunning) && (!pData->bSkipping) &&
        (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_LOCAL 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

  {
#ifndef MNG_SKIPCHUNK_FRAM
    if (pData->iFramedelay > 0 || pData->bForcedelay) /* real delay ? */
    {                                  /* let the app refresh first ? */
      pData->bForcedelay = MNG_FALSE;
      if ((pData->bRunning) && (!pData->bSkipping) &&
          (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;

#ifndef MNG_SKIPCHUNK_TERM
      if (pData->bOnlyfirstframe)      /* only processing first frame after TERM ? */
      {
        pData->iFramesafterTERM++;
                                       /* did we do a frame yet ? */
        if (pData->iFramesafterTERM > 1)
        {                              /* then that's it; just stop right here ! */
          pData->pCurraniobj = MNG_NULL;
          pData->bRunning    = MNG_FALSE;

          return MNG_NOERROR;
        }
      }
#endif

      if (pData->fGettickcount)
      {                                /* 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;
      }
      else
      {
        iRuninterval = 0;
      }

      iWaitfor = calculate_delay (pData, pData->iFramedelay);

      if (iWaitfor > iRuninterval)     /* delay necessary ? */
        iInterval = iWaitfor - iRuninterval;
      else
        iInterval = 1;                 /* force app to process messageloop */
                                       /* set the timer ? */
      if (((pData->bRunning) || (pData->bSearching) || (pData->bReading)) &&
          (!pData->bSkipping))
      {
        iRetcode = set_delay (pData, iInterval);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
    }

    if (!pData->bSkipping)             /* increase frametime in advance */
      pData->iFrametime = pData->iFrametime + iWaitfor;
                                       /* setup for next delay */
    pData->iFramedelay = pData->iNextdelay;
    pData->iAccumdelay += pData->iFramedelay;
#endif
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_INTERFRAME_DELAY, MNG_LC_END);
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

MNG_LOCAL void set_display_routine (mng_datap pData)
{                                        /* actively running ? */
  if (((pData->bRunning) || (pData->bSearching)) && (!pData->bSkipping))
  {
    switch (pData->iCanvasstyle)         /* determine display routine */
    {
#ifndef MNG_SKIPCANVAS_RGB8
      case MNG_CANVAS_RGB8    : { pData->fDisplayrow = (mng_fptr)mng_display_rgb8;     break; }
#endif
#ifndef MNG_SKIPCANVAS_RGBA8
      case MNG_CANVAS_RGBA8   : { pData->fDisplayrow = (mng_fptr)mng_display_rgba8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_RGBA8_PM
      case MNG_CANVAS_RGBA8_PM: { pData->fDisplayrow = (mng_fptr)mng_display_rgba8_pm; break; }
#endif
#ifndef MNG_SKIPCANVAS_ARGB8
      case MNG_CANVAS_ARGB8   : { pData->fDisplayrow = (mng_fptr)mng_display_argb8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_ARGB8_PM
      case MNG_CANVAS_ARGB8_PM: { pData->fDisplayrow = (mng_fptr)mng_display_argb8_pm; break; }
#endif
#ifndef MNG_SKIPCANVAS_RGB8_A8
      case MNG_CANVAS_RGB8_A8 : { pData->fDisplayrow = (mng_fptr)mng_display_rgb8_a8;  break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR8
      case MNG_CANVAS_BGR8    : { pData->fDisplayrow = (mng_fptr)mng_display_bgr8;     break; }
#endif
#ifndef MNG_SKIPCANVAS_BGRX8
      case MNG_CANVAS_BGRX8   : { pData->fDisplayrow = (mng_fptr)mng_display_bgrx8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_BGRA8
      case MNG_CANVAS_BGRA8   : { pData->fDisplayrow = (mng_fptr)mng_display_bgra8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_BGRA8_PM
      case MNG_CANVAS_BGRA8_PM: { pData->fDisplayrow = (mng_fptr)mng_display_bgra8_pm; break; }
#endif
#ifndef MNG_SKIPCANVAS_ABGR8
      case MNG_CANVAS_ABGR8   : { pData->fDisplayrow = (mng_fptr)mng_display_abgr8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_ABGR8_PM
      case MNG_CANVAS_ABGR8_PM: { pData->fDisplayrow = (mng_fptr)mng_display_abgr8_pm; break; }
#endif
#ifndef MNG_SKIPCANVAS_RGB565
      case MNG_CANVAS_RGB565  : { pData->fDisplayrow = (mng_fptr)mng_display_rgb565;   break; }
#endif
#ifndef MNG_SKIPCANVAS_RGBA565
      case MNG_CANVAS_RGBA565 : { pData->fDisplayrow = (mng_fptr)mng_display_rgba565;  break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR565
      case MNG_CANVAS_BGR565  : { pData->fDisplayrow = (mng_fptr)mng_display_bgr565;   break; }
#endif
#ifndef MNG_SKIPCANVAS_BGRA565
      case MNG_CANVAS_BGRA565 : { pData->fDisplayrow = (mng_fptr)mng_display_bgra565;  break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR565_A8
      case MNG_CANVAS_BGR565_A8 : { pData->fDisplayrow = (mng_fptr)mng_display_bgr565_a8;  break; }
#endif
#ifndef MNG_SKIPCANVAS_RGB555
      case MNG_CANVAS_RGB555  : { pData->fDisplayrow = (mng_fptr)mng_display_rgb555;  break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR555
      case MNG_CANVAS_BGR555  : { pData->fDisplayrow = (mng_fptr)mng_display_bgr555;  break; }
#endif

#ifndef MNG_NO_16BIT_SUPPORT
/*      case MNG_CANVAS_RGB16   : { pData->fDisplayrow = (mng_fptr)mng_display_rgb16;    break; } */
/*      case MNG_CANVAS_RGBA16  : { pData->fDisplayrow = (mng_fptr)mng_display_rgba16;   break; } */
/*      case MNG_CANVAS_ARGB16  : { pData->fDisplayrow = (mng_fptr)mng_display_argb16;   break; } */
/*      case MNG_CANVAS_BGR16   : { pData->fDisplayrow = (mng_fptr)mng_display_bgr16;    break; } */
/*      case MNG_CANVAS_BGRA16  : { pData->fDisplayrow = (mng_fptr)mng_display_bgra16;   break; } */
/*      case MNG_CANVAS_ABGR16  : { pData->fDisplayrow = (mng_fptr)mng_display_abgr16;   break; } */
#endif
/*      case MNG_CANVAS_INDEX8  : { pData->fDisplayrow = (mng_fptr)mng_display_index8;   break; } */
/*      case MNG_CANVAS_INDEXA8 : { pData->fDisplayrow = (mng_fptr)mng_display_indexa8;  break; } */
/*      case MNG_CANVAS_AINDEX8 : { pData->fDisplayrow = (mng_fptr)mng_display_aindex8;  break; } */
/*      case MNG_CANVAS_GRAY8   : { pData->fDisplayrow = (mng_fptr)mng_display_gray8;    break; } */
/*      case MNG_CANVAS_AGRAY8  : { pData->fDisplayrow = (mng_fptr)mng_display_agray8;   break; } */
/*      case MNG_CANVAS_GRAYA8  : { pData->fDisplayrow = (mng_fptr)mng_display_graya8;   break; } */
#ifndef MNG_NO_16BIT_SUPPORT
/*      case MNG_CANVAS_GRAY16  : { pData->fDisplayrow = (mng_fptr)mng_display_gray16;   break; } */
/*      case MNG_CANVAS_GRAYA16 : { pData->fDisplayrow = (mng_fptr)mng_display_graya16;  break; } */
/*      case MNG_CANVAS_AGRAY16 : { pData->fDisplayrow = (mng_fptr)mng_display_agray16;  break; } */
#endif
/*      case MNG_CANVAS_DX15    : { pData->fDisplayrow = (mng_fptr)mng_display_dx15;     break; } */
/*      case MNG_CANVAS_DX16    : { pData->fDisplayrow = (mng_fptr)mng_display_dx16;     break; } */
    }
  }

  return;
}

/* ************************************************************************** */

MNG_LOCAL 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->bSearching)) && (!pData->bSkipping))
  {
    mng_int32   iY;
    mng_retcode iRetcode;
    mng_bool    bColorcorr   = MNG_FALSE;
                                       /* 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_uint8p  pPrevrow     = pData->pPrevrow;
    mng_uint8p  pRGBArow     = pData->pRGBArow;
    mng_bool    bIsRGBA16    = pData->bIsRGBA16;
    mng_bool    bIsOpaque    = pData->bIsOpaque;
    mng_fptr    fCorrectrow  = pData->fCorrectrow;
    mng_fptr    fDisplayrow  = pData->fDisplayrow;
    mng_fptr    fRetrieverow = pData->fRetrieverow;
    mng_objectp pCurrentobj  = pData->pCurrentobj;
    mng_objectp pRetrieveobj = pData->pRetrieveobj;

    pData->iDestl   = 0;               /* determine clipping region */
    pData->iDestt   = 0;
    pData->iDestr   = pData->iWidth;
    pData->iDestb   = pData->iHeight;

#ifndef MNG_SKIPCHUNK_FRAM
    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);
    }
#endif
                                       /* 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)mng_restore_bkgd_bgcolor;

#ifndef MNG_SKIPCHUNK_bKGD
      if (((pData->eImagetype == mng_it_png) || (pData->eImagetype == mng_it_jng)) &&
          (pData->bUseBKGD))
      {                                /* prefer bKGD in PNG/JNG */
        if (!pData->pCurrentobj)
          pData->pCurrentobj = pData->pObjzero;

        if (((mng_imagep)pData->pCurrentobj)->pImgbuf->bHasBKGD)
        {
          pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_bkgd;
          bColorcorr          = MNG_TRUE;
        }
      }
#endif

      if (pData->fGetbkgdline)         /* background-canvas-access callback set ? */
      {
        switch (pData->iBkgdstyle)
        {
#ifndef MNG_SKIPCANVAS_RGB8
          case MNG_CANVAS_RGB8    : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_rgb8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR8
          case MNG_CANVAS_BGR8    : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_bgr8;    break; }
#endif
#ifndef MNG_SKIPCANVAS_BGRX8
          case MNG_CANVAS_BGRX8   : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_bgrx8;   break; }
#endif
#ifndef MNG_SKIPCANVAS_BGR565
          case MNG_CANVAS_BGR565  : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_bgr565;  break; }
#endif
#ifndef MNG_SKIPCANVAS_RGB565
          case MNG_CANVAS_RGB565  : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_rgb565;  break; }
#endif
#ifndef MNG_NO_16BIT_SUPPORT
  /*        case MNG_CANVAS_RGB16   : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_rgb16;   break; } */
  /*        case MNG_CANVAS_BGR16   : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_bgr16;   break; } */
#endif
  /*        case MNG_CANVAS_INDEX8  : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_index8;  break; } */
  /*        case MNG_CANVAS_GRAY8   : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_gray8;   break; } */
#ifndef MNG_NO_16BIT_SUPPORT
  /*        case MNG_CANVAS_GRAY16  : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_gray16;  break; } */
#endif
  /*        case MNG_CANVAS_DX15    : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_dx15;    break; } */
  /*        case MNG_CANVAS_DX16    : { pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_dx16;    break; } */
        }
      }

#ifndef MNG_SKIPCHUNK_BACK
      if (pData->bHasBACK)
      {                                /* background image ? */
        if ((pData->iBACKmandatory & 0x02) && (pData->iBACKimageid))
        {
          pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_backcolor;
          bColorcorr          = MNG_TRUE;
        }
        else                           /* background color ? */
        if (pData->iBACKmandatory & 0x01)
        {
          pData->fRestbkgdrow = (mng_fptr)mng_restore_bkgd_backcolor;
          bColorcorr          = MNG_TRUE;
        }
      }
#endif

      pData->fCorrectrow = MNG_NULL;   /* default no color-correction */

      if (bColorcorr)                  /* do we have to do color-correction ? */
      {
#ifdef MNG_NO_CMS
        iRetcode = MNG_NOERROR;
#else
#if defined(MNG_FULL_CMS)              /* determine color-management routine */
        iRetcode = mng_init_full_cms   (pData, MNG_TRUE, MNG_FALSE, MNG_FALSE);
#elif defined(MNG_GAMMA_ONLY)
        iRetcode = mng_init_gamma_only (pData, MNG_TRUE, MNG_FALSE, MNG_FALSE);
#elif defined(MNG_APP_CMS)
        iRetcode = mng_init_app_cms    (pData, MNG_TRUE, MNG_FALSE, MNG_FALSE);
#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->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 = mng_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_FULL_CMS)              /* cleanup cms stuff */
      if (bColorcorr)                  /* did we do color-correction ? */
      {
        iRetcode = mng_clear_cms (pData);

        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
#endif
#ifndef MNG_SKIPCHUNK_BACK
                                       /* background image ? */
      if ((pData->bHasBACK) && (pData->iBACKmandatory & 0x02) && (pData->iBACKimageid))
      {
        mng_imagep pImage;
                                       /* let's find that object then */
        pData->pRetrieveobj = mng_find_imageobject (pData, pData->iBACKimageid);
        pImage              = (mng_imagep)pData->pRetrieveobj;
                                       /* exists, viewable and visible ? */
        if ((pImage) && (pImage->bViewable) && (pImage->bVisible))
        {                              /* will it fall within the target region ? */
          if ((pImage->iPosx < pData->iDestr) && (pImage->iPosy < pData->iDestb)             &&
              ((pData->iBACKtile) ||
               ((pImage->iPosx + (mng_int32)pImage->pImgbuf->iWidth  >= pData->iDestl) &&
                (pImage->iPosy + (mng_int32)pImage->pImgbuf->iHeight >= pData->iDestt)    )) &&
              ((!pImage->bClipped) ||
               ((pImage->iClipl <= pImage->iClipr) && (pImage->iClipt <= pImage->iClipb)     &&
                (pImage->iClipl < pData->iDestr)   && (pImage->iClipr >= pData->iDestl)      &&
                (pImage->iClipt < pData->iDestb)   && (pImage->iClipb >= pData->iDestt)         )))
          {                            /* right; we've got ourselves something to do */
            if (pImage->bClipped)      /* clip output region with image's clipping region ? */
            {
              if (pImage->iClipl > pData->iDestl)
                pData->iDestl = pImage->iClipl;
              if (pImage->iClipr < pData->iDestr)
                pData->iDestr = pImage->iClipr;
              if (pImage->iClipt > pData->iDestt)
                pData->iDestt = pImage->iClipt;
              if (pImage->iClipb < pData->iDestb)
                pData->iDestb = pImage->iClipb;
            }
                                       /* image offset does some extra clipping too ! */
            if (pImage->iPosx > pData->iDestl)
              pData->iDestl = pImage->iPosx;
            if (pImage->iPosy > pData->iDestt)
              pData->iDestt = pImage->iPosy;

            if (!pData->iBACKtile)     /* without tiling further clipping is needed */
            {
              if (pImage->iPosx + (mng_int32)pImage->pImgbuf->iWidth  < pData->iDestr)
                pData->iDestr = pImage->iPosx + (mng_int32)pImage->pImgbuf->iWidth;
              if (pImage->iPosy + (mng_int32)pImage->pImgbuf->iHeight < pData->iDestb)
                pData->iDestb = pImage->iPosy + (mng_int32)pImage->pImgbuf->iHeight;
            }
            
            pData->iSourcel    = 0;    /* source relative to destination */
            pData->iSourcer    = pData->iDestr - pData->iDestl;
            pData->iSourcet    = 0;
            pData->iSourceb    = pData->iDestb - pData->iDestt;
                                       /* 16-bit background ? */

#ifdef MNG_NO_16BIT_SUPPORT
            pData->bIsRGBA16   = MNG_FALSE;
#else
            pData->bIsRGBA16      = (mng_bool)(pImage->pImgbuf->iBitdepth > 8);
#endif
                                       /* let restore routine know the offsets !!! */
            pData->iBackimgoffsx  = pImage->iPosx;
            pData->iBackimgoffsy  = pImage->iPosy;
            pData->iBackimgwidth  = pImage->pImgbuf->iWidth;
            pData->iBackimgheight = pImage->pImgbuf->iHeight;
            pData->iRow           = 0; /* start at the top again !! */
                                       /* determine background object retrieval routine */
            switch (pImage->pImgbuf->iColortype)
            {
              case  0 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                          pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                          break;
                        }

              case  2 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                          pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                          break;
                        }

              case  3 : { pData->fRetrieverow   = (mng_fptr)mng_retrieve_idx8;
                          pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                          break;
                        }

              case  4 : { 
#ifndef MNG_NO_16BIT_SUPPORT
			if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                          pData->bIsOpaque      = MNG_FALSE;
                          break;
                        }

              case  6 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;

                          pData->bIsOpaque      = MNG_FALSE;
                          break;
                        }

              case  8 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                          pData->bIsOpaque      = MNG_TRUE;
                          break;
                        }

              case 10 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                          pData->bIsOpaque      = MNG_TRUE;
                          break;
                        }

              case 12 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                          pData->bIsOpaque      = MNG_FALSE;
                          break;
                        }

              case 14 : {
#ifndef MNG_NO_16BIT_SUPPORT
                          if (pImage->pImgbuf->iBitdepth > 8)
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                          else
#endif
                            pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;

                          pData->bIsOpaque      = MNG_FALSE;
                          break;
                        }
            }

#ifdef MNG_NO_CMS
            iRetcode = MNG_NOERROR;
#else
#if defined(MNG_FULL_CMS)              /* determine color-management routine */
            iRetcode = mng_init_full_cms   (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_GAMMA_ONLY)
            iRetcode = mng_init_gamma_only (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_APP_CMS)
            iRetcode = mng_init_app_cms    (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#endif
            if (iRetcode)              /* on error bail out */
              return iRetcode;
#endif /* MNG_NO_CMS */
                                       /* get temporary row-buffers */
            MNG_ALLOC (pData, pData->pPrevrow, pData->iRowsize);
            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_restore_bkgd_backimage (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 = mng_next_row (pData);

              iY++;                    /* and next line */
            }
                                       /* drop temporary row-buffers */
            MNG_FREE (pData, pData->pRGBArow, pData->iRowsize);
            MNG_FREE (pData, pData->pPrevrow, pData->iRowsize);

            if (iRetcode)              /* on error bail out */
              return iRetcode;

#if defined(MNG_FULL_CMS)              /* cleanup cms stuff */
            iRetcode = mng_clear_cms (pData);

            if (iRetcode)              /* on error bail out */
              return iRetcode;
#endif
          }
        }
      }
#endif
    }

    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->pPrevrow     = pPrevrow;
    pData->pRGBArow     = pRGBArow;
    pData->bIsRGBA16    = bIsRGBA16;
    pData->bIsOpaque    = bIsOpaque;
    pData->fCorrectrow  = fCorrectrow;
    pData->fDisplayrow  = fDisplayrow; 
    pData->fRetrieverow = fRetrieverow;
    pData->pCurrentobj  = pCurrentobj;
    pData->pRetrieveobj = pRetrieveobj;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_LOAD_BKGDLAYER, MNG_LC_END);
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

MNG_LOCAL 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 = mng_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_LOCAL 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 ? */
  {
#ifndef MNG_SKIPCHUNK_FRAM
    mng_uint8 iOldmode = pData->iFramemode;
                                       /* interframe delay required ? */
    if ((iOldmode == 2) || (iOldmode == 4))
    {
      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 = pData->iFRAMdelay;

      if (iChangedelay == 2)           /* also overall ? */
        pData->iFRAMdelay = iDelay;
    }
    else
    {                                  /* reload default */
      pData->iNextdelay = pData->iFRAMdelay;
    }

    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;
    }
#endif
  }

  if (!pData->bTimerset)               /* timer still off ? */
  {
    if (
#ifndef MNG_SKIPCHUNK_FRAM
       (pData->iFramemode == 4) ||    /* insert background layer after a new frame */
#endif
        (!pData->iLayerseq))           /* and certainly before the very first layer */
      iRetcode = load_bkgdlayer (pData);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

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

#ifndef MNG_SKIPCHUNK_FRAM
  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;
  }
#endif

  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);
        pData->iLayerseq++;            /* and it counts as a layer then ! */
      }
    }
#ifndef MNG_SKIPCHUNK_FRAM
    else
    if (pData->iFramemode == 3)        /* restore background for each layer ? */
      iRetcode = load_bkgdlayer (pData);
#endif

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

#ifndef MNG_NO_DELTA_PNG
    if (pData->bHasDHDR)               /* processing a delta-image ? */
      pImage = (mng_imagep)pData->pDeltaImage;
    else
#endif
      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);
    }

#ifndef MNG_SKIPCHUNK_FRAM
    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);
    }
#endif

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

    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 mng_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 ? */
#ifndef MNG_SKIPCHUNK_MAGN
  if (((pData->bRunning) || (pData->bSearching)) && (!pData->bSkipping))
  {
    if ( (!pData->iBreakpoint) &&      /* needs magnification ? */
         ( (pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY) ) )
    {
      iRetcode = mng_magnify_imageobject (pData, pImage);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
  }
#endif

  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;

    pData->iLayerseq++;                /* and it counts as a layer then ! */
  }
                                       /* actively running ? */
  if (((pData->bRunning) || (pData->bSearching)) && (!pData->bSkipping))
  {
    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 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }

          case  2 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }


          case  3 : { pData->fRetrieverow   = (mng_fptr)mng_retrieve_idx8;
                      pData->bIsOpaque      = (mng_bool)(!pImage->pImgbuf->bHasTRNS);
                      break;
                    }


          case  4 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }


          case  6 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }

          case  8 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                      pData->bIsOpaque      = MNG_TRUE;
                      break;
                    }

          case 10 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                      pData->bIsOpaque      = MNG_TRUE;
                      break;
                    }


          case 12 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                      pData->bIsOpaque      = MNG_FALSE;
                      break;
                    }


          case 14 : {
#ifndef MNG_NO_16BIT_SUPPORT
                      if (pImage->pImgbuf->iBitdepth > 8)
                        pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                      else
#endif
                        pData->fRetrieverow = (mng_fptr)mng_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 ? */
#ifndef MNG_NO_16BIT_SUPPORT
        if (pImage->pImgbuf->iBitdepth > 8)
        {
          pData->bIsRGBA16 = MNG_TRUE;
          pData->iRowsize  = pData->iRowsamples << 3;
        }
#endif

        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 = mng_init_full_cms   (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_GAMMA_ONLY)
        iRetcode = mng_init_gamma_only (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_APP_CMS)
        iRetcode = mng_init_app_cms    (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#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 = mng_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_FULL_CMS)              /* 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 ! */
}

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
mng_retcode mng_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;
  mng_ptr        pSaveRGBA;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_EXECUTE_DELTA_IMAGE, MNG_LC_START);
#endif
                                       /* actively running ? */
  if (((pData->bRunning) || (pData->bSearching)) && (!pData->bSkipping))
  {
    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 */
    }

#ifndef MNG_SKIPCHUNK_bKGD
    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;
    }
#endif

    if (pBufdelta->bHasGAMA)           /* gamma in source ? */
    {
      pBuftarget->bHasGAMA = MNG_TRUE; /* drop it onto the target */
      pBuftarget->iGamma   = pBufdelta->iGamma;
    }

#ifndef MNG_SKIPCHUNK_cHRM
    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;
    }
#endif

#ifndef MNG_SKIPCHUNK_sRGB
    if (pBufdelta->bHasSRGB)           /* sRGB in delta ? */
    {                                  /* drop it onto the target */
      pBuftarget->bHasSRGB         = MNG_TRUE;
      pBuftarget->iRenderingintent = pBufdelta->iRenderingintent;
    }
#endif

#ifndef MNG_SKIPCHUNK_iCCP
    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 its length as well */
      pBuftarget->iProfilesize = pBufdelta->iProfilesize;
    }
#endif
                                       /* need to execute delta pixels ? */
    if ((!pData->bDeltaimmediate) && (pData->iDeltatype != MNG_DELTATYPE_NOCHANGE))
    {
      pData->fScalerow = MNG_NULL;     /* not needed by default */

      switch (pBufdelta->iBitdepth)    /* determine scaling routine */
      {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
        case  1 : {
                    switch (pBuftarget->iBitdepth)
                    {
                      case  2 : { pData->fScalerow = (mng_fptr)mng_scale_g1_g2;  break; }
                      case  4 : { pData->fScalerow = (mng_fptr)mng_scale_g1_g4;  break; }

                      case  8 : { pData->fScalerow = (mng_fptr)mng_scale_g1_g8;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
                      case 16 : { pData->fScalerow = (mng_fptr)mng_scale_g1_g16; break; }
#endif
                    }
                    break;
                  }

        case  2 : {
                    switch (pBuftarget->iBitdepth)
                    {
                      case  1 : { pData->fScalerow = (mng_fptr)mng_scale_g2_g1;  break; }
                      case  4 : { pData->fScalerow = (mng_fptr)mng_scale_g2_g4;  break; }
                      case  8 : { pData->fScalerow = (mng_fptr)mng_scale_g2_g8;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
                      case 16 : { pData->fScalerow = (mng_fptr)mng_scale_g2_g16; break; }
#endif
                    }
                    break;
                  }

        case  4 : {
                    switch (pBuftarget->iBitdepth)
                    {
                      case  1 : { pData->fScalerow = (mng_fptr)mng_scale_g4_g1;  break; }
                      case  2 : { pData->fScalerow = (mng_fptr)mng_scale_g4_g2;  break; }
                      case  8 : { pData->fScalerow = (mng_fptr)mng_scale_g4_g8;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
                      case 16 : { pData->fScalerow = (mng_fptr)mng_scale_g4_g16; break; }
#endif
                    }
                    break;
                  }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */

        case  8 : {
                    switch (pBufdelta->iColortype)
                    {
                      case  0 : ;
                      case  3 : ;
                      case  8 : {
                                  switch (pBuftarget->iBitdepth)
                                  {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                                    case  1 : { pData->fScalerow = (mng_fptr)mng_scale_g8_g1;  break; }
                                    case  2 : { pData->fScalerow = (mng_fptr)mng_scale_g8_g2;  break; }
                                    case  4 : { pData->fScalerow = (mng_fptr)mng_scale_g8_g4;  break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
#ifndef MNG_NO_16BIT_SUPPORT
                                    case 16 : { pData->fScalerow = (mng_fptr)mng_scale_g8_g16; break; }
#endif
                                  }
                                  break;
                                }
                      case  2 : ;
                      case 10 : {
#ifndef MNG_NO_16BIT_SUPPORT
                                  if (pBuftarget->iBitdepth == 16)
                                    pData->fScalerow = (mng_fptr)mng_scale_rgb8_rgb16;
#endif
                                  break;
                                }
                      case  4 : ;
                      case 12 : {
#ifndef MNG_NO_16BIT_SUPPORT
                                  if (pBuftarget->iBitdepth == 16)
                                    pData->fScalerow = (mng_fptr)mng_scale_ga8_ga16;
#endif
                                  break;
                                }
                      case  6 : ;
                      case 14 : {
#ifndef MNG_NO_16BIT_SUPPORT
                                  if (pBuftarget->iBitdepth == 16)
                                    pData->fScalerow = (mng_fptr)mng_scale_rgba8_rgba16;
#endif
                                  break;
                                }
                    }
                    break;
                  }

#ifndef MNG_NO_16BIT_SUPPORT
        case 16 : {
                    switch (pBufdelta->iColortype)
                    {
                      case  0 : ;
                      case  3 : ;
                      case  8 : {
                                  switch (pBuftarget->iBitdepth)
                                  {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                                    case 1 : { pData->fScalerow = (mng_fptr)mng_scale_g16_g1; break; }
                                    case 2 : { pData->fScalerow = (mng_fptr)mng_scale_g16_g2; break; }
                                    case 4 : { pData->fScalerow = (mng_fptr)mng_scale_g16_g4; break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                                    case 8 : { pData->fScalerow = (mng_fptr)mng_scale_g16_g8; break; }
                                  }
                                  break;
                                }
                      case  2 : ;
                      case 10 : {
                                  if (pBuftarget->iBitdepth == 8)
                                    pData->fScalerow = (mng_fptr)mng_scale_rgb16_rgb8;
                                  break;
                                }
                      case  4 : ;
                      case 12 : {
                                  if (pBuftarget->iBitdepth == 8)
                                    pData->fScalerow = (mng_fptr)mng_scale_ga16_ga8;
                                  break;
                                }
                      case  6 : ;
                      case 14 : {
                                  if (pBuftarget->iBitdepth == 8)
                                    pData->fScalerow = (mng_fptr)mng_scale_rgba16_rgba8;
                                  break;
                                }
                    }
                    break;
                  }
#endif

      }

      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)
                        {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                          case  1 : { pData->fDeltarow = (mng_fptr)mng_delta_g1_g1;   break; }
                          case  2 : { pData->fDeltarow = (mng_fptr)mng_delta_g2_g2;   break; }
                          case  4 : { pData->fDeltarow = (mng_fptr)mng_delta_g4_g4;   break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                          case  8 : { pData->fDeltarow = (mng_fptr)mng_delta_g8_g8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_g16_g16; break; }
#endif
                        }
                      }
                    }

                    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)mng_delta_rgb8_rgb8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_rgb16_rgb16; break; }
#endif
                        }
                      }
                    }

                    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)
                        {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                          case  1 : { pData->fDeltarow = (mng_fptr)mng_delta_g1_g1; break; }
                          case  2 : { pData->fDeltarow = (mng_fptr)mng_delta_g2_g2; break; }
                          case  4 : { pData->fDeltarow = (mng_fptr)mng_delta_g4_g4; break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                          case  8 : { pData->fDeltarow = (mng_fptr)mng_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)mng_delta_ga8_ga8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_ga16_ga16; break; }
#endif
                        }
                      }
                    }
                    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)mng_delta_ga8_g8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_ga16_g16; break; }
#endif
                        }
                      }
                    }
                    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)mng_delta_ga8_a8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_ga16_a16; break; }
#endif
                        }
                      }
                    }

                    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)mng_delta_rgba8_rgba8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_rgba16_rgba16; break; }
#endif
                        }
                      }
                    }
                    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)mng_delta_rgba8_rgb8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_rgba16_rgb16; break; }
#endif
                        }
                      }
                    }
                    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)mng_delta_rgba8_a8;   break; }
#ifndef MNG_NO_16BIT_SUPPORT
                          case 16 : { pData->fDeltarow = (mng_fptr)mng_delta_rgba16_a16; break; }
#endif
                        }
                      }
                    }

                    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;

        pSaveRGBA = pData->pRGBArow;   /* save current temp-buffer! */
                                       /* get a temporary row-buffer */
        MNG_ALLOC (pData, pData->pRGBArow, (pBufdelta->iRowsize << 1));

        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 = mng_next_row (pData);

          iY++;                        /* and next line */
        }
                                       /* drop the temporary row-buffer */
        MNG_FREE (pData, pData->pRGBArow, (pBufdelta->iRowsize << 1));
        pData->pRGBArow = pSaveRGBA;   /* restore saved temp-buffer! */

        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;
}
#endif /* MNG_NO_DELTA_PNG */

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_SAVE
MNG_LOCAL 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 */

#ifndef MNG_SKIPCHUNK_BACK
  pSave->iBACKred             = pData->iBACKred;
  pSave->iBACKgreen           = pData->iBACKgreen;
  pSave->iBACKblue            = pData->iBACKblue;
  pSave->iBACKmandatory       = pData->iBACKmandatory;
  pSave->iBACKimageid         = pData->iBACKimageid;
  pSave->iBACKtile            = pData->iBACKtile;
#endif

#ifndef MNG_SKIPCHUNK_FRAM
  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;
#endif

  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;

#ifndef MNG_SKIPCHUNK_cHRM
  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;
#endif

#ifndef MNG_SKIPCHUNK_sRGB
  pSave->iGlobalRendintent    = pData->iGlobalRendintent;
#endif

#ifndef MNG_SKIPCHUNK_iCCP
  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);
  }
#endif

#ifndef MNG_SKIPCHUNK_bKGD
  pSave->iGlobalBKGDred       = pData->iGlobalBKGDred;
  pSave->iGlobalBKGDgreen     = pData->iGlobalBKGDgreen;
  pSave->iGlobalBKGDblue      = pData->iGlobalBKGDblue;
#endif

                                       /* freeze current image objects */
  pImage = (mng_imagep)pData->pFirstimgobj;

  while (pImage)
  {                                    /* freeze the object AND its 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;
}
#endif

/* ************************************************************************** */

mng_retcode mng_reset_objzero (mng_datap pData)
{
  mng_imagep  pImage   = (mng_imagep)pData->pObjzero;
  mng_retcode iRetcode = mng_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;
#ifndef MNG_SKIPCHUNK_MAGN
  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;
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

MNG_LOCAL mng_retcode restore_state (mng_datap pData)
{
#ifndef MNG_SKIPCHUNK_SAVE
  mng_savedatap pSave;
#endif
  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;

#ifndef MNG_SKIPCHUNK_SAVE
  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 */

#ifndef MNG_SKIPCHUNK_BACK
    pData->iBACKred             = pSave->iBACKred;
    pData->iBACKgreen           = pSave->iBACKgreen;
    pData->iBACKblue            = pSave->iBACKblue;
    pData->iBACKmandatory       = pSave->iBACKmandatory;
    pData->iBACKimageid         = pSave->iBACKimageid;
    pData->iBACKtile            = pSave->iBACKtile;
#endif

#ifndef MNG_SKIPCHUNK_FRAM
    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;
                                       /* NOOOOOOOOOOOO */
/*    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->iNextdelay           = pData->iFramedelay;
#endif

    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;

#ifndef MNG_SKIPCHUNK_cHRM
    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;
#endif

    pData->iGlobalRendintent    = pSave->iGlobalRendintent;

#ifndef MNG_SKIPCHUNK_iCCP
    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);
    }
#endif

#ifndef MNG_SKIPCHUNK_bKGD
    pData->iGlobalBKGDred       = pSave->iGlobalBKGDred;
    pData->iGlobalBKGDgreen     = pSave->iGlobalBKGDgreen;
    pData->iGlobalBKGDblue      = pSave->iGlobalBKGDblue;
#endif
  }
  else                                 /* no saved-data; so reset the lot */
#endif /* SKIPCHUNK_SAVE */
  {
#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 */

#ifndef MNG_SKIPCHUNK_TERM
    if (!pData->bMisplacedTERM)        /* backward compatible ugliness !!! */
    {
      pData->iBACKred           = 0;
      pData->iBACKgreen         = 0;
      pData->iBACKblue          = 0;
      pData->iBACKmandatory     = 0;
      pData->iBACKimageid       = 0;
      pData->iBACKtile          = 0;
    }
#endif

#ifndef MNG_SKIPCHUNK_FRAM
    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;
                                       /* NOOOOOOOOOOOO */
/*    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->iNextdelay           = pData->iFramedelay;
#endif

    pData->iGlobalPLTEcount     = 0;

    pData->iGlobalTRNSrawlen    = 0;

    pData->iGlobalGamma         = 0;

#ifndef MNG_SKIPCHUNK_cHRM
    pData->iGlobalWhitepointx   = 0;
    pData->iGlobalWhitepointy   = 0;
    pData->iGlobalPrimaryredx   = 0;
    pData->iGlobalPrimaryredy   = 0;
    pData->iGlobalPrimarygreenx = 0;
    pData->iGlobalPrimarygreeny = 0;
    pData->iGlobalPrimarybluex  = 0;
    pData->iGlobalPrimarybluey  = 0;
#endif

    pData->iGlobalRendintent    = 0;

#ifndef MNG_SKIPCHUNK_iCCP
    if (pData->iGlobalProfilesize)     /* free a previous profile ? */
      MNG_FREE (pData, pData->pGlobalProfile, pData->iGlobalProfilesize);

    pData->iGlobalProfilesize   = 0;
#endif

#ifndef MNG_SKIPCHUNK_bKGD
    pData->iGlobalBKGDred       = 0;
    pData->iGlobalBKGDgreen     = 0;
    pData->iGlobalBKGDblue      = 0;
#endif
  }

#ifndef MNG_SKIPCHUNK_TERM
  if (!pData->bMisplacedTERM)          /* backward compatible ugliness !!! */
  {
    pImage = (mng_imagep)pData->pFirstimgobj;
                                       /* drop un-frozen image objects */
    while (pImage)
    {
      mng_imagep pNext = (mng_imagep)pImage->sHeader.pNext;

      if (!pImage->bFrozen)            /* is it un-frozen ? */
      {
        mng_imagep pPrev = (mng_imagep)pImage->sHeader.pPrev;

        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 = mng_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;                  /* neeeext */
    }
  }
#endif

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_RESTORE_STATE, MNG_LC_END);
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */
/* *                                                                        * */
/* * General display processing routine                                     * */
/* *                                                                        * */
/* ************************************************************************** */

mng_retcode mng_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)             /* clear timer-flag when searching !!! */
      pData->bTimerset = MNG_FALSE;
                                       /* do we need to finish something first ? */
    if ((pData->iBreakpoint) && (pData->iBreakpoint < 99))
    {
      switch (pData->iBreakpoint)      /* return to broken display routine */
      {
#ifndef MNG_SKIPCHUNK_FRAM
        case  1 : { iRetcode = mng_process_display_fram2 (pData); break; }
#endif
#ifndef MNG_SKIPCHUNK_SHOW
        case  3 : ;                    /* same as 4 !!! */
        case  4 : { iRetcode = mng_process_display_show  (pData); break; }
#endif
#ifndef MNG_SKIPCHUNK_CLON
        case  5 : { iRetcode = mng_process_display_clon2 (pData); break; }
#endif
#ifndef MNG_SKIPCHUNK_MAGN
        case  9 : { iRetcode = mng_process_display_magn2 (pData); break; }
        case 10 : { iRetcode = mng_process_display_mend2 (pData); break; }
#endif
#ifndef MNG_SKIPCHUNK_PAST
        case 11 : { iRetcode = mng_process_display_past2 (pData); break; }
#endif
        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 = mng_process_display_mend (pData);

      if (!pData->pCurraniobj)         /* refresh after last image ? */
        pData->bNeedrefresh = MNG_TRUE;
    }

    if (pData->bSearching)             /* are we looking for something ? */
    {
      if ((pData->iRequestframe) && (pData->iRequestframe <= pData->iFrameseq))
      {
        pData->iRequestframe = 0;      /* found the frame ! */
        pData->bSearching    = MNG_FALSE;
      }
      else
      if ((pData->iRequestlayer) && (pData->iRequestlayer <= pData->iLayerseq))
      {
        pData->iRequestlayer = 0;      /* found the layer ! */
        pData->bSearching    = MNG_FALSE;
      }
      else
      if ((pData->iRequesttime) && (pData->iRequesttime <= pData->iFrametime))
      {
        pData->iRequesttime  = 0;      /* found the playtime ! */
        pData->bSearching    = MNG_FALSE;
      }
    }
  }                                    /* until error or a break or no more objects */
  while ((!iRetcode) && (pData->pCurraniobj) &&
         (((pData->bRunning) && (!pData->bTimerset)) || (pData->bSearching)) &&
         (!pData->bSectionwait) && (!pData->bFreezing));

  if (iRetcode)                        /* on error bail out */
    return iRetcode;
                                       /* refresh needed ? */
  if ((!pData->bTimerset) && (pData->bNeedrefresh))
  {
    iRetcode = mng_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                                      * */
/* *                                                                        * */
/* ************************************************************************** */

#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
png_imgtype mng_png_imgtype(mng_uint8 colortype, mng_uint8 bitdepth)
{
  png_imgtype ret;
  switch (bitdepth)
  {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
    case 1:
    {
      png_imgtype imgtype[]={png_g1,png_none,png_none,png_idx1};
      ret=imgtype[colortype];
      break;
    }
    case 2:
    {
      png_imgtype imgtype[]={png_g2,png_none,png_none,png_idx2};
      ret=imgtype[colortype];
      break;
    }
    case 4:
    {
      png_imgtype imgtype[]={png_g4,png_none,png_none,png_idx4};
      ret=imgtype[colortype];
      break;
    }
#endif
    case 8:
    {
      png_imgtype imgtype[]={png_g8,png_none,png_rgb8,png_idx8,png_ga8,
          png_none,png_rgba8};
      ret=imgtype[colortype];
      break;
    }
#ifndef MNG_NO_16BIT_SUPPORT
    case 16:
    {
      png_imgtype imgtype[]={png_g16,png_none,png_rgb16,png_none,png_ga16,
          png_none,png_rgba16};
      ret=imgtype[colortype];
      break;
    }
#endif
    default:
      ret=png_none;
      break;
  }
  return (ret);
}
#endif /* MNG_OPTIMIZE_FOOTPRINT_INIT */

/* ************************************************************************** */

mng_retcode mng_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;

#ifndef MNG_NO_DELTA_PNG
    if (pData->bHasDHDR)               /* is a delta-image ? */
    {
      if (pData->iDeltatype == MNG_DELTATYPE_REPLACE)
        iRetcode = mng_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;

      if (!iRetcode)
      {                                /* process immediately 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)    );
                                       /* be sure to reset object 0 */
        iRetcode = mng_reset_object_details (pData, (mng_imagep)pData->pObjzero,
                                             pData->iDatawidth, pData->iDataheight,
                                             pData->iBitdepth, pData->iColortype,
                                             pData->iCompression, pData->iFilter,
                                             pData->iInterlace, MNG_TRUE);
      }
    }
    else
#endif
    {
      if (pImage)                      /* update object buffer ? */
        iRetcode = mng_reset_object_details (pData, pImage,
                                             pData->iDatawidth, pData->iDataheight,
                                             pData->iBitdepth, pData->iColortype,
                                             pData->iCompression, pData->iFilter,
                                             pData->iInterlace, MNG_TRUE);
      else
        iRetcode = mng_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;
  }

#ifndef MNG_NO_DELTA_PNG
  if (!pData->bHasDHDR)
#endif
  {
    if (pImage)                        /* real object ? */
      pData->pStoreobj = pImage;       /* tell the row routines */
    else                               /* otherwise use object 0 */
      pData->pStoreobj = pData->pObjzero;

#if !defined(MNG_INCLUDE_MPNG_PROPOSAL) && !defined(MNG_INCLUDE_ANG_PROPOSAL)
    if (                               /* display "on-the-fly" ? */
#ifndef MNG_SKIPCHUNK_MAGN
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) &&
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) &&
#endif
         ( (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 */
      }
    }
#endif
  }

  if (!pData->bTimerset)               /* no timer break ? */
  {
#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
    pData->fInitrowproc = (mng_fptr)mng_init_rowproc;
    pData->ePng_imgtype=mng_png_imgtype(pData->iColortype,pData->iBitdepth);
#else
    switch (pData->iColortype)         /* determine row initialization routine */
    {
      case 0 : {                       /* gray */
                 switch (pData->iBitdepth)
                 {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                   case  1 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_g1_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_g1_i;

                               break;
                             }
                   case  2 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_g2_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_g2_i;

                               break;
                             }
                   case  4 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_g4_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_g4_i;
                               break;
                             }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_g8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_g8_i;

                               break;
                             }
#ifndef MNG_NO_16BIT_SUPPORT
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_g16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_g16_i;

                               break;
                             }
#endif
                 }

                 break;
               }
      case 2 : {                       /* rgb */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgb8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgb8_i;
                               break;
                             }
#ifndef MNG_NO_16BIT_SUPPORT
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgb16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgb16_i;

                               break;
                             }
#endif
                 }

                 break;
               }
      case 3 : {                       /* indexed */
                 switch (pData->iBitdepth)
                 {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                   case  1 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx1_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx1_i;

                               break;
                             }
                   case  2 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx2_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx2_i;

                               break;
                             }
                   case  4 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx4_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx4_i;

                               break;
                             }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_idx8_i;

                               break;
                             }
                 }

                 break;
               }
      case 4 : {                       /* gray+alpha */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_ga8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_ga8_i;

                               break;
                             }
#ifndef MNG_NO_16BIT_SUPPORT
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_ga16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_ga16_i;
                               break;
                             }
#endif
                 }

                 break;
               }
      case 6 : {                       /* rgb+alpha */
                 switch (pData->iBitdepth)
                 {
                   case  8 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgba8_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgba8_i;

                               break;
                             }
#ifndef MNG_NO_16BIT_SUPPORT
                   case 16 : {
                               if (!pData->iInterlace)
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgba16_ni;
                               else
                                 pData->fInitrowproc = (mng_fptr)mng_init_rgba16_i;

                               break;
                             }
#endif
                 }

                 break;
               }
    }
#endif /* MNG_OPTIMIZE_FOOTPRINT_INIT */

    pData->iFilterofs = 0;             /* determine filter characteristics */
    pData->iLevel0    = 0;             /* default levels */
    pData->iLevel1    = 0;    
    pData->iLevel2    = 0;
    pData->iLevel3    = 0;

#ifdef FILTER192                       /* leveling & differing ? */
    if (pData->iFilter == MNG_FILTER_DIFFERING)
    {
      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->iFilterofs = 4;
                   else
                     pData->iFilterofs = 8;

                   break;
                 }
      }
    }
#endif

#ifdef FILTER193                       /* no adaptive filtering ? */
    if (pData->iFilter == MNG_FILTER_NOFILTER)
      pData->iPixelofs = pData->iFilterofs;
    else
#endif    
      pData->iPixelofs = pData->iFilterofs + 1;

  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IHDR, MNG_LC_END);
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

#ifdef MNG_INCLUDE_MPNG_PROPOSAL
mng_retcode mng_process_display_mpng (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MPNG, MNG_LC_START);
#endif

  pData->iAlphadepth = 8;              /* assume transparency !! */

  if (pData->fProcessheader)           /* inform the app (creating the output canvas) ? */
  {
    pData->iWidth  = ((mng_mpng_objp)pData->pMPNG)->iFramewidth;
    pData->iHeight = ((mng_mpng_objp)pData->pMPNG)->iFrameheight;

    if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight))
      MNG_ERROR (pData, MNG_APPMISCERROR);
  }

  next_layer (pData);                  /* first mPNG layer then ! */
  pData->bTimerset   = MNG_FALSE;
  pData->iBreakpoint = 0;

  if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt))
    set_display_routine (pData);       /* then determine display routine */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MPNG, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifdef MNG_INCLUDE_ANG_PROPOSAL
mng_retcode mng_process_display_ang (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_ANG, MNG_LC_START);
#endif

  if (pData->fProcessheader)           /* inform the app (creating the output canvas) ? */
  {
    if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight))
      MNG_ERROR (pData, MNG_APPMISCERROR);
  }

  next_layer (pData);                  /* first mPNG layer then ! */
  pData->bTimerset   = MNG_FALSE;
  pData->iBreakpoint = 0;

  if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt))
    set_display_routine (pData);       /* then determine display routine */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_ANG, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_idat (mng_datap  pData,
                                      mng_uint32 iRawlen,
                                      mng_uint8p pRawdata)
#else
mng_retcode mng_process_display_idat (mng_datap  pData)
#endif
{
  mng_retcode iRetcode = MNG_NOERROR;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IDAT, MNG_LC_START);
#endif

#if defined(MNG_INCLUDE_MPNG_PROPOSAL) || defined(MNG_INCLUDE_ANG_PROPOSAL) 
  if ((pData->eImagetype == mng_it_png) && (pData->iLayerseq <= 0))
  {
    if (pData->fProcessheader)         /* inform the app (creating the output canvas) ? */
      if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight))
        MNG_ERROR (pData, MNG_APPMISCERROR);

    next_layer (pData);                /* first regular PNG layer then ! */
    pData->bTimerset   = MNG_FALSE;
    pData->iBreakpoint = 0;

    if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt))
      set_display_routine (pData);     /* then determine display routine */
  }
#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;

    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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    iRetcode = mngzlib_inflaterows (pData, iRawlen, pRawdata);
#else
    iRetcode = mngzlib_inflaterows (pData, pData->iRawlen, pData->pRawdata);
#endif

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

#ifndef MNG_SKIPCHUNK_MAGN
  if ( (pData->pStoreobj) &&           /* on-the-fly magnification ? */
       ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX) ||
         (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY)    ) )
    bMagnify = MNG_TRUE;
#endif

  if ((pData->bHasBASI) ||             /* was it a BASI stream */
      (bDodisplay)      ||             /* or should we display the JNG */
#ifndef MNG_SKIPCHUNK_MAGN
      (bMagnify)        ||             /* or should we magnify it */
#endif
                                       /* 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 = mng_display_image (pData, pImage, bDodisplay);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 6;
    }
  }
#ifndef MNG_NO_DELTA_PNG
  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 = mng_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 = mng_display_image (pData, pImage, MNG_FALSE);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 8;
    }
  }
#endif

  if (!pData->bTimerset)               /* can we continue ? */
  {
    pData->iBreakpoint = 0;            /* clear this flag now ! */


#ifdef MNG_INCLUDE_MPNG_PROPOSAL
    if (pData->eImagetype == mng_it_mpng)
    {
      pData->pCurraniobj = pData->pFirstaniobj;
    } else
#endif
#ifdef MNG_INCLUDE_ANG_PROPOSAL
    if (pData->eImagetype == mng_it_ang)
    {
      pData->pCurraniobj = pData->pFirstaniobj;
    } else
#endif
    {                                  /* cleanup object 0 */
      mng_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  = mng_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  = mng_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  = mng_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;
}

/* ************************************************************************** */

/* change in the MNG spec with regards to TERM delay & interframe_delay
   as proposed by Adam M. Costello (option 4) and finalized by official vote
   during december 2002 / check the 'mng-list' archives for more details */

mng_retcode mng_process_display_mend (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_START);
#endif

  pData->bForcedelay = pData->iAccumdelay ? MNG_FALSE : MNG_TRUE;
  pData->iAccumdelay = 0;

#ifdef MNG_SUPPORT_DYNAMICMNG
  if (pData->bStopafterseek)           /* need to stop after this ? */
  {
    pData->bFreezing      = MNG_TRUE;  /* stop processing on this one */
    pData->bRunningevent  = MNG_FALSE;
    pData->bStopafterseek = MNG_FALSE;
    pData->bNeedrefresh   = MNG_TRUE;  /* make sure the last bit is displayed ! */
  }
#endif

#ifndef MNG_SKIPCHUNK_TERM
                                       /* 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 */
                                       /* max(1, TERM delay, interframe_delay) */
#ifndef MNG_SKIPCHUNK_FRAM
                 if (pTERM->iDelay > pData->iFramedelay)
                   pData->iFramedelay = pTERM->iDelay;
                 if (!pData->iFramedelay)
                   pData->iFramedelay = 1;
#endif

                 iRetcode = interframe_delay (pData);
                                       /* no interframe_delay? then fake it */
                 if ((!iRetcode) && (!pData->bTimerset))
                   iRetcode = set_delay (pData, 1);

                 if (iRetcode)
                   return iRetcode;

                 pData->iBreakpoint = 10;
                 break;
               }

      case 2 : {                       /* show first image after TERM */
                 iRetcode = restore_state (pData);

                 if (iRetcode)         /* on error bail out */
                   return iRetcode;
                                       /* notify the app ? */
                 if (pData->fProcessmend)
                   if (!pData->fProcessmend ((mng_handle)pData, pData->iIterations, 0))
                     MNG_ERROR (pData, MNG_APPMISCERROR);

                                       /* show first frame after TERM chunk */
                 pData->pCurraniobj      = pTERM;
                 pData->bOnlyfirstframe  = MNG_TRUE;
                 pData->iFramesafterTERM = 0;

                                       /* max(1, TERM delay, interframe_delay) */
#ifndef MNG_SKIPCHUNK_FRAM
                 if (pTERM->iDelay > pData->iFramedelay)
                   pData->iFramedelay = pTERM->iDelay;
                 if (!pData->iFramedelay)
                   pData->iFramedelay = 1;
#endif

                 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)
                     if (!pData->fProcessmend ((mng_handle)pData,
                                               pData->iIterations, pTERM->iItermax))
                       MNG_ERROR (pData, MNG_APPMISCERROR);

                                       /* restart from TERM chunk */
                   pData->pCurraniobj = pTERM;

                   if (pTERM->iDelay)  /* set the delay (?) */
                   {
                                       /* max(1, TERM delay, interframe_delay) */
#ifndef MNG_SKIPCHUNK_FRAM
                     if (pTERM->iDelay > pData->iFramedelay)
                       pData->iFramedelay = pTERM->iDelay;
                     if (!pData->iFramedelay)
                       pData->iFramedelay = 1;
#endif

                     pData->bNeedrefresh = MNG_TRUE;
                   }
                 }
                 else
                 {
                   switch (pTERM->iIteraction)
                   {
                     case 0 : {        /* show last frame indefinitly */
                                break; /* piece of cake, that is... */
                              }

                     case 1 : {        /* cease displaying anything */
                                       /* max(1, TERM delay, interframe_delay) */
#ifndef MNG_SKIPCHUNK_FRAM
                                if (pTERM->iDelay > pData->iFramedelay)
                                  pData->iFramedelay = pTERM->iDelay;
                                if (!pData->iFramedelay)
                                  pData->iFramedelay = 1;
#endif

                                iRetcode = interframe_delay (pData);
                                       /* no interframe_delay? then fake it */
                                if ((!iRetcode) && (!pData->bTimerset))
                                  iRetcode = set_delay (pData, 1);

                                if (iRetcode)
                                  return iRetcode;

                                pData->iBreakpoint = 10;
                                break;
                              }

                     case 2 : {        /* show first image after TERM */
                                iRetcode = restore_state (pData);
                                       /* on error bail out */
                                if (iRetcode)
                                  return iRetcode;
                                       /* notify the app ? */
                                if (pData->fProcessmend)
                                  if (!pData->fProcessmend ((mng_handle)pData,
                                                            pData->iIterations, 0))
                                    MNG_ERROR (pData, MNG_APPMISCERROR);

                                       /* show first frame after TERM chunk */
                                pData->pCurraniobj      = pTERM;
                                pData->bOnlyfirstframe  = MNG_TRUE;
                                pData->iFramesafterTERM = 0;
                                       /* max(1, TERM delay, interframe_delay) */
#ifndef MNG_SKIPCHUNK_FRAM
                                if (pTERM->iDelay > pData->iFramedelay)
                                  pData->iFramedelay = pTERM->iDelay;
                                if (!pData->iFramedelay)
                                  pData->iFramedelay = 1;
#endif

                                break;
                              }
                   }
                 }

                 break;
               }
    }
  }
#endif /* MNG_SKIPCHUNK_TERM */
                                       /* just reading ? */
  if ((!pData->bDisplaying) && (pData->bReading))
    if (pData->fProcessmend)           /* inform the app ? */
      if (!pData->fProcessmend ((mng_handle)pData, 0, 0))
        MNG_ERROR (pData, MNG_APPMISCERROR);

  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 mng_process_display_mend2 (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_START);
#endif

#ifndef MNG_SKIPCHUNK_FRAM
  pData->bFrameclipping = MNG_FALSE;   /* nothing to do but restore the app background */
#endif
  load_bkgdlayer (pData);

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_END);
#endif

  return MNG_NOERROR;
}

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_DEFI
mng_retcode mng_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)mng_find_imageobject (pData, pData->iDEFIobjectid);

    if (!pImage)                       /* if not; create new */
    {
      mng_retcode iRetcode = mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_BASI
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_basi (mng_datap  pData,
                                      mng_uint16 iRed,
                                      mng_uint16 iGreen,
                                      mng_uint16 iBlue,
                                      mng_bool   bHasalpha,
                                      mng_uint16 iAlpha,
                                      mng_uint8  iViewable)
#else
mng_retcode mng_process_display_basi (mng_datap  pData)
#endif
{                                      /* 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 = mng_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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  pImage->bViewable = (mng_bool)(iViewable == 1);
#else
  pImage->bViewable = (mng_bool)(pData->iBASIviewable == 1);
#endif
  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 */
#ifndef MNG_NO_16BIT_SUPPORT
               if (pData->iBitdepth == 16)
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   mng_put_uint16 (pWork, iRed);
#else
                   mng_put_uint16 (pWork, pData->iBASIred);
#endif
                   pWork += 2;
                 }
               }
               else
#endif
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   *pWork = (mng_uint8)iRed;
#else
                   *pWork = (mng_uint8)pData->iBASIred;
#endif
                   pWork++;
                 }
               }
                                       /* force tRNS ? */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
               if ((bHasalpha) && (!iAlpha))
#else
               if ((pData->bBASIhasalpha) && (!pData->iBASIalpha))
#endif
               {
                 pBuf->bHasTRNS  = MNG_TRUE;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                 pBuf->iTRNSgray = iRed;
#else
                 pBuf->iTRNSgray = pData->iBASIred;
#endif
               }

               break;
             }

    case 2 : {                         /* rgb */
#ifndef MNG_NO_16BIT_SUPPORT
               if (pData->iBitdepth == 16)
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   mng_put_uint16 (pWork,   iRed  );
                   mng_put_uint16 (pWork+2, iGreen);
                   mng_put_uint16 (pWork+4, iBlue );
#else
                   mng_put_uint16 (pWork,   pData->iBASIred  );
                   mng_put_uint16 (pWork+2, pData->iBASIgreen);
                   mng_put_uint16 (pWork+4, pData->iBASIblue );
#endif
                   pWork += 6;
                 }
               }
               else
#endif
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iGreen;
                   *(pWork+2) = (mng_uint8)iBlue;
#else
                   *pWork     = (mng_uint8)pData->iBASIred;
                   *(pWork+1) = (mng_uint8)pData->iBASIgreen;
                   *(pWork+2) = (mng_uint8)pData->iBASIblue;
#endif
                   pWork += 3;
                 }
               }
                                       /* force tRNS ? */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
               if ((bHasalpha) && (!iAlpha))
#else
               if ((pData->bBASIhasalpha) && (!pData->iBASIalpha))
#endif
               {
                 pBuf->bHasTRNS   = MNG_TRUE;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                 pBuf->iTRNSred   = iRed;
                 pBuf->iTRNSgreen = iGreen;
                 pBuf->iTRNSblue  = iBlue;
#else
                 pBuf->iTRNSred   = pData->iBASIred;
                 pBuf->iTRNSgreen = pData->iBASIgreen;
                 pBuf->iTRNSblue  = pData->iBASIblue;
#endif
               }

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

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
               pBuf->aPLTEentries [0].iRed   = (mng_uint8)iRed;
               pBuf->aPLTEentries [0].iGreen = (mng_uint8)iGreen;
               pBuf->aPLTEentries [0].iBlue  = (mng_uint8)iBlue;
#else
               pBuf->aPLTEentries [0].iRed   = (mng_uint8)pData->iBASIred;
               pBuf->aPLTEentries [0].iGreen = (mng_uint8)pData->iBASIgreen;
               pBuf->aPLTEentries [0].iBlue  = (mng_uint8)pData->iBASIblue;
#endif

               for (iX = 1; iX < pBuf->iPLTEcount; iX++)
               {
                 pBuf->aPLTEentries [iX].iRed   = 0;
                 pBuf->aPLTEentries [iX].iGreen = 0;
                 pBuf->aPLTEentries [iX].iBlue  = 0;
               }
                                       /* force tRNS ? */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
               if ((bHasalpha) && (iAlpha < 255))
#else
               if ((pData->bBASIhasalpha) && (pData->iBASIalpha < 255))
#endif
               {
                 pBuf->bHasTRNS         = MNG_TRUE;
                 pBuf->iTRNScount       = 1;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                 pBuf->aTRNSentries [0] = (mng_uint8)iAlpha;
#else
                 pBuf->aTRNSentries [0] = (mng_uint8)pData->iBASIalpha;
#endif
               }

               break;
             }

    case 4 : {                         /* gray+alpha */
#ifndef MNG_NO_16BIT_SUPPORT
               if (pData->iBitdepth == 16)
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   mng_put_uint16 (pWork,   iRed);
                   mng_put_uint16 (pWork+2, iAlpha);
#else
                   mng_put_uint16 (pWork,   pData->iBASIred);
                   mng_put_uint16 (pWork+2, pData->iBASIalpha);
#endif
                   pWork += 4;
                 }
               }
               else
#endif
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iAlpha;
#else
                   *pWork     = (mng_uint8)pData->iBASIred;
                   *(pWork+1) = (mng_uint8)pData->iBASIalpha;
#endif
                   pWork += 2;
                 }
               }

               break;
             }

    case 6 : {                         /* rgb+alpha */
#ifndef MNG_NO_16BIT_SUPPORT
               if (pData->iBitdepth == 16)
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   mng_put_uint16 (pWork,   iRed);
                   mng_put_uint16 (pWork+2, iGreen);
                   mng_put_uint16 (pWork+4, iBlue);
                   mng_put_uint16 (pWork+6, iAlpha);
#else
                   mng_put_uint16 (pWork,   pData->iBASIred);
                   mng_put_uint16 (pWork+2, pData->iBASIgreen);
                   mng_put_uint16 (pWork+4, pData->iBASIblue);
                   mng_put_uint16 (pWork+6, pData->iBASIalpha);
#endif
                   pWork += 8;
                 }
               }
               else
#endif
               {
#ifdef MNG_DECREMENT_LOOPS
                 for (iX = pData->iDatawidth * pData->iDataheight;
                    iX > 0;iX--)
#else
                 for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++)
#endif
                 {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   *pWork     = (mng_uint8)iRed;
                   *(pWork+1) = (mng_uint8)iGreen;
                   *(pWork+2) = (mng_uint8)iBlue;
                   *(pWork+3) = (mng_uint8)iAlpha;
#else
                   *pWork     = (mng_uint8)pData->iBASIred;
                   *(pWork+1) = (mng_uint8)pData->iBASIgreen;
                   *(pWork+2) = (mng_uint8)pData->iBASIblue;
                   *(pWork+3) = (mng_uint8)pData->iBASIalpha;
#endif
                   pWork += 4;
                 }
               }

               break;
             }

  }

#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
  pData->fInitrowproc = (mng_fptr)mng_init_rowproc;
  pData->ePng_imgtype=mng_png_imgtype(pData->iColortype,pData->iBitdepth);
#else
  switch (pData->iColortype)           /* determine row initialization routine */
  {                                    /* just to accomodate IDAT if it arrives */
    case 0 : {                         /* gray */
               switch (pData->iBitdepth)
               {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                 case  1 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_g1_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_g1_i;

                             break;
                           }
                 case  2 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_g2_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_g2_i;

                             break;
                           }
                 case  4 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_g4_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_g4_i;

                             break;
                           }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_g8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_g8_i;

                             break;
                           }
#ifndef MNG_NO_16BIT_SUPPORT
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_g16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_g16_i;

                             break;
                           }
#endif
               }

               break;
             }
    case 2 : {                         /* rgb */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_rgb8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_rgb8_i;

                             break;
                           }
#ifndef MNG_NO_16BIT_SUPPORT
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_rgb16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_rgb16_i;

                             break;
                           }
#endif
               }

               break;
             }
    case 3 : {                         /* indexed */
               switch (pData->iBitdepth)
               {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                 case  1 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_idx1_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_idx1_i;

                             break;
                           }
                 case  2 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_idx2_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_idx2_i;

                             break;
                           }
                 case  4 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_idx4_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_idx4_i;

                             break;
                           }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_idx8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_idx8_i;

                             break;
                           }
               }

               break;
             }
    case 4 : {                         /* gray+alpha */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_ga8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_ga8_i;

                             break;
                           }
#ifndef MNG_NO_16BIT_SUPPORT
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_ga16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_ga16_i;

                             break;
                           }
#endif
               }

               break;
             }
    case 6 : {                         /* rgb+alpha */
               switch (pData->iBitdepth)
               {
                 case  8 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_rgba8_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_rgba8_i;

                             break;
                           }
#ifndef MNG_NO_16BIT_SUPPORT
                 case 16 : {
                             if (!pData->iInterlace)
                               pData->fInitrowproc = (mng_fptr)mng_init_rgba16_ni;
                             else
                               pData->fInitrowproc = (mng_fptr)mng_init_rgba16_i;

                             break;
                           }
#endif
               }

               break;
             }
  }
#endif /* MNG_OPTIMIZE_FOOTPRINT_INIT */

  pData->iFilterofs = 0;               /* determine filter characteristics */
  pData->iLevel0    = 0;               /* default levels */
  pData->iLevel1    = 0;
  pData->iLevel2    = 0;
  pData->iLevel3    = 0;

#ifdef FILTER192
  if (pData->iFilter == 0xC0)          /* leveling & differing ? */
  {
    switch (pData->iColortype)
    {
      case 0 : {
#ifndef MNG_NO_16BIT_SUPPORT
                 if (pData->iBitdepth <= 8)
#endif
                   pData->iFilterofs = 1;
#ifndef MNG_NO_16BIT_SUPPORT
                 else
                   pData->iFilterofs = 2;
#endif

                 break;
               }
      case 2 : {
#ifndef MNG_NO_16BIT_SUPPORT
                 if (pData->iBitdepth <= 8)
#endif
                   pData->iFilterofs = 3;
#ifndef MNG_NO_16BIT_SUPPORT
                 else
                   pData->iFilterofs = 6;
#endif

                 break;
               }
      case 3 : {
                 pData->iFilterofs = 1;
                 break;
               }
      case 4 : {
#ifndef MNG_NO_16BIT_SUPPORT
                 if (pData->iBitdepth <= 8)
#endif
                   pData->iFilterofs = 2;
#ifndef MNG_NO_16BIT_SUPPORT
                 else
                   pData->iFilterofs = 4;
#endif

                 break;
               }
      case 6 : {
#ifndef MNG_NO_16BIT_SUPPORT
                 if (pData->iBitdepth <= 8)
#endif
                   pData->iFilterofs = 4;
#ifndef MNG_NO_16BIT_SUPPORT
                 else
                   pData->iFilterofs = 8;
#endif

                 break;
               }
    }
  }
#endif

#ifdef FILTER193
  if (pData->iFilter == 0xC1)          /* no adaptive filtering ? */
    pData->iPixelofs = pData->iFilterofs;
  else
#endif
    pData->iPixelofs = pData->iFilterofs + 1;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_BASI, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_CLON
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_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)
#else
mng_retcode mng_process_display_clon (mng_datap  pData)
#endif
{
  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
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                                       /* locate the source object first */
  pSource = mng_find_imageobject (pData, iSourceid);
                                       /* check if the clone exists */
  pClone  = mng_find_imageobject (pData, iCloneid);
#else
                                       /* locate the source object first */
  pSource = mng_find_imageobject (pData, pData->iCLONsourceid);
                                       /* check if the clone exists */
  pClone  = mng_find_imageobject (pData, pData->iCLONcloneid);
#endif

  if (!pSource)                        /* source must exist ! */
    MNG_ERROR (pData, MNG_OBJECTUNKNOWN);

  if (pClone)                          /* clone must not exist ! */
    MNG_ERROR (pData, MNG_OBJECTEXISTS);

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if (bHasdonotshow)                   /* DoNotShow flag filled ? */
    bVisible = (mng_bool)(iDonotshow == 0);
  else
    bVisible = pSource->bVisible;
#else
  if (pData->bCLONhasdonotshow)        /* DoNotShow flag filled ? */
    bVisible = (mng_bool)(pData->iCLONdonotshow == 0);
  else
    bVisible = pSource->bVisible;
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  bAbstract  = (mng_bool)(iConcrete == 1);
#else
  bAbstract  = (mng_bool)(pData->iCLONconcrete == 1);
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  switch (iClonetype)                  /* determine action to take */
  {
    case 0 : {                         /* full clone */
               iRetcode = mng_clone_imageobject (pData, iCloneid, MNG_FALSE,
                                                 bVisible, bAbstract, bHasloca,
                                                 iLocationtype, iLocationx, iLocationy,
                                                 pSource, &pClone);
               break;
             }

    case 1 : {                         /* partial clone */
               iRetcode = mng_clone_imageobject (pData, iCloneid, MNG_TRUE,
                                                 bVisible, bAbstract, bHasloca,
                                                 iLocationtype, iLocationx, iLocationy,
                                                 pSource, &pClone);
               break;
             }

    case 2 : {                         /* renumber object */
               iRetcode = mng_renum_imageobject (pData, pSource, iCloneid,
                                                 bVisible, bAbstract, bHasloca,
                                                 iLocationtype, iLocationx, iLocationy);
               pClone   = pSource;
               break;
             }

  }
#else
  switch (pData->iCLONclonetype)       /* determine action to take */
  {
    case 0 : {                         /* full clone */
               iRetcode = mng_clone_imageobject (pData, pData->iCLONcloneid, MNG_FALSE,
                                                 bVisible, bAbstract,
                                                 pData->bCLONhasloca, pData->iCLONlocationtype,
                                                 pData->iCLONlocationx, pData->iCLONlocationy,
                                                 pSource, &pClone);
               break;
             }

    case 1 : {                         /* partial clone */
               iRetcode = mng_clone_imageobject (pData, pData->iCLONcloneid, MNG_TRUE,
                                                 bVisible, bAbstract,
                                                 pData->bCLONhasloca, pData->iCLONlocationtype,
                                                 pData->iCLONlocationx, pData->iCLONlocationy,
                                                 pSource, &pClone);
               break;
             }

    case 2 : {                         /* renumber object */
               iRetcode = mng_renum_imageobject (pData, pSource, pData->iCLONcloneid,
                                                 bVisible, bAbstract,
                                                 pData->bCLONhasloca, pData->iCLONlocationtype,
                                                 pData->iCLONlocationx, pData->iCLONlocationy);
               pClone   = pSource;
               break;
             }

  }
#endif

  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 */
    mng_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 mng_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 ! */
  mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_DISC
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_disc (mng_datap   pData,
                                      mng_uint32  iCount,
                                      mng_uint16p pIds)
#else
mng_retcode mng_process_display_disc (mng_datap   pData)
#endif
{
  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

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if (iCount)                          /* specific list ? */
#else
  if (pData->iDISCcount)               /* specific list ? */
#endif
  {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    mng_uint16p pWork = pIds;
#else
    mng_uint16p pWork = pData->pDISCids;
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
#ifdef MNG_DECREMENT_LOOPS             /* iterate the list */
    for (iX = iCount; iX > 0; iX--)
#else
    for (iX = 0; iX < iCount; iX++)
#endif
#else
#ifdef MNG_DECREMENT_LOOPS             /* iterate the list */
    for (iX = pData->iDISCcount; iX > 0; iX--)
#else
    for (iX = 0; iX < pData->iDISCcount; iX++)
#endif
#endif
    {
      pImage = mng_find_imageobject (pData, *pWork++);

      if (pImage)                      /* found the object ? */
      {                                /* then drop it */
        iRetcode = mng_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 = mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_FRAM
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_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)
#else
mng_retcode mng_process_display_fram (mng_datap  pData)
#endif
{
  mng_retcode iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_START);
#endif
                                       /* advance a frame then */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  iRetcode = next_frame (pData, iFramemode, iChangedelay, iDelay,
                         iChangetimeout, iTimeout, iChangeclipping,
                         iCliptype, iClipl, iClipr, iClipt, iClipb);
#else
  iRetcode = next_frame (pData, pData->iTempFramemode, pData->iTempChangedelay,
                         pData->iTempDelay, pData->iTempChangetimeout,
                         pData->iTempTimeout, pData->iTempChangeclipping,
                         pData->iTempCliptype, pData->iTempClipl, pData->iTempClipr,
                         pData->iTempClipt, pData->iTempClipb);
#endif

  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 mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_MOVE
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_move (mng_datap  pData,
                                      mng_uint16 iFromid,
                                      mng_uint16 iToid,
                                      mng_uint8  iMovetype,
                                      mng_int32  iMovex,
                                      mng_int32  iMovey)
#else
mng_retcode mng_process_display_move (mng_datap  pData)
#endif
{
  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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  for (iX = iFromid; iX <= iToid; iX++)
#else
  for (iX = pData->iMOVEfromid; iX <= pData->iMOVEtoid; iX++)
#endif
  {
    if (!iX)                           /* object id=0 ? */
      pImage = (mng_imagep)pData->pObjzero;
    else
      pImage = mng_find_imageobject (pData, iX);

    if (pImage)                        /* object exists ? */
    {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      switch (iMovetype)
#else
      switch (pData->iMOVEmovetype)
#endif
      {
        case 0 : {                     /* absolute */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pImage->iPosx = iMovex;
                   pImage->iPosy = iMovey;
#else
                   pImage->iPosx = pData->iMOVEmovex;
                   pImage->iPosy = pData->iMOVEmovey;
#endif
                   break;
                 }
        case 1 : {                     /* relative */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pImage->iPosx = pImage->iPosx + iMovex;
                   pImage->iPosy = pImage->iPosy + iMovey;
#else
                   pImage->iPosx = pImage->iPosx + pData->iMOVEmovex;
                   pImage->iPosy = pImage->iPosy + pData->iMOVEmovey;
#endif
                   break;
                 }
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MOVE, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_CLIP
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_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)
#else
mng_retcode mng_process_display_clip (mng_datap  pData)
#endif
{
  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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  for (iX = iFromid; iX <= iToid; iX++)
#else
  for (iX = pData->iCLIPfromid; iX <= pData->iCLIPtoid; iX++)
#endif
  {
    if (!iX)                           /* object id=0 ? */
      pImage = (mng_imagep)pData->pObjzero;
    else
      pImage = mng_find_imageobject (pData, iX);

    if (pImage)                        /* object exists ? */
    {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      switch (iCliptype)
#else
      switch (pData->iCLIPcliptype)
#endif
      {
        case 0 : {                     /* absolute */
                   pImage->bClipped = MNG_TRUE;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pImage->iClipl   = iClipl;
                   pImage->iClipr   = iClipr;
                   pImage->iClipt   = iClipt;
                   pImage->iClipb   = iClipb;
#else
                   pImage->iClipl   = pData->iCLIPclipl;
                   pImage->iClipr   = pData->iCLIPclipr;
                   pImage->iClipt   = pData->iCLIPclipt;
                   pImage->iClipb   = pData->iCLIPclipb;
#endif
                   break;
                 }
        case 1 : {                    /* relative */
                   pImage->bClipped = MNG_TRUE;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pImage->iClipl   = pImage->iClipl + iClipl;
                   pImage->iClipr   = pImage->iClipr + iClipr;
                   pImage->iClipt   = pImage->iClipt + iClipt;
                   pImage->iClipb   = pImage->iClipb + iClipb;
#else
                   pImage->iClipl   = pImage->iClipl + pData->iCLIPclipl;
                   pImage->iClipr   = pImage->iClipr + pData->iCLIPclipr;
                   pImage->iClipt   = pImage->iClipt + pData->iCLIPclipt;
                   pImage->iClipb   = pImage->iClipb + pData->iCLIPclipb;
#endif
                   break;
                 }
      }
    }
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLIP, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_SHOW
mng_retcode mng_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 = mng_find_imageobject (pData, pData->iSHOWnextid);
                 
    if (pImage)                        /* still there ? */
      mng_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 = mng_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 = mng_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))
      {
        mng_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 = mng_find_imageobject (pData, iX);
                     
        if (pImage)                    /* object exists ? */
        {
          if (pData->iBreakpoint)      /* did we get broken last time ? */
          {                            /* could only happen in the display routine */
            mng_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;
                         mng_display_image (pData, pImage, MNG_FALSE);
                         break;
                       }
              case 1 : {
                         pImage->bVisible = MNG_FALSE;
                         break;
                       }
              case 2 : {
                         if (pImage->bVisible)
                           mng_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)
                           mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_SAVE
mng_retcode mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_SEEK
mng_retcode mng_process_display_seek (mng_datap pData)
{
#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_START);
#endif

#ifdef MNG_SUPPORT_DYNAMICMNG
  if (pData->bStopafterseek)           /* need to stop after this SEEK ? */
  {
    pData->bFreezing      = MNG_TRUE;  /* stop processing on this one */
    pData->bRunningevent  = MNG_FALSE;
    pData->bStopafterseek = MNG_FALSE;
    pData->bNeedrefresh   = MNG_TRUE;  /* make sure the last bit is displayed ! */
  }
  else
#endif
  {                                    /* restore the initial or SAVE state */
    mng_retcode iRetcode = restore_state (pData);

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

#ifdef MNG_SUPPORT_DYNAMICMNG
                                       /* stop after next SEEK ? */
    if ((pData->bDynamic) || (pData->bRunningevent))
      pData->bStopafterseek = MNG_TRUE;
#endif
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifdef MNG_INCLUDE_JNG
mng_retcode mng_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 ? */
  {
#ifndef MNG_NO_DELTA_PNG
    if (pData->bHasDHDR)               /* delta-image ? */
    {
      if (pData->iDeltatype == MNG_DELTATYPE_REPLACE)
      {
        iRetcode = mng_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
#endif /* MNG_NO_DELTA_PNG */
    {
      if (pImage)                      /* update object buffer ? */
      {
        iRetcode = mng_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 = mng_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 (
#ifndef MNG_SKIPCHUNK_MAGN
         ( ((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) &&
         ( ((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) &&
#endif
         ( (pData->eImagetype == mng_it_jng         ) ||
           (((mng_imagep)pData->pStoreobj)->bVisible)    )       )
    {
      next_layer (pData);              /* that's a new layer then ! */

      pData->iBreakpoint = 0;

      if (pData->bTimerset)            /* timer break ? */
        pData->iBreakpoint = 7;
      else
      if (pData->bRunning)             /* still running ? */
      {                                /* 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 ! */
#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
    pData->ePng_imgtype=png_none;
#endif
    pData->fInitrowproc = (mng_fptr)mng_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)mng_store_jpeg_g8;
                 pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;
                 pData->bIsOpaque    = MNG_TRUE;
                 break;
               }
          case MNG_COLORTYPE_JPEGCOLOR :
               {
                 pData->fStorerow2   = (mng_fptr)mng_store_jpeg_rgb8;
                 pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;
                 pData->bIsOpaque    = MNG_TRUE;
                 break;
               }
          case MNG_COLORTYPE_JPEGGRAYA :
               {
                 pData->fStorerow2   = (mng_fptr)mng_store_jpeg_ga8;
                 pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;
                 pData->bIsOpaque    = MNG_FALSE;
                 break;
               }
          case MNG_COLORTYPE_JPEGCOLORA :
               {
                 pData->fStorerow2   = (mng_fptr)mng_store_jpeg_rgba8;
                 pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;
                 pData->bIsOpaque    = MNG_FALSE;
                 break;
               }
        }
      }
#ifndef MNG_NO_16BIT_SUPPORT
      else
      {
        pData->bIsRGBA16 = MNG_TRUE;   /* intermediate row is 16-bit deep */

        /* TODO: 12-bit JPEG */
        /* TODO: 8- + 12-bit JPEG (eg. type=20) */

      }
#endif
                                       /* possible IDAT alpha-channel ? */
      if (pData->iJHDRalphacompression == MNG_COMPRESSION_DEFLATE)
      {
                                       /* determine alpha processing routine */
#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
        pData->fInitrowproc = (mng_fptr)mng_init_rowproc;
#endif
        switch (pData->iJHDRalphabitdepth)
        {
#ifndef MNG_OPTIMIZE_FOOTPRINT_INIT
#ifndef MNG_NO_1_2_4BIT_SUPPORT
          case  1 : { pData->fInitrowproc = (mng_fptr)mng_init_jpeg_a1_ni;  break; }
          case  2 : { pData->fInitrowproc = (mng_fptr)mng_init_jpeg_a2_ni;  break; }
          case  4 : { pData->fInitrowproc = (mng_fptr)mng_init_jpeg_a4_ni;  break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
          case  8 : { pData->fInitrowproc = (mng_fptr)mng_init_jpeg_a8_ni;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
          case 16 : { pData->fInitrowproc = (mng_fptr)mng_init_jpeg_a16_ni; break; }
#endif
#else
#ifndef MNG_NO_1_2_4BIT_SUPPORT
          case  1 : { pData->ePng_imgtype = png_jpeg_a1;  break; }
          case  2 : { pData->ePng_imgtype = png_jpeg_a2;  break; }
          case  4 : { pData->ePng_imgtype = png_jpeg_a4;  break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
          case  8 : { pData->ePng_imgtype = png_jpeg_a8;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
          case 16 : { pData->ePng_imgtype = png_jpeg_a16; break; }
#endif
#endif
        }
      }
      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)mng_store_jpeg_g8_alpha;
          else
          if (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA)
            pData->fStorerow3 = (mng_fptr)mng_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 */
#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
        pData->fInitrowproc = (mng_fptr)mng_init_rowproc;
#endif
      switch (pData->iJHDRalphabitdepth)
      {
#ifndef MNG_OPTIMIZE_FOOTPRINT_INIT
#ifndef MNG_NO_1_2_4BIT_SUPPORT
        case  1 : { pData->fInitrowproc = (mng_fptr)mng_init_g1_ni;  break; }
        case  2 : { pData->fInitrowproc = (mng_fptr)mng_init_g2_ni;  break; }
        case  4 : { pData->fInitrowproc = (mng_fptr)mng_init_g4_ni;  break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
        case  8 : { pData->fInitrowproc = (mng_fptr)mng_init_g8_ni;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
        case 16 : { pData->fInitrowproc = (mng_fptr)mng_init_g16_ni; break; }
#endif
#else
#ifndef MNG_NO_1_2_4BIT_SUPPORT
        case  1 : { pData->ePng_imgtype = png_jpeg_a1;  break; }
        case  2 : { pData->ePng_imgtype = png_jpeg_a2;  break; }
        case  4 : { pData->ePng_imgtype = png_jpeg_a4;  break; }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
        case  8 : { pData->ePng_imgtype = png_jpeg_a8;  break; }
#ifndef MNG_NO_16BIT_SUPPORT
        case 16 : { pData->ePng_imgtype = png_jpeg_a16; break; }
#endif
#endif /* MNG_OPTIMIZE_FOOTPRINT_INIT */
      }
    }

    pData->iFilterofs = 0;             /* determine filter characteristics */
    pData->iLevel0    = 0;             /* default levels */
    pData->iLevel1    = 0;    
    pData->iLevel2    = 0;
    pData->iLevel3    = 0;

#ifdef FILTER192                       /* leveling & differing ? */
    if (pData->iJHDRalphafilter == 0xC0)
    {
       if (pData->iJHDRalphabitdepth <= 8)
         pData->iFilterofs = 1;
       else
         pData->iFilterofs = 2;

    }
#endif
#ifdef FILTER193                       /* no adaptive filtering ? */
    if (pData->iJHDRalphafilter == 0xC1)
      pData->iPixelofs = pData->iFilterofs;
    else
#endif
      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
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_jdaa (mng_datap  pData,
                                      mng_uint32 iRawlen,
                                      mng_uint8p pRawdata)
#else
mng_retcode mng_process_display_jdaa (mng_datap  pData)
#endif
{
  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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    iRetcode = mngjpeg_decompressdata2 (pData, iRawlen, pRawdata);
#else
    iRetcode = mngjpeg_decompressdata2 (pData, pData->iRawlen, pData->pRawdata);
#endif

  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
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_jdat (mng_datap  pData,
                                      mng_uint32 iRawlen,
                                      mng_uint8p pRawdata)
#else
mng_retcode mng_process_display_jdat (mng_datap  pData)
#endif
{
  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);

    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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    iRetcode = mngjpeg_decompressdata (pData, iRawlen, pRawdata);
#else
    iRetcode = mngjpeg_decompressdata (pData, pData->iRawlen, pData->pRawdata);
#endif

  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 */

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_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)
#else
mng_retcode mng_process_display_dhdr (mng_datap  pData)
#endif
{
  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;

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  pImage = mng_find_imageobject (pData, iObjectid);
#else
  pImage = mng_find_imageobject (pData, pData->iDHDRobjectid);
#endif

  if (pImage)                          /* object exists ? */
  {
    if (pImage->pImgbuf->bConcrete)    /* is it concrete ? */
    {                                  /* previous magnification to be done ? */
#ifndef MNG_SKIPCHUNK_MAGN
      if ((pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY))
      {
        iRetcode = mng_magnify_imageobject (pData, pImage);
                       
        if (iRetcode)                  /* on error bail out */
          return iRetcode;
      }
#endif
                                       /* save delta fields */
      pData->pDeltaImage           = (mng_ptr)pImage;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      pData->iDeltaImagetype       = iImagetype;
      pData->iDeltatype            = iDeltatype;
      pData->iDeltaBlockwidth      = iBlockwidth;
      pData->iDeltaBlockheight     = iBlockheight;
      pData->iDeltaBlockx          = iBlockx;
      pData->iDeltaBlocky          = iBlocky;
#else
      pData->iDeltaImagetype       = pData->iDHDRimagetype;
      pData->iDeltatype            = pData->iDHDRdeltatype;
      pData->iDeltaBlockwidth      = pData->iDHDRblockwidth;
      pData->iDeltaBlockheight     = pData->iDHDRblockheight;
      pData->iDeltaBlockx          = pData->iDHDRblockx;
      pData->iDeltaBlocky          = pData->iDHDRblocky;
#endif
                                       /* 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;

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      if ((iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
          (iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iPixelsampledepth;
      else
      if ((iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
          (iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iAlphasampledepth;
      else
      if ((iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
          (iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iPixelsampledepth;
#else
      if ((pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKPIXELADD    ) ||
          (pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iPixelsampledepth;
      else
      if ((pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKALPHAADD    ) ||
          (pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iAlphasampledepth;
      else
      if ((pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKCOLORADD    ) ||
          (pData->iDHDRdeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE)    )
        pData->iBitdepth           = pImage->pImgbuf->iPixelsampledepth;
#endif

#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

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                                       /* block size specified ? */
      if (iDeltatype != MNG_DELTATYPE_NOCHANGE)
      {                                /* block entirely within target ? */
        if (iDeltatype != MNG_DELTATYPE_REPLACE)
        {
          if (((iBlockx + iBlockwidth ) > pData->iDatawidth ) ||
              ((iBlocky + iBlockheight) > pData->iDataheight)    )
            MNG_ERROR (pData, MNG_INVALIDBLOCK);
        }

        pData->iDatawidth          = iBlockwidth;
        pData->iDataheight         = iBlockheight;
      }
#else
                                       /* block size specified ? */
      if (pData->iDHDRdeltatype != MNG_DELTATYPE_NOCHANGE)
      {                                /* block entirely within target ? */
        if (pData->iDHDRdeltatype != MNG_DELTATYPE_REPLACE)
        {
          if (((pData->iDHDRblockx + pData->iDHDRblockwidth ) > pData->iDatawidth ) ||
              ((pData->iDHDRblocky + pData->iDHDRblockheight) > pData->iDataheight)    )
            MNG_ERROR (pData, MNG_INVALIDBLOCK);
        }

        pData->iDatawidth          = pData->iDHDRblockwidth;
        pData->iDataheight         = pData->iDHDRblockheight;
      }
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      switch (iDeltatype)              /* determine nr of delta-channels */
#else
      switch (pData->iDHDRdeltatype)   /* determine nr of delta-channels */
#endif
      {
         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 ? */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      if (iDeltatype == MNG_DELTATYPE_REPLACE)
#else
      if (pData->iDHDRdeltatype == MNG_DELTATYPE_REPLACE)
#endif
      {
        iRetcode = mng_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 = mng_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 immediately if bitdepth & colortype are equal */
        pData->bDeltaimmediate =
          (mng_bool)((pData->bDisplaying) && (!pData->bSkipping) &&
                     ((pData->bRunning) || (pData->bSearching)) &&
                     (pData->iBitdepth  == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iBitdepth ) &&
                     (pData->iColortype == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iColortype)    );
      }
 
#ifdef MNG_OPTIMIZE_FOOTPRINT_INIT
  pData->fInitrowproc = (mng_fptr)mng_init_rowproc;
  pData->ePng_imgtype = mng_png_imgtype (pData->iColortype, pData->iBitdepth);
#else
      switch (pData->iColortype)       /* determine row initialization routine */
      {
        case 0 : {                     /* gray */
                   switch (pData->iBitdepth)
                   {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                     case  1 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_g1_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_g1_i;

                                 break;
                               }
                     case  2 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_g2_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_g2_i;

                                 break;
                               }
                     case  4 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_g4_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_g4_i;

                                 break;
                               }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_g8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_g8_i;

                                 break;
                               }
#ifndef MNG_NO_16BIT_SUPPORT
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_g16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_g16_i;

                                 break;
                               }
#endif
                   }

                   break;
                 }
        case 2 : {                     /* rgb */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgb8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgb8_i;

                                 break;
                               }
#ifndef MNG_NO_16BIT_SUPPORT
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgb16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgb16_i;

                                 break;
                               }
#endif
                   }

                   break;
                 }
        case 3 : {                     /* indexed */
                   switch (pData->iBitdepth)
                   {
#ifndef MNG_NO_1_2_4BIT_SUPPORT
                     case  1 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx1_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx1_i;

                                 break;
                               }
                     case  2 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx2_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx2_i;

                                 break;
                               }
                     case  4 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx4_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx4_i;

                                 break;
                               }
#endif /* MNG_NO_1_2_4BIT_SUPPORT */
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_idx8_i;

                                 break;
                               }
                   }

                   break;
                 }
        case 4 : {                     /* gray+alpha */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_ga8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_ga8_i;

                                 break;
                               }
#ifndef MNG_NO_16BIT_SUPPORT
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_ga16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_ga16_i;

                                 break;
                               }
#endif
                   }

                   break;
                 }
        case 6 : {                     /* rgb+alpha */
                   switch (pData->iBitdepth)
                   {
                     case  8 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgba8_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgba8_i;

                                 break;
                               }
#ifndef MNG_NO_16BIT_SUPPORT
                     case 16 : {
                                 if (!pData->iInterlace)
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgba16_ni;
                                 else
                                   pData->fInitrowproc = (mng_fptr)mng_init_rgba16_i;

                                 break;
                               }
#endif
                   }

                   break;
                 }
      }
#endif /* MNG_OPTIMIZE_FOOTPRINT_INIT */
    }
    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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_prom (mng_datap  pData,
                                      mng_uint8  iBitdepth,
                                      mng_uint8  iColortype,
                                      mng_uint8  iFilltype)
#else
mng_retcode mng_process_display_prom (mng_datap  pData)
#endif
{
  mng_imagep     pImage;
  mng_imagedatap pBuf;
  mng_retcode    iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_START);
#endif

  if (!pData->pDeltaImage)             /* gotta have this now! */
    MNG_ERROR (pData, MNG_INVALIDDELTA);

  pImage = (mng_imagep)pData->pDeltaImage;
  pBuf   = pImage->pImgbuf;
                                       /* can't demote bitdepth! */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if (iBitdepth < pBuf->iBitdepth)
    MNG_ERROR (pData, MNG_INVALIDBITDEPTH);

  if ( ((pBuf->iColortype == MNG_COLORTYPE_GRAY      ) &&
        (iColortype       != MNG_COLORTYPE_GRAY      ) &&
        (iColortype       != MNG_COLORTYPE_GRAYA     ) &&
        (iColortype       != MNG_COLORTYPE_RGB       ) &&
        (iColortype       != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_GRAYA     ) &&
        (iColortype       != MNG_COLORTYPE_GRAYA     ) &&
        (iColortype       != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_RGB       ) &&
        (iColortype       != MNG_COLORTYPE_RGB       ) &&
        (iColortype       != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_RGBA      ) &&
        (iColortype       != MNG_COLORTYPE_RGBA      )    ) ||
#ifdef MNG_INCLUDE_JNG
       ((pBuf->iColortype == MNG_COLORTYPE_JPEGGRAY  ) &&
        (iColortype       != MNG_COLORTYPE_JPEGGRAY  ) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLOR ) &&
        (iColortype       != MNG_COLORTYPE_JPEGGRAYA ) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_JPEGCOLOR ) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLOR ) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_JPEGGRAYA ) &&
        (iColortype       != MNG_COLORTYPE_JPEGGRAYA ) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype == MNG_COLORTYPE_JPEGCOLORA) &&
        (iColortype       != MNG_COLORTYPE_JPEGCOLORA)    ) ||
#endif
       ((pBuf->iColortype == MNG_COLORTYPE_INDEXED   ) &&
        (iColortype       != MNG_COLORTYPE_INDEXED   ) &&
        (iColortype       != MNG_COLORTYPE_RGB       ) &&
        (iColortype       != MNG_COLORTYPE_RGBA      )    )    )
    MNG_ERROR (pData, MNG_INVALIDCOLORTYPE);

  iRetcode = mng_promote_imageobject (pData, pImage, iBitdepth, iColortype, iFilltype);
#else
  if (pData->iPROMbitdepth < pBuf->iBitdepth)
    MNG_ERROR (pData, MNG_INVALIDBITDEPTH);

  if ( ((pBuf->iColortype      == MNG_COLORTYPE_GRAY      ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_GRAY      ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_GRAYA     ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGB       ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_GRAYA     ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_GRAYA     ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_RGB       ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGB       ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGBA      )    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_RGBA      ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGBA      )    ) ||
#ifdef MNG_INCLUDE_JNG
       ((pBuf->iColortype      == MNG_COLORTYPE_JPEGGRAY  ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGGRAY  ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLOR ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGGRAYA ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_JPEGCOLOR ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLOR ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_JPEGGRAYA ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGGRAYA ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLORA)    ) ||
       ((pBuf->iColortype      == MNG_COLORTYPE_JPEGCOLORA) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_JPEGCOLORA)    ) ||
#endif
       ((pBuf->iColortype      == MNG_COLORTYPE_INDEXED   ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_INDEXED   ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGB       ) &&
        (pData->iPROMcolortype != MNG_COLORTYPE_RGBA      )    )    )
    MNG_ERROR (pData, MNG_INVALIDCOLORTYPE);

  iRetcode = mng_promote_imageobject (pData, pImage, pData->iPROMbitdepth,
                                      pData->iPROMcolortype, pData->iPROMfilltype);
#endif

  if (iRetcode)                        /* on error bail out */
    return iRetcode;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
mng_retcode mng_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;
}
#endif

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
#ifdef MNG_INCLUDE_JNG
mng_retcode mng_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;
}
#endif
#endif

/* ************************************************************************** */

#ifndef MNG_NO_DELTA_PNG
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_pplt (mng_datap      pData,
                                      mng_uint8      iType,
                                      mng_uint32     iCount,
                                      mng_palette8ep paIndexentries,
                                      mng_uint8p     paAlphaentries,
                                      mng_uint8p     paUsedentries)
#else
mng_retcode mng_process_display_pplt (mng_datap      pData)
#endif
{
  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

#ifdef MNG_DECREMENT_LOOPS
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  iX = iCount;
#else
  iX = pData->iPPLTcount;
#endif
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  switch (iType)
#else
  switch (pData->iPPLTtype)
#endif
  {
    case MNG_DELTATYPE_REPLACERGB :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          if (paUsedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   = paIndexentries [iX].iRed;
            pBuf->aPLTEentries [iX].iGreen = paIndexentries [iX].iGreen;
            pBuf->aPLTEentries [iX].iBlue  = paIndexentries [iX].iBlue;
          }
#else
          if (pData->paPPLTusedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   = pData->paPPLTindexentries [iX].iRed;
            pBuf->aPLTEentries [iX].iGreen = pData->paPPLTindexentries [iX].iGreen;
            pBuf->aPLTEentries [iX].iBlue  = pData->paPPLTindexentries [iX].iBlue;
          }
#endif
        }

        break;
      }
    case MNG_DELTATYPE_DELTARGB :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          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 );
          }
#else
          if (pData->paPPLTusedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iRed   +
                                           pData->paPPLTindexentries [iX].iRed  );
            pBuf->aPLTEentries [iX].iGreen =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iGreen +
                                           pData->paPPLTindexentries [iX].iGreen);
            pBuf->aPLTEentries [iX].iBlue  =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iBlue  +
                                           pData->paPPLTindexentries [iX].iBlue );
          }
#endif
        }

        break;
      }
    case MNG_DELTATYPE_REPLACEALPHA :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          if (paUsedentries [iX])
            pBuf->aTRNSentries [iX] = paAlphaentries [iX];
        }
#else
          if (pData->paPPLTusedentries [iX])
            pBuf->aTRNSentries [iX] = pData->paPPLTalphaentries [iX];
        }
#endif

        break;
      }
    case MNG_DELTATYPE_DELTAALPHA :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          if (paUsedentries [iX])
            pBuf->aTRNSentries [iX] =
                               (mng_uint8)(pBuf->aTRNSentries [iX] +
                                           paAlphaentries [iX]);
#else
          if (pData->paPPLTusedentries [iX])
            pBuf->aTRNSentries [iX] =
                               (mng_uint8)(pBuf->aTRNSentries [iX] +
                                           pData->paPPLTalphaentries [iX]);
#endif
        }

        break;
      }
    case MNG_DELTATYPE_REPLACERGBA :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          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];
          }
#else
          if (pData->paPPLTusedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   = pData->paPPLTindexentries [iX].iRed;
            pBuf->aPLTEentries [iX].iGreen = pData->paPPLTindexentries [iX].iGreen;
            pBuf->aPLTEentries [iX].iBlue  = pData->paPPLTindexentries [iX].iBlue;
            pBuf->aTRNSentries [iX]        = pData->paPPLTalphaentries [iX];
          }
#endif
        }

        break;
      }
    case MNG_DELTATYPE_DELTARGBA :
      {
#ifdef MNG_DECREMENT_LOOPS
        for (; iX > 0;iX--)
#else
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        for (iX = 0; iX < iCount; iX++)
#else
        for (iX = 0; iX < pData->iPPLTcount; iX++)
#endif
#endif
        {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
          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]);
          }
#else
          if (pData->paPPLTusedentries [iX])
          {
            pBuf->aPLTEentries [iX].iRed   =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iRed   +
                                           pData->paPPLTindexentries [iX].iRed  );
            pBuf->aPLTEentries [iX].iGreen =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iGreen +
                                           pData->paPPLTindexentries [iX].iGreen);
            pBuf->aPLTEentries [iX].iBlue  =
                               (mng_uint8)(pBuf->aPLTEentries [iX].iBlue  +
                                           pData->paPPLTindexentries [iX].iBlue );
            pBuf->aTRNSentries [iX] =
                               (mng_uint8)(pBuf->aTRNSentries [iX] +
                                           pData->paPPLTalphaentries [iX]);
          }
#endif
        }

        break;
      }
  }

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if ((iType != MNG_DELTATYPE_REPLACERGB) && (iType != MNG_DELTATYPE_DELTARGB))
#else
  if ((pData->iPPLTtype != MNG_DELTATYPE_REPLACERGB) &&
      (pData->iPPLTtype != MNG_DELTATYPE_DELTARGB  )    )
#endif
  {
    if (pBuf->bHasTRNS)
    {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      if (iCount > pBuf->iTRNScount)
        pBuf->iTRNScount = iCount;
#else
      if (pData->iPPLTcount > pBuf->iTRNScount)
        pBuf->iTRNScount = pData->iPPLTcount;
#endif
    }
    else
    {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      pBuf->iTRNScount = iCount;
      pBuf->bHasTRNS   = MNG_TRUE;
#else
      pBuf->iTRNScount = pData->iPPLTcount;
      pBuf->bHasTRNS   = MNG_TRUE;
#endif
    }
  }

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if ((iType != MNG_DELTATYPE_REPLACEALPHA) && (iType != MNG_DELTATYPE_DELTAALPHA))
#else
  if ((pData->iPPLTtype != MNG_DELTATYPE_REPLACEALPHA) &&
      (pData->iPPLTtype != MNG_DELTATYPE_DELTAALPHA  )    )
#endif
  {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    if (iCount > pBuf->iPLTEcount)
      pBuf->iPLTEcount = iCount;
#else
    if (pData->iPPLTcount > pBuf->iPLTEcount)
      pBuf->iPLTEcount = pData->iPPLTcount;
#endif
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PPLT, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_MAGN
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_magn (mng_datap  pData,
                                      mng_uint16 iFirstid,
                                      mng_uint16 iLastid,
                                      mng_uint8  iMethodX,
                                      mng_uint16 iMX,
                                      mng_uint16 iMY,
                                      mng_uint16 iML,
                                      mng_uint16 iMR,
                                      mng_uint16 iMT,
                                      mng_uint16 iMB,
                                      mng_uint8  iMethodY)
#else
mng_retcode mng_process_display_magn (mng_datap  pData)
#endif
{
  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 */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  for (iX = iFirstid; iX <= iLastid; iX++)
#else
  for (iX = pData->iMAGNfirstid; iX <= pData->iMAGNlastid; iX++)
#endif
  {
    if (iX == 0)                       /* process object 0 ? */
    {
      pImage = (mng_imagep)pData->pObjzero;

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      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->iMAGN_MethodX = pData->iMAGNmethodX;
      pImage->iMAGN_MethodY = pData->iMAGNmethodY;
      pImage->iMAGN_MX      = pData->iMAGNmX;
      pImage->iMAGN_MY      = pData->iMAGNmY;
      pImage->iMAGN_ML      = pData->iMAGNmL;
      pImage->iMAGN_MR      = pData->iMAGNmR;
      pImage->iMAGN_MT      = pData->iMAGNmT;
      pImage->iMAGN_MB      = pData->iMAGNmB;
#endif
    }
    else
    {
      pImage = mng_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 = mng_magnify_imageobject (pData, pImage);
          if (iRetcode)                /* on error bail out */
            return iRetcode;
        }

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
        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->iMAGN_MethodX = pData->iMAGNmethodX;
        pImage->iMAGN_MethodY = pData->iMAGNmethodY;
        pImage->iMAGN_MX      = pData->iMAGNmX;
        pImage->iMAGN_MY      = pData->iMAGNmY;
        pImage->iMAGN_ML      = pData->iMAGNmL;
        pImage->iMAGN_MR      = pData->iMAGNmR;
        pImage->iMAGN_MT      = pData->iMAGNmT;
        pImage->iMAGN_MB      = pData->iMAGNmB;
#endif
      }
    }
  }

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  pData->iMAGNfromid = iFirstid;
  pData->iMAGNtoid   = iLastid;
  iX                 = iFirstid;
#else
  pData->iMAGNfromid = pData->iMAGNfirstid;
  pData->iMAGNtoid   = pData->iMAGNlastid;
  iX                 = pData->iMAGNfirstid;
#endif
                                       /* iterate again for showing */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  while ((iX <= iLastid) && (!pData->bTimerset))
#else
  while ((iX <= pData->iMAGNlastid) && (!pData->bTimerset))
#endif
  {
    pData->iMAGNcurrentid = iX;

    if (iX)                            /* only real objects ! */
    {
      pImage = mng_find_imageobject (pData, iX);
                                       /* object exists & is not frozen  &
                                          is visible & is viewable ? */
      if ((pImage) && (!pImage->bFrozen) &&
          (pImage->bVisible) && (pImage->bViewable))
      {
        mng_retcode iRetcode = mng_display_image (pData, pImage, MNG_FALSE);
        if (iRetcode)
          return iRetcode;
      }
    }

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

/* ************************************************************************** */

mng_retcode mng_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->iMAGNcurrentid;
                                       /* iterate again for showing */
  while ((iX <= pData->iMAGNtoid) && (!pData->bTimerset))
  {
    pData->iMAGNcurrentid = iX;

    if (iX)                            /* only real objects ! */
    {
      pImage = mng_find_imageobject (pData, iX);
                                       /* object exists & is not frozen  &
                                          is visible & is viewable ? */
      if ((pImage) && (!pImage->bFrozen) &&
          (pImage->bVisible) && (pImage->bViewable))
      {
        mng_retcode iRetcode = mng_display_image (pData, pImage, MNG_FALSE);
        if (iRetcode)
          return iRetcode;
      }
    }

    iX++;
  }

  if (pData->bTimerset)                /* broken ? */
    pData->iBreakpoint = 9;
  else
    pData->iBreakpoint = 0;            /* not again ! */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_PAST
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
mng_retcode mng_process_display_past (mng_datap  pData,
                                      mng_uint16 iTargetid,
                                      mng_uint8  iTargettype,
                                      mng_int32  iTargetx,
                                      mng_int32  iTargety,
                                      mng_uint32 iCount,
                                      mng_ptr    pSources)
#else
mng_retcode mng_process_display_past (mng_datap  pData)
#endif
{
  mng_retcode      iRetcode = MNG_NOERROR;
  mng_imagep       pTargetimg;
  mng_imagep       pSourceimg;
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  mng_past_sourcep pSource = (mng_past_sourcep)pSources;
#else
  mng_past_sourcep pSource = (mng_past_sourcep)pData->pPASTsources;
#endif
  mng_uint32       iX      = 0;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PAST, MNG_LC_START);
#endif

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
  if (iTargetid)                       /* a real destination object ? */
#else
  if (pData->iPASTtargetid)            /* a real destination object ? */
#endif
  {                                    /* let's find it then */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    pTargetimg = (mng_imagep)mng_find_imageobject (pData, iTargetid);
#else
    pTargetimg = (mng_imagep)mng_find_imageobject (pData, pData->iPASTtargetid);
#endif

    if (!pTargetimg)                   /* if it doesn't exists; do a barf */
      MNG_ERROR (pData, MNG_OBJECTUNKNOWN);
                                       /* it's gotta be abstract !!! */
    if (pTargetimg->pImgbuf->bConcrete)
      MNG_ERROR (pData, MNG_OBJNOTABSTRACT);
                                       /* we want 32-/64-bit RGBA to play with ! */
    if ((pTargetimg->pImgbuf->iBitdepth <= MNG_BITDEPTH_8)          ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_GRAY)    ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_RGB)     ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_INDEXED) ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_GRAYA)      )
      iRetcode = mng_promote_imageobject (pData, pTargetimg, MNG_BITDEPTH_8,
                                          MNG_COLORTYPE_RGBA,
                                          MNG_FILLMETHOD_LEFTBITREPLICATE);
    else
    if ((pTargetimg->pImgbuf->iBitdepth > MNG_BITDEPTH_8)              &&
        ((pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_GRAY)  ||
         (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_RGB)   ||
         (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_GRAYA)    )   )
      iRetcode = mng_promote_imageobject (pData, pTargetimg, MNG_BITDEPTH_16,
                                          MNG_COLORTYPE_RGBA,
                                          MNG_FILLMETHOD_LEFTBITREPLICATE);
#ifdef MNG_INCLUDE_JNG
    else
    if ((pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_JPEGGRAY)  ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_JPEGCOLOR) ||
        (pTargetimg->pImgbuf->iColortype ==  MNG_COLORTYPE_JPEGGRAYA)    )
      iRetcode = mng_promote_imageobject (pData, pTargetimg,
                                          pTargetimg->pImgbuf->iBitdepth,
                                          MNG_COLORTYPE_JPEGCOLORA,
                                          MNG_FILLMETHOD_LEFTBITREPLICATE);
#endif

    if (iRetcode)                      /* on error bail out */
      return iRetcode;
                                       /* make it really abstract ? */
    if (!pTargetimg->pImgbuf->bCorrected)
    {
      iRetcode = mng_colorcorrect_object (pData, pTargetimg);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
  }
  else
  {                                    /* pasting into object 0 !!! */
    pTargetimg = (mng_imagep)pData->pObjzero;
                                       /* is it usable ??? */
    if ((pTargetimg->bClipped) &&
        (pTargetimg->iClipr > pTargetimg->iPosx) &&
        (pTargetimg->iClipb > pTargetimg->iPosy))
    {
                                       /* make it 32-bit RGBA please !!! */
      iRetcode = mng_reset_object_details (pData, pTargetimg,
                                           pTargetimg->iClipr - pTargetimg->iPosx,
                                           pTargetimg->iClipb - pTargetimg->iPosy,
                                           MNG_BITDEPTH_8, MNG_COLORTYPE_RGBA,
                                           0, 0, 0, MNG_FALSE);

      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
    else
      pTargetimg = MNG_NULL;           /* clipped beyond visibility ! */
  }

  if (pTargetimg)                      /* usable destination ? */
  {
    mng_int32      iSourceY;
    mng_int32      iSourceYinc;
    mng_int32      iSourcerowsize;
    mng_int32      iSourcesamples;
    mng_bool       bSourceRGBA16;
    mng_int32      iTargetY;
    mng_int32      iTargetrowsize;
    mng_int32      iTargetsamples;
    mng_bool       bTargetRGBA16 = MNG_FALSE;
    mng_int32      iTemprowsize;
    mng_imagedatap pBuf;
#ifndef MNG_SKIPCHUNK_MAGN
                                       /* needs magnification ? */
    if ((pTargetimg->iMAGN_MethodX) || (pTargetimg->iMAGN_MethodY))
      iRetcode = mng_magnify_imageobject (pData, pTargetimg);
#endif

    if (!iRetcode)                     /* still ok ? */
    {
      bTargetRGBA16 = (mng_bool)(pTargetimg->pImgbuf->iBitdepth > 8);

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
      switch (iTargettype)             /* determine target x/y */
#else
      switch (pData->iPASTtargettype)  /* determine target x/y */
#endif
      {
        case 0 : {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pData->iPastx = iTargetx;
                   pData->iPasty = iTargety;
#else
                   pData->iPastx = pData->iPASTtargetx;
                   pData->iPasty = pData->iPASTtargety;
#endif
                   break;
                 }

        case 1 : {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pData->iPastx = pTargetimg->iPastx + iTargetx;
                   pData->iPasty = pTargetimg->iPasty + iTargety;
#else
                   pData->iPastx = pTargetimg->iPastx + pData->iPASTtargetx;
                   pData->iPasty = pTargetimg->iPasty + pData->iPASTtargety;
#endif
                   break;
                 }

        case 2 : {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
                   pData->iPastx += iTargetx;
                   pData->iPasty += iTargety;
#else
                   pData->iPastx += pData->iPASTtargetx;
                   pData->iPasty += pData->iPASTtargety;
#endif
                   break;
                 }
      }
                                       /* save for next time ... */
      pTargetimg->iPastx      = pData->iPastx;
      pTargetimg->iPasty      = pData->iPasty;
                                       /* address destination for row-routines */
      pData->pStoreobj        = (mng_objectp)pTargetimg;
      pData->pStorebuf        = (mng_objectp)pTargetimg->pImgbuf;
    }
                                       /* process the sources one by one */
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    while ((!iRetcode) && (iX < iCount))
#else
    while ((!iRetcode) && (iX < pData->iPASTcount))
#endif
    {                                  /* find the little bastards first */
      pSourceimg              = (mng_imagep)mng_find_imageobject (pData, pSource->iSourceid);
                                       /* exists and viewable? */
      if ((pSourceimg) && (pSourceimg->bViewable))
      {                                /* needs magnification ? */
#ifndef MNG_SKIPCHUNK_MAGN
        if ((pSourceimg->iMAGN_MethodX) || (pSourceimg->iMAGN_MethodY))
          iRetcode = mng_magnify_imageobject (pData, pSourceimg);
#endif

        if (!iRetcode)                 /* still ok ? */
        {
          pBuf                = (mng_imagedatap)pSourceimg->pImgbuf;
                                       /* address source for row-routines */
          pData->pRetrieveobj = (mng_objectp)pSourceimg;

          pData->iPass        = -1;    /* init row-processing variables */
          pData->iRowinc      = 1;
          pData->iColinc      = 1;
          pData->iPixelofs    = 0;
          iSourcesamples      = (mng_int32)pBuf->iWidth;
          iSourcerowsize      = pBuf->iRowsize;
          bSourceRGBA16       = (mng_bool)(pBuf->iBitdepth > 8);
                                       /* make sure the delta-routines do the right thing */
          pData->iDeltatype   = MNG_DELTATYPE_BLOCKPIXELREPLACE;

          switch (pBuf->iColortype)
          {
            case  0 : { 
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                        pData->bIsOpaque      = (mng_bool)(!pBuf->bHasTRNS);
                        break;
                      }

            case  2 : {
#ifndef MNG_NO_16BIT_SUPPORT
                        if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                        pData->bIsOpaque      = (mng_bool)(!pBuf->bHasTRNS);
                        break;
                      }


            case  3 : { pData->fRetrieverow   = (mng_fptr)mng_retrieve_idx8;
                        pData->bIsOpaque      = (mng_bool)(!pBuf->bHasTRNS);
                        break;
                      }


            case  4 : {
#ifndef MNG_NO_16BIT_SUPPORT
                        if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                        pData->bIsOpaque      = MNG_FALSE;
                        break;
                      }


            case  6 : {
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;

                        pData->bIsOpaque      = MNG_FALSE;
                        break;
                      }

            case  8 : {
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_g16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_g8;

                        pData->bIsOpaque      = MNG_TRUE;
                        break;
                      }

            case 10 : {
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgb8;

                        pData->bIsOpaque      = MNG_TRUE;
                        break;
                      }


            case 12 : {
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_ga16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_ga8;

                        pData->bIsOpaque      = MNG_FALSE;
                        break;
                      }


            case 14 : {
#ifndef MNG_NO_16BIT_SUPPORT
                         if (bSourceRGBA16)
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba16;
                        else
#endif
                          pData->fRetrieverow = (mng_fptr)mng_retrieve_rgba8;

                        pData->bIsOpaque      = MNG_FALSE;
                        break;
                      }
          }
                                       /* determine scaling */
#ifndef MNG_NO_16BIT_SUPPORT
#ifndef MNG_NO_DELTA_PNG
          if ((!bSourceRGBA16) && (bTargetRGBA16))
            pData->fScalerow = (mng_fptr)mng_scale_rgba8_rgba16;
          else
          if ((bSourceRGBA16) && (!bTargetRGBA16))
            pData->fScalerow = (mng_fptr)mng_scale_rgba16_rgba8;
          else
#endif
#endif
            pData->fScalerow = MNG_NULL;

                                       /* default no color-correction */
          pData->fCorrectrow = MNG_NULL;

#if defined(MNG_FULL_CMS)              /* determine color-management routine */
          iRetcode = mng_init_full_cms   (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_GAMMA_ONLY)
          iRetcode = mng_init_gamma_only (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#elif defined(MNG_APP_CMS)
          iRetcode = mng_init_app_cms    (pData, MNG_FALSE, MNG_FALSE, MNG_TRUE);
#endif
        }

        if (!iRetcode)                 /* still ok ? */
        {  
          pData->fFliprow = MNG_NULL;  /* no flipping or tiling by default */
          pData->fTilerow = MNG_NULL;
                                       /* but perhaps we do have to ... */
          switch (pSource->iOrientation)
          {
            case 2 : ;
            case 4 : {
#ifndef MNG_NO_16BIT_SUPPORT
                       if (bTargetRGBA16)
                         pData->fFliprow = (mng_fptr)mng_flip_rgba16;
                       else
#endif
                         pData->fFliprow = (mng_fptr)mng_flip_rgba8;
                       break;
                     }

            case 8 : {
#ifndef MNG_NO_16BIT_SUPPORT
                       if (bTargetRGBA16)
                         pData->fTilerow = (mng_fptr)mng_tile_rgba16;
                       else
#endif
                         pData->fTilerow = (mng_fptr)mng_tile_rgba8;
                       break;
                     }
          }
                                       /* determine composition routine */
                                       /* note that we're abusing the delta-routine setup !!! */
          switch (pSource->iComposition)
          {
            case 0 : {                 /* composite over */
#ifndef MNG_NO_16BIT_SUPPORT
                       if (bTargetRGBA16)
                         pData->fDeltarow = (mng_fptr)mng_composeover_rgba16;
                       else
#endif
                         pData->fDeltarow = (mng_fptr)mng_composeover_rgba8;
                       break;
                     }

            case 1 : {                 /* replace */
#ifndef MNG_NO_16BIT_SUPPORT
                       if (bTargetRGBA16)
                         pData->fDeltarow = (mng_fptr)mng_delta_rgba16_rgba16;
                       else
#endif
                         pData->fDeltarow = (mng_fptr)mng_delta_rgba8_rgba8;
                       break;
                     }

            case 2 : {                 /* composite under */
#ifndef MNG_NO_16BIT_SUPPORT
                       if (bTargetRGBA16)
                         pData->fDeltarow = (mng_fptr)mng_composeunder_rgba16;
                       else
#endif
                         pData->fDeltarow = (mng_fptr)mng_composeunder_rgba8;
                       break;
                     }
          }
                                       /* determine offsets & clipping */
          if (pSource->iOffsettype == 1)
          {
            pData->iDestl          = pData->iPastx + pSource->iOffsetx;
            pData->iDestt          = pData->iPasty + pSource->iOffsety;
          }
          else
          {
            pData->iDestl          = pSource->iOffsetx;
            pData->iDestt          = pSource->iOffsety;
          }

          pData->iDestr            = (mng_int32)pTargetimg->pImgbuf->iWidth;
          pData->iDestb            = (mng_int32)pTargetimg->pImgbuf->iHeight;
                                       /* take the source dimension into account ? */
          if (pSource->iOrientation != 8)
          {
            pData->iDestr          = MIN_COORD (pData->iDestr, pData->iDestl + (mng_int32)pBuf->iWidth);
            pData->iDestb          = MIN_COORD (pData->iDestb, pData->iDestt + (mng_int32)pBuf->iHeight);
          }
                                       /* source clipping */
          if (pSource->iBoundarytype == 1)
          {
            if (pData->iDestl < pData->iPastx + pSource->iBoundaryl)
              pData->iSourcel      = pData->iPastx + pSource->iBoundaryl - pData->iDestl;
            else
              pData->iSourcel      = 0;

            if (pData->iDestt < pData->iPasty + pSource->iBoundaryt)
              pData->iSourcet      = pData->iPasty + pSource->iBoundaryt - pData->iDestt;
            else
              pData->iSourcet      = 0;

            pData->iDestl          = MAX_COORD (pData->iDestl, pData->iPastx + pSource->iBoundaryl);
            pData->iDestt          = MAX_COORD (pData->iDestt, pData->iPasty + pSource->iBoundaryt);
            pData->iDestr          = MIN_COORD (pData->iDestr, pData->iPastx + pSource->iBoundaryr);
            pData->iDestb          = MIN_COORD (pData->iDestb, pData->iPasty + pSource->iBoundaryb);
          }
          else
          {
            if (pData->iDestl < pSource->iBoundaryl)
              pData->iSourcel      = pSource->iBoundaryl - pData->iDestl;
            else
              pData->iSourcel      = 0;

            if (pData->iDestt < pSource->iBoundaryt)
              pData->iSourcet      = pSource->iBoundaryt - pData->iDestt;
            else
              pData->iSourcet      = 0;

            pData->iDestl          = MAX_COORD (pData->iDestl, pSource->iBoundaryl);
            pData->iDestt          = MAX_COORD (pData->iDestt, pSource->iBoundaryt);
            pData->iDestr          = MIN_COORD (pData->iDestr, pSource->iBoundaryr);
            pData->iDestb          = MIN_COORD (pData->iDestb, pSource->iBoundaryb);
          }

          if (pData->iSourcel)         /* indent source ? */
          {
#ifndef MNG_NO_16BIT_SUPPORT
             if (bTargetRGBA16)        /* abuse tiling routine to shift source-pixels */
               pData->fTilerow = (mng_fptr)mng_tile_rgba16;
             else
#endif
               pData->fTilerow = (mng_fptr)mng_tile_rgba8;
          }
                                       /* anything to display ? */
          if ((pData->iDestl <= pData->iDestr) && (pData->iDestt <= pData->iDestb))
          {                            /* init variables for the loop */
            if ((pSource->iOrientation == 2) || (pSource->iOrientation == 6))
            {
              iSourceY             = (mng_int32)pBuf->iHeight - 1 - pData->iSourcet;
              iSourceYinc          = -1;
            }
            else
            {
              iSourceY             = pData->iSourcet;
              iSourceYinc          = 1;
            }

            iTargetY               = pData->iDestt;
            pData->iCol            = pData->iDestl;

            iTargetsamples         = pData->iDestr - pData->iDestl;

#ifndef MNG_NO_16BIT_SUPPORT
            if (bTargetRGBA16)
              iTargetrowsize       = (iTargetsamples << 3);
            else
#endif
              iTargetrowsize       = (iTargetsamples << 2);

                                       /* get temporary work-buffers */
            if (iSourcerowsize > iTargetrowsize)
              iTemprowsize         = iSourcerowsize << 1;
            else
              iTemprowsize         = iTargetrowsize << 1;
            MNG_ALLOC (pData, pData->pRGBArow, iTemprowsize);
            MNG_ALLOC (pData, pData->pWorkrow, iTemprowsize);

            while ((!iRetcode) && (iTargetY < pData->iDestb))
            {                          /* get a row */
              pData->iRow          = iSourceY;
              pData->iRowsamples   = iSourcesamples;
              pData->iRowsize      = iSourcerowsize;
              pData->bIsRGBA16     = bSourceRGBA16;
              iRetcode             = ((mng_retrieverow)pData->fRetrieverow) (pData);
                                       /* scale it (if necessary) */
              if ((!iRetcode) && (pData->fScalerow))
                iRetcode           = ((mng_scalerow)pData->fScalerow) (pData);

              pData->bIsRGBA16     = bTargetRGBA16;
                                       /* color correction (if necessary) */
              if ((!iRetcode) && (pData->fCorrectrow))
                iRetcode           = ((mng_correctrow)pData->fCorrectrow) (pData);
                                       /* flipping (if necessary) */
              if ((!iRetcode) && (pData->fFliprow))
                iRetcode           = ((mng_fliprow)pData->fFliprow) (pData);
                                       /* tiling (if necessary) */
              if ((!iRetcode) && (pData->fTilerow))
                iRetcode           = ((mng_tilerow)pData->fTilerow) (pData);

              if (!iRetcode)           /* and paste..... */
              {
                pData->iRow        = iTargetY;
                pData->iRowsamples = iTargetsamples;
                pData->iRowsize    = iTargetrowsize;
                iRetcode           = ((mng_deltarow)pData->fDeltarow) (pData);
              }

              iSourceY += iSourceYinc; /* and next line */

              if (iSourceY < 0)
                iSourceY = (mng_int32)pBuf->iHeight - 1;
              else
              if (iSourceY >= (mng_int32)pBuf->iHeight)
                iSourceY = 0;

              iTargetY++;
            }
                                       /* drop the temporary row-buffer */
            MNG_FREEX (pData, pData->pWorkrow, iTemprowsize);
            MNG_FREEX (pData, pData->pRGBArow, iTemprowsize);
          }

#if defined(MNG_FULL_CMS)              /* cleanup cms stuff */
          if (!iRetcode)
            iRetcode = mng_clear_cms (pData);
#endif
        }

        pSource++;                     /* neeeeext */
        iX++;
      }
    }

    if (iRetcode)                      /* on error bail out */
      return iRetcode;

#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    if (!iTargetid)                    /* did we paste into object 0 ? */
#else
    if (!pData->iPASTtargetid)         /* did we paste into object 0 ? */
#endif
    {                                  /* display it then ! */
      iRetcode = mng_display_image (pData, pTargetimg, MNG_FALSE);
      if (iRetcode)                    /* on error bail out */
        return iRetcode;
    }
    else
    {                                  /* target is visible & viewable ? */
      if ((pTargetimg->bVisible) && (pTargetimg->bViewable))
      {
        iRetcode = mng_display_image (pData, pTargetimg, MNG_FALSE);
        if (iRetcode)
          return iRetcode;
      }
    }  
  }

  if (pData->bTimerset)                /* broken ? */
  {
#ifndef MNG_OPTIMIZE_DISPLAYCALLS
    pData->iPASTid     = iTargetid;
#else
    pData->iPASTid     = pData->iPASTtargetid;
#endif
    pData->iBreakpoint = 11;
  }

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PAST, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif /* MNG_SKIPCHUNK_PAST */

/* ************************************************************************** */

#ifndef MNG_SKIPCHUNK_PAST
mng_retcode mng_process_display_past2 (mng_datap pData)
{
  mng_retcode iRetcode;
  mng_imagep  pTargetimg;

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PAST, MNG_LC_START);
#endif

  if (pData->iPASTid)                  /* a real destination object ? */
    pTargetimg = (mng_imagep)mng_find_imageobject (pData, pData->iPASTid);
  else                                 /* otherwise object 0 */
    pTargetimg = (mng_imagep)pData->pObjzero;

  iRetcode = mng_display_image (pData, pTargetimg, MNG_FALSE);
  if (iRetcode)
    return iRetcode;

  pData->iBreakpoint = 0;              /* only once */

#ifdef MNG_SUPPORT_TRACE
  MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PAST, MNG_LC_END);
#endif

  return MNG_NOERROR;
}
#endif /* MNG_SKIPCHUNK_PAST */

/* ************************************************************************** */

#endif /* MNG_INCLUDE_DISPLAY_PROCS */

/* ************************************************************************** */
/* * end of file                                                            * */
/* ************************************************************************** */


