home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libimg / src / jpeg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  29.9 KB  |  988 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  *      jpeg.c --- Glue code to Independent JPEG Group decoder library
  21.  *    $Id: jpeg.c,v 3.1 1998/03/28 03:35:03 ltabb Exp $
  22.  */
  23.  
  24.  
  25. /*
  26. #include "xp.h"
  27. */
  28.  
  29. #include "if.h"
  30.  
  31. #include "xp_core.h"
  32. #include "merrors.h"
  33.  
  34. #include "il.h"
  35.  
  36. #include <ctype.h>        /* to declare isprint() */
  37. #ifndef XP_MAC
  38. #     include <sys/types.h>
  39. #endif
  40.  
  41. #include "jinclude.h"
  42. #include "jpeglib.h"
  43. #include "jerror.h"
  44.  
  45. extern int MK_OUT_OF_MEMORY;
  46.  
  47. #ifdef XP_OS2_HACK
  48. /* IBM-MAS: We removed setjmp.h from XP_core.h, now we need it here. */
  49. /*          We need to see if we can fix hwthreads/XP_CORE correctly.. */
  50. #include <setjmp.h>
  51. #endif
  52.  
  53. #ifdef PROFILE
  54. #     pragma profile on
  55. #endif
  56.  
  57.  
  58. /* Normal JFIF markers can't have more bytes than this. */
  59. #define MAX_JPEG_MARKER_LENGTH    (((uint32)1 << 16) - 1)
  60.  
  61. /*
  62.  * States that the jpeg decoder might be in
  63.  */
  64. typedef enum {
  65.     JPEG_HEADER,                          /* Reading JFIF headers */
  66.     JPEG_START_DECOMPRESS,
  67.     JPEG_DECOMPRESS_PROGRESSIVE,          /* Output progressive pixels */
  68.     JPEG_DECOMPRESS_SEQUENTIAL,           /* Output sequential pixels */
  69.     JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT,
  70.     JPEG_DONE,
  71.     JPEG_SINK_NON_JPEG_TRAILER           /* Some image files have a */
  72.                                          /* non-JPEG trailer */
  73. } jstate;
  74.     
  75. typedef struct {
  76.     struct jpeg_error_mgr pub;    /* "public" fields for IJG library*/
  77.     jmp_buf setjmp_buffer;        /* For handling catastropic errors */
  78. } il_error_mgr;
  79.  
  80. /*
  81.  * Structure used to manage the JPEG decoder stream.
  82.  */
  83. typedef struct jpeg_struct {
  84.     jstate state;                /* Decoder FSM state */
  85.     int pass_num;
  86.     int completed_output_passes;
  87.  
  88.     int rows_per_chunk;
  89.     void *timeout;
  90.     
  91.     /* One scanline's worth of post-processed sample data */
  92.     JSAMPARRAY samples;
  93.     JSAMPARRAY samples3;
  94.     /* IJG JPEG library decompressor state */
  95.     struct jpeg_decompress_struct jd;
  96.     il_error_mgr jerr;
  97.     il_container *ic;
  98. } jpeg_struct;
  99.  
  100.  
  101.  
  102.  
  103. /* Possible states for JPEG source manager */
  104. enum data_source_state {
  105.     dss_consuming_backtrack_buffer = 0, /* Must be zero for init purposes */
  106.     dss_consuming_netlib_buffer
  107. };
  108.  
  109. /*
  110.  *    Implementation of a JPEG src object that understands our state machine
  111.  */
  112. typedef struct {
  113.     /* public fields; must be first in this struct! */
  114.     struct jpeg_source_mgr pub;
  115.  
  116.     jpeg_struct *js;              /* pointer to netlib stream object */
  117.  
  118.     int bytes_to_skip;            /* remaining bytes to skip */
  119.  
  120.     enum data_source_state state;
  121.  
  122.     JOCTET *netlib_buffer;        /* next buffer for fill_input_buffer */
  123.     uint32 netlib_buflen;
  124.  
  125.     /*
  126.      * Buffer of "remaining" characters left over after a call to 
  127.      * fill_input_buffer(), when no additional data is available.
  128.      */ 
  129.     JOCTET *backtrack_buffer;
  130.     size_t backtrack_buffer_size; /* Allocated size of backtrack_buffer        */
  131.     size_t backtrack_buflen;      /* Offset of end of active backtrack data */
  132.     size_t backtrack_num_unread_bytes; /* Length of active backtrack data    */
  133. } il_source_mgr;
  134.  
  135.  
  136. /* Override the standard error method in the IJG JPEG decoder code. */
  137. void PR_CALLBACK
  138. il_error_exit (j_common_ptr cinfo)
  139. {
  140.     int error_code;
  141.     il_error_mgr *err = (il_error_mgr *) cinfo->err;
  142.  
  143. #ifdef DEBUG
  144.     if (il_debug >= 1) {
  145.         char buffer[JMSG_LENGTH_MAX];
  146.  
  147.         /* Create the message */
  148.         (*cinfo->err->format_message) (cinfo, buffer);
  149.  
  150.         XP_TRACE(("%s\n", buffer));
  151.     }
  152. #endif
  153.  
  154.     /* Convert error to a browser error code */
  155.     if (cinfo->err->msg_code == JERR_OUT_OF_MEMORY)
  156.         error_code = MK_OUT_OF_MEMORY;
  157.     else
  158.         error_code = MK_IMAGE_LOSSAGE;
  159.         
  160.     /* Return control to the setjmp point. */
  161.     longjmp(err->setjmp_buffer, error_code);
  162. }
  163.  
  164.  
  165. void PR_CALLBACK
  166. init_source (j_decompress_ptr jd)
  167. {
  168. }
  169.  
  170. /*-----------------------------------------------------------------------------
  171.  * This is the callback routine from the IJG JPEG library used to supply new
  172.  * data to the decompressor when its input buffer is exhausted.     It juggles
  173.  * multiple buffers in an attempt to avoid unnecessary copying of input data.
  174.  *
  175.  * (A simpler scheme is possible: It's much easier to use only a single
  176.  * buffer; when fill_input_buffer() is called, move any unconsumed data
  177.  * (beyond the current pointer/count) down to the beginning of this buffer and
  178.  * then load new data into the remaining buffer space.    This approach requires
  179.  * a little more data copying but is far easier to get right.)
  180.  *
  181.  * At any one time, the JPEG decompressor is either reading from the netlib
  182.  * input buffer, which is volatile across top-level calls to the IJG library,
  183.  * or the "backtrack" buffer.  The backtrack buffer contains the remaining
  184.  * unconsumed data from the netlib buffer after parsing was suspended due
  185.  * to insufficient data in some previous call to the IJG library.
  186.  *
  187.  * When suspending, the decompressor will back up to a convenient restart
  188.  * point (typically the start of the current MCU). The variables
  189.  * next_input_byte & bytes_in_buffer indicate where the restart point will be
  190.  * if the current call returns FALSE.  Data beyond this point must be
  191.  * rescanned after resumption, so it must be preserved in case the decompressor
  192.  * decides to backtrack.
  193.  *
  194.  * Returns:
  195.  *    TRUE if additional data is available, FALSE if no data present and
  196.  *     the JPEG library should therefore suspend processing of input stream
  197.  *---------------------------------------------------------------------------*/
  198. boolean PR_CALLBACK
  199. fill_input_buffer (j_decompress_ptr jd)
  200. {
  201.     il_source_mgr *src = (il_source_mgr *)jd->src;
  202.     enum data_source_state data_source_state = src->state;
  203.     uint32 bytesToSkip, new_backtrack_buflen, new_buflen, roundup_buflen;
  204.     unsigned char *new_buffer;
  205.  
  206.     ILTRACE(5,("il:jpeg: fill, state=%d, nib=0x%x, bib=%d", data_source_state,
  207.                src->pub.next_input_byte, src->pub.bytes_in_buffer));
  208.  
  209.     switch (data_source_state) {
  210.  
  211.     /* Decompressor reached end of backtrack buffer. Return netlib buffer.*/
  212.     case dss_consuming_backtrack_buffer:
  213.         new_buffer = (unsigned char *)src->netlib_buffer;
  214.         new_buflen = src->netlib_buflen;
  215.         if ((new_buffer == NULL) || (new_buflen == 0))
  216.             goto suspend;
  217.  
  218.         /*
  219.          * Clear, so that repeated calls to fill_input_buffer() do not
  220.          * deliver the same netlib buffer more than once.
  221.          */
  222.         src->netlib_buflen = 0;
  223.         
  224.         /* Discard data if asked by skip_input_data(). */
  225.         bytesToSkip = src->bytes_to_skip;
  226.         if (bytesToSkip) {
  227.             if (bytesToSkip < new_buflen) {
  228.                 /* All done skipping bytes; Return what's left. */
  229.                 new_buffer += bytesToSkip;
  230.                 new_buflen -= bytesToSkip;
  231.                 src->bytes_to_skip = 0;
  232.             } else {
  233.                 /* Still need to skip some more data in the future */
  234.                 src->bytes_to_skip -= (size_t)new_buflen;
  235.                 goto suspend;
  236.             }
  237.         }
  238.  
  239.         /* Save old backtrack buffer parameters, in case the decompressor
  240.          * backtracks and we're forced to restore its contents.
  241.          */
  242.         src->backtrack_num_unread_bytes = src->pub.bytes_in_buffer;
  243.  
  244.         src->pub.next_input_byte = new_buffer;
  245.         src->pub.bytes_in_buffer = (size_t)new_buflen;
  246.         src->state = dss_consuming_netlib_buffer;
  247.         return TRUE;
  248.  
  249.     /* Reached end of netlib buffer. Suspend */
  250.     case dss_consuming_netlib_buffer:
  251.         if (src->pub.next_input_byte != src->netlib_buffer) {
  252.             /* Backtrack data has been permanently consumed. */
  253.             src->backtrack_num_unread_bytes = 0;
  254.             src->backtrack_buflen = 0;
  255.         }
  256.  
  257.         /* Save remainder of netlib buffer in backtrack buffer */
  258.         new_backtrack_buflen = src->pub.bytes_in_buffer + src->backtrack_buflen;
  259.                 
  260.         /* Make sure backtrack buffer is big enough to hold new data. */
  261.         if (src->backtrack_buffer_size < new_backtrack_buflen) {
  262.  
  263.             /* Round up to multiple of 16 bytes. */
  264.             roundup_buflen = ((new_backtrack_buflen + 15) >> 4) << 4;
  265.             if (src->backtrack_buffer_size) {
  266.                 src->backtrack_buffer =
  267.                     (JOCTET *)XP_REALLOC(src->backtrack_buffer, roundup_buflen);
  268.             } else {
  269.                 src->backtrack_buffer = (JOCTET*)XP_ALLOC(roundup_buflen);
  270.             }
  271.  
  272.             /* Check for OOM */
  273.             if (! src->backtrack_buffer) {
  274.                 j_common_ptr cinfo = (j_common_ptr)(&src->js->jd);
  275.                 cinfo->err->msg_code = JERR_OUT_OF_MEMORY;
  276.                 il_error_exit(cinfo);
  277.             }
  278.                 
  279.             src->backtrack_buffer_size = (size_t)roundup_buflen;
  280.  
  281.             /* Check for malformed MARKER segment lengths. */
  282.             if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH)
  283.                 il_error_exit((j_common_ptr)(&src->js->jd));
  284.         }
  285.  
  286.         /* Copy remainder of netlib buffer into backtrack buffer. */
  287.         XP_BCOPY (src->pub.next_input_byte,
  288.                   src->backtrack_buffer + src->backtrack_buflen,
  289.                   src->pub.bytes_in_buffer);
  290.  
  291.         /* Point to start of data to be rescanned. */
  292.         src->pub.next_input_byte = src->backtrack_buffer +
  293.             src->backtrack_buflen - src->backtrack_num_unread_bytes;
  294.         src->pub.bytes_in_buffer += src->backtrack_num_unread_bytes;
  295.         src->backtrack_buflen = (size_t)new_backtrack_buflen;
  296.         
  297.         src->state = dss_consuming_backtrack_buffer;
  298.         goto suspend;
  299.             
  300.     default:
  301.         XP_ASSERT(0);
  302.         return FALSE;
  303.     }
  304.  
  305.   suspend:
  306.     ILTRACE(5,("         Suspending, bib=%d", src->pub.bytes_in_buffer));
  307.     return FALSE;
  308. }
  309.  
  310. void PR_CALLBACK
  311. skip_input_data (j_decompress_ptr jd, long num_bytes)
  312. {
  313.     il_source_mgr *src = (il_source_mgr *)jd->src;
  314.  
  315. #ifdef DEBUG
  316.     ILTRACE(5, ("il:jpeg: skip_input_data js->buf=0x%x js->buflen=%d skip=%d",
  317.                 src->netlib_buffer, src->netlib_buflen,
  318.                 num_bytes));
  319. #endif
  320.  
  321.     if (num_bytes > (long)src->pub.bytes_in_buffer) {
  322.         /*
  323.          * Can't skip it all right now until we get more data from
  324.          * network stream. Set things up so that fill_input_buffer
  325.          * will skip remaining amount.
  326.          */
  327.         src->bytes_to_skip = (size_t)num_bytes - src->pub.bytes_in_buffer;
  328.         src->pub.next_input_byte += src->pub.bytes_in_buffer;
  329.         src->pub.bytes_in_buffer = 0;
  330.     } else {
  331.         /* Simple case. Just advance buffer pointer */
  332.         src->pub.bytes_in_buffer -= (size_t)num_bytes;
  333.         src->pub.next_input_byte += num_bytes;
  334.     }
  335. }
  336.  
  337.  
  338. /*
  339.  * Terminate source --- called by jpeg_finish_decompress() after all
  340.  * data has been read to clean up JPEG source manager.
  341.  */
  342. void PR_CALLBACK
  343. term_source (j_decompress_ptr jd)
  344. {
  345.     /* No work necessary here */
  346. }
  347.  
  348.  
  349. /*-----------------------------------------------------------------------------
  350.  * Setup a JPEG source object for streaming data in a demand-driven
  351.  * fashion into the IJG JPEG decompression library.     A JPEG source
  352.  * object consists of a set of callback functions which the
  353.  * decompressor library calls when it needs more data or to seek ahead
  354.  * in the input stream.
  355.  *
  356.  * Returns:
  357.  *    TRUE if setup succeeds, FALSE otherwise.
  358.  *---------------------------------------------------------------------------*/
  359. static int
  360. setup_jpeg_src (j_decompress_ptr jd, jpeg_struct *js)
  361. {
  362.     il_source_mgr *src;
  363.  
  364.     if (jd->src == NULL) {
  365.         src = XP_NEW_ZAP(il_source_mgr);
  366.         if (!src) {
  367.             XP_TRACE(("il:jpeg: src manager memory lossage"));
  368.             return FALSE;
  369.         }
  370.         jd->src = (struct jpeg_source_mgr *) src;
  371.     }
  372.  
  373.     src = (il_source_mgr *)jd->src;
  374.     src->js = js;
  375.  
  376.     /* Setup callback functions. */
  377.     src->pub.init_source = init_source;
  378.     src->pub.fill_input_buffer = fill_input_buffer;
  379.     src->pub.skip_input_data = skip_input_data;
  380.     src->pub.resync_to_restart = jpeg_resync_to_restart;
  381.     src->pub.term_source = term_source;
  382.  
  383.     return TRUE;
  384. }
  385.  
  386.  
  387.  
  388. /*
  389.  * Macros for fetching data from the data source module.
  390.  *
  391.  * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
  392.  * the current restart point; we update them only when we have reached a
  393.  * suitable place to restart if a suspension occurs.
  394.  */
  395.  
  396. /* Declare and initialize local copies of input pointer/count */
  397. #define INPUT_VARS(cinfo)  \
  398.     struct jpeg_source_mgr * datasrc = (cinfo)->src;  \
  399.     const JOCTET * next_input_byte = datasrc->next_input_byte;  \
  400.     size_t bytes_in_buffer = datasrc->bytes_in_buffer
  401.  
  402. /* Unload the local copies --- do this only at a restart boundary */
  403. #define INPUT_SYNC(cinfo)  \
  404.     ( datasrc->next_input_byte = next_input_byte,  \
  405.       datasrc->bytes_in_buffer = bytes_in_buffer )
  406.  
  407. /* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */
  408. #define INPUT_RELOAD(cinfo)  \
  409.     ( next_input_byte = datasrc->next_input_byte,  \
  410.       bytes_in_buffer = datasrc->bytes_in_buffer )
  411.  
  412. /* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
  413.  * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
  414.  * but we must reload the local copies after a successful fill.
  415.  */
  416. #define MAKE_BYTE_AVAIL(cinfo,action)  \
  417.     if (bytes_in_buffer == 0) {  \
  418.       if (! (*datasrc->fill_input_buffer) (cinfo))  \
  419.         { action; }  \
  420.       INPUT_RELOAD(cinfo);  \
  421.     }  \
  422.     bytes_in_buffer--
  423.  
  424. /* Read a byte into variable V.
  425.  * If must suspend, take the specified action (typically "return FALSE").
  426.  */
  427. #define INPUT_BYTE(cinfo,V,action)  \
  428.     MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
  429.           V = GETJOCTET(*next_input_byte++); )
  430.  
  431. /* As above, but read two bytes interpreted as an unsigned 16-bit integer.
  432.  * V should be declared unsigned int or perhaps INT32.
  433.  */
  434. #define INPUT_2BYTES(cinfo,V,action)  \
  435.     MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
  436.           V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
  437.           MAKE_BYTE_AVAIL(cinfo,action); \
  438.           V += GETJOCTET(*next_input_byte++); )
  439.  
  440.  
  441. /* Process the COM marker segment, which contains human-readable comments. */
  442. boolean PR_CALLBACK
  443. il_jpeg_COM_handler (j_decompress_ptr cinfo)
  444. {
  445.     uint length;
  446.     char *comment;
  447.     unsigned int ch;
  448.  
  449.     il_source_mgr *src = (il_source_mgr*) cinfo->src;
  450.     il_container *ic = src->js->ic;
  451.     static unsigned int lastch = 0;
  452.  
  453.     INPUT_VARS(cinfo);
  454.  
  455.     /* Get 16-bit comment length word. */
  456.     INPUT_2BYTES(cinfo, length, return FALSE);
  457.     length -= 2;            /* discount the length word itself */
  458.   
  459.     if (ic->comment)
  460.         XP_FREE(ic->comment);
  461.     comment = ic->comment = (char *)XP_ALLOC(length + 1);
  462.     ic->comment_length = length;
  463.     
  464.     if (!ic->comment) {
  465.         skip_input_data(cinfo, length + 2);
  466.         return TRUE;
  467.     }
  468.  
  469.     /* Emit the character in a readable form.
  470.      * Newlines in CR, CR/LF, or LF form will be printed as one newline.
  471.      */
  472.     while (length-- > 0) {
  473.         INPUT_BYTE(cinfo, ch, return FALSE);
  474.  
  475.         if (ch == '\r') {
  476.             *comment++ = '\n';
  477.         } else if (ch == '\n') {
  478.             if (lastch != '\r')
  479.                 *comment++ = '\n';
  480.         } else if (isprint(ch) || !ch) {
  481.             *comment++ = ch;
  482.         }
  483.         lastch = ch;
  484.     }
  485.  
  486.     *comment = 0;
  487.  
  488.     INPUT_SYNC(cinfo);
  489.  
  490.     return TRUE;
  491. }
  492.  
  493. int il_jpeg_init(il_container *ic)
  494. {
  495.     jpeg_struct *js;
  496.     j_decompress_ptr jd;
  497.     NI_ColorSpace *src_color_space = ic->src_header->color_space;
  498.     NI_RGBBits *rgb = &src_color_space->bit_alloc.rgb;
  499.  
  500.     js = XP_NEW_ZAP(jpeg_struct);
  501.     if (!js) {
  502.         XP_TRACE(("il:jpeg: jpeg_struct memory lossage"));
  503.         return FALSE;
  504.     }
  505.  
  506.     /* Init jpeg_struct */
  507.     ic->ds = js;
  508.     js->state = JPEG_HEADER;
  509.     js->samples = NULL;
  510.     js->samples3 = NULL;
  511.     js->ic = ic;
  512.  
  513.     jd = &js->jd;
  514.  
  515.     /* Install our error handler because the default is to exit(). */
  516.     jd->err = jpeg_std_error(&js->jerr.pub);
  517.     js->jerr.pub.error_exit = il_error_exit;
  518.  
  519.     /* Control returns here if an error occurs before setup completes. */
  520.     if(setjmp(js->jerr.setjmp_buffer)) {
  521.         /* Free up all the data structures */
  522.         il_jpeg_abort(ic);
  523.         return FALSE;
  524.     }
  525.  
  526. #ifdef DEBUG
  527.     if (il_debug > 20) {
  528.         jd->err->trace_level = 99;
  529.     }
  530. #endif
  531.  
  532.     
  533.     jpeg_create_decompress(jd);
  534.  
  535.     /* Setup jpeg data source object */
  536.     if (!setup_jpeg_src(jd, js)) {
  537.         XP_TRACE(("il:jpeg: jpeg source memory lossage"));
  538.         /* Free up all the data structures */
  539.         il_jpeg_abort(ic);
  540.         return FALSE;
  541.     }
  542.  
  543.     /* Insert custom COM comment marker processor. */
  544.     jpeg_set_marker_processor(jd, JPEG_COM, il_jpeg_COM_handler);
  545.  
  546.  
  547.     /* Initialize the container's source image header. */
  548.     src_color_space->type = NI_TrueColor;
  549.     src_color_space->pixmap_depth = 24;
  550.     rgb->red_bits = 8;
  551.     rgb->red_shift = 16;
  552.     rgb->green_bits = 8;
  553.     rgb->green_shift = 8;
  554.     rgb->blue_bits = 8;
  555.     rgb->blue_shift = 0;
  556.  
  557.     return TRUE;
  558. }
  559.  
  560.  
  561. /*-----------------------------------------------------------------------------
  562.  * Calling this routine sends scanlines to the front-end for display.
  563.  * Scanlines will be emitted until the entire scan has been displayed or
  564.  * until insufficient input data is available to continue output.
  565.  *
  566.  * The maximum number of scanlines to be output is controlled by the
  567.  * `num_scanlines' parameter.  Set num_scanlines to -1 to output scanlines
  568.  * until input data is exhausted.
  569.  *
  570.  * Returns:
  571.  *    TRUE if output was discontinued due to lack of input data
  572.  *  FALSE, otherwise
  573.  *---------------------------------------------------------------------------*/
  574. int
  575. output_jpeg_scanlines(il_container *ic, int num_scanlines)
  576. {
  577.     jpeg_struct *js = (jpeg_struct *)ic->ds;
  578.     j_decompress_ptr jd = &js->jd;
  579.     int input_exhausted;
  580.     int pass;
  581.     
  582. #ifdef DEBUG
  583.     uint start_scanline = jd->output_scanline;
  584. #endif
  585.  
  586.     if (js->state == JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT)
  587.         pass = IL_FINAL_PASS;
  588.     else
  589.         pass = js->completed_output_passes + 1;
  590.  
  591.     while ((jd->output_scanline < jd->output_height) && num_scanlines--) {
  592.         JSAMPROW samples;
  593.         
  594.         /* Request one scanline.  Returns 0 or 1 scanlines. */
  595.         int ns = jpeg_read_scanlines(jd, js->samples, 1);
  596.         ILTRACE(15,("il:jpeg: scanline %d, ns = %d",
  597.                     jd->output_scanline, ns));
  598.         if (ns != 1) {
  599.             ILTRACE(5,("il:jpeg: suspending scanline"));
  600.             input_exhausted = TRUE;
  601.             goto done;
  602.         }
  603.  
  604.         /* If grayscale image ... */
  605.         if (jd->output_components == 1) {
  606.             JSAMPLE j, *j1, *j1end, *j3;
  607.  
  608.             /* Convert from grayscale to RGB. */
  609.             j1 = js->samples[0];
  610.             j1end = j1 + jd->output_width;
  611.             j3 = js->samples3[0];
  612.             while (j1 < j1end) {
  613.                 j = *j1++;
  614.                 j3[0] = j;
  615.                 j3[1] = j;
  616.                 j3[2] = j;
  617.                 j3 += 3;
  618.             }
  619.             samples = js->samples3[0];
  620.         } else {        /* 24-bit color image */
  621.             samples = js->samples[0];
  622.         }
  623.  
  624.         il_emit_row(ic, 0, samples, 0, jd->output_width, jd->output_scanline-1,
  625.                     1, ilErase, pass);
  626.     }
  627.  
  628.     input_exhausted = FALSE;
  629.  
  630.   done:
  631.  
  632. #ifdef DEBUG
  633.     if (start_scanline != jd->output_scanline)
  634.         ILTRACE(4, ("il: jpeg: Input pass=%2d, next input scanline=%3d,"
  635.                     " emitted %3d - %3d\n",
  636.                     jd->input_scan_number, jd->input_iMCU_row * 16,
  637.                     start_scanline, jd->output_scanline - 1));
  638.  
  639. #endif
  640.     
  641.     return input_exhausted;
  642. }
  643.  
  644. #define JPEG_OUTPUT_CHUNK_SIZE     50000
  645.  
  646. /* Timeout durations, in milliseconds */
  647.  
  648. /* Delay between displaying chunks of pixels for the first scan. */
  649. #define JPEG_TIMEOUT_INITIAL_DELAY   100
  650.  
  651. /* Delay between displaying chunks of pixels for subsequent scans */
  652. #define JPEG_TIMEOUT_DELAY           200
  653.  
  654. static void
  655. jpeg_timeout_callback(void *closure)
  656. {
  657.     uint32 delay;
  658.     jpeg_struct *js = (jpeg_struct *)closure;
  659.     j_decompress_ptr jd = &js->jd;
  660.  
  661.     if (jd->input_scan_number == 1)
  662.         delay = JPEG_TIMEOUT_INITIAL_DELAY;
  663.     else
  664.         delay = JPEG_TIMEOUT_DELAY;
  665.  
  666.     /*
  667.      * Perform incremental display of progressive scans,
  668.      * except don't display unless enough time has elapsed
  669.      * since the previous scan was displayed.
  670.      */
  671.  
  672.     if (js->pass_num != js->completed_output_passes + 1) {
  673.         if (! jpeg_start_output(jd, jd->input_scan_number)) {
  674.             ILTRACE(1, ("il: jpeg: jpeg_start_output returned"
  675.                         "FALSE!\n"));
  676.             goto done;
  677.         }
  678.         js->pass_num = js->completed_output_passes + 1;
  679.     }
  680.     
  681.     js->timeout = NULL;
  682.  
  683.     /* If there's no more data to process for this scan,
  684.        wait until jpeg_write() wakes us up by scheduling a
  685.        new timeout */
  686.     if (output_jpeg_scanlines(js->ic, js->rows_per_chunk))
  687.         return;
  688.     
  689.     /* If we're at the end of this progressive scan ... */
  690.     if (jd->output_scanline == jd->output_height) {
  691.         if (jpeg_finish_output(jd))
  692.             js->completed_output_passes++;
  693.     }
  694.  
  695.   done:
  696.     js->timeout = FE_SetTimeout(jpeg_timeout_callback, js, delay);
  697. }
  698.  
  699. /*
  700.  * Force the display of scans, even if no data has entered the netlib
  701.  * buffer since jpeg_timeout_callback() was run.  This will flush
  702.  * pixels to the screen during a long pause in a bursty data source.
  703.  */
  704. #if 0
  705. static void
  706. jpeg_idle_callback(void *closure)
  707. {
  708.     il_container *ic = (il_container *)closure;
  709.     il_jpeg_write(ic, NULL, 0);
  710. }
  711. #endif
  712.  
  713. int
  714. il_jpeg_write(il_container *ic, const unsigned char *buf, int32 len)
  715. {
  716.     int row_stride, status;
  717.     int input_exhausted;
  718.     int error_code;
  719.  
  720.     jpeg_struct *js = (jpeg_struct *)ic->ds;
  721.     j_decompress_ptr jd = &js->jd;
  722.     il_source_mgr *src = (il_source_mgr*) js->jd.src;
  723.     NI_PixmapHeader *img_header = &ic->image->header;
  724. #ifndef M12N                    /* XXXM12N Get rid of this */
  725.     NI_PixmapHeader *src_header = ic->src_header;
  726.     NI_ColorMap *cmap = &src_header->color_space->cmap;
  727. #endif /* M12N */
  728.  
  729.     /* If this assert fires, chances are the netlib 
  730.        continued to send data after the image stream was closed. */
  731.     XP_ASSERT(js);
  732.     if (!js) {
  733. #ifdef DEBUG
  734.         XP_TRACE(("Netlib sent data after the image stream was closed\n"));
  735. #endif
  736.         return MK_IMAGE_LOSSAGE;
  737.     }
  738.     
  739.     /* Return here if there is a fatal error. */
  740.     if ((error_code = setjmp(js->jerr.setjmp_buffer))) {
  741.         /* Free up all the data structures */
  742.         il_jpeg_abort(ic);
  743.         return error_code;
  744.     }
  745.  
  746.     /* Register new buffer contents with data source manager. */
  747.     src->netlib_buffer = (JOCTET*)buf;
  748.     src->netlib_buflen = (uint32)len;
  749.  
  750.     input_exhausted = 0;
  751.     while (! input_exhausted) {
  752.         ILTRACE(5,("il:jpeg: write, state=%d, buf=0x%x, len=%d",
  753.                    js->state, buf, len));
  754.  
  755.         switch (js->state) {
  756.         case JPEG_HEADER:
  757.             if (jpeg_read_header(jd, TRUE) != JPEG_SUSPENDED) {
  758. #ifndef M12N                    /* XXXM12N Get rid of this */
  759.                 cmap->map = 0;
  760.                 cmap->num_colors = ic->cs->default_map_size;
  761. #endif /* M12N */
  762.                 ic->src_header->width = jd->image_width;
  763.                 ic->src_header->height = jd->image_height;
  764.                 if ((status = il_size(ic))) {
  765.                     XP_TRACE(("il:jpeg: MEM il_size"));
  766.                     return status;
  767.                 }
  768.  
  769.                 il_setup_color_space_converter(ic); /* XXXM12N Should check
  770.                                                        return code. */
  771.  
  772.                 js->rows_per_chunk =
  773.                     JPEG_OUTPUT_CHUNK_SIZE / img_header->widthBytes;
  774.  
  775.                 /* FIXME -- Should reset dct_method and dither mode
  776.                  * for final pass of progressive JPEG
  777.                  */
  778.                 jd->dct_method = JDCT_FASTEST;
  779.                 jd->dither_mode = JDITHER_ORDERED;
  780.                 jd->do_fancy_upsampling = FALSE;
  781.                 jd->enable_2pass_quant = FALSE;
  782.                 jd->do_block_smoothing = TRUE;
  783.                 
  784.                 /*
  785.                  * Don't allocate a giant and superfluous memory buffer
  786.                  * when the image is a sequential JPEG.
  787.                  */
  788.                 jd->buffered_image = jpeg_has_multiple_scans(jd);
  789.  
  790.                 /* Used to set up image size so arrays can be allocated */
  791.                 jpeg_calc_output_dimensions(jd);
  792.  
  793.                 /*
  794.                  * Make a one-row-high sample array that will go away
  795.                  * when done with image. Always make it big enough to
  796.                  * hold an RGB row.     Since this uses the IJG memory
  797.                  * manager, it must be allocated before the call to
  798.                  * jpeg_start_compress().
  799.                  */
  800.                 row_stride = jd->output_width * jd->output_components;
  801.                 js->samples = (*jd->mem->alloc_sarray)((j_common_ptr) jd,
  802.                                                        JPOOL_IMAGE,
  803.                                                        row_stride, 1);
  804.  
  805.                 /* Allocate RGB buffer for conversion from greyscale. */
  806.                 if (jd->output_components != 3) {
  807.                     row_stride = jd->output_width * 3;
  808.                     js->samples3 = (*jd->mem->alloc_sarray)((j_common_ptr) jd,
  809.                                                             JPOOL_IMAGE,
  810.                                                             row_stride, 1);
  811.                 }
  812.                 js->state = JPEG_START_DECOMPRESS;
  813.  
  814.             } else {
  815.                 ILTRACE(5,("il:jpeg: suspending header"));
  816.                 input_exhausted = TRUE;
  817.             }
  818.             break;
  819.  
  820.         case JPEG_START_DECOMPRESS:
  821.             if (jpeg_start_decompress(jd)) {
  822.  
  823.                 /* If this is a progressive JPEG ... */
  824.                 if (jd->buffered_image) {
  825.                     js->state = JPEG_DECOMPRESS_PROGRESSIVE;
  826.                 } else {
  827.                     js->state = JPEG_DECOMPRESS_SEQUENTIAL;
  828.                 }
  829.             }
  830.                    
  831.             break;
  832.  
  833.         case JPEG_DECOMPRESS_SEQUENTIAL:
  834.             input_exhausted = output_jpeg_scanlines(ic, -1);
  835.  
  836.             /* If we've completed image output ... */
  837.             if (jd->output_scanline == jd->output_height)
  838.                 js->state = JPEG_DONE;
  839.  
  840.             break;
  841.             
  842.         case JPEG_DECOMPRESS_PROGRESSIVE:
  843.  
  844.             /*
  845.              * Set a timeout to trigger display of the next progressive scan.
  846.              * Any scans which arrive in the intervening time will be displayed
  847.              * instead.  Thus, the decoder adapts to the data arrival rate.
  848.              */
  849.             if (js->timeout == NULL) {
  850.                 uint32 delay;
  851.  
  852.                 /*
  853.                  * First time around, display the scan a little
  854.                  * quicker than in subsequent scans.
  855.                  */
  856.                 if (jd->input_scan_number == 1)
  857.                     delay = JPEG_TIMEOUT_INITIAL_DELAY;
  858.                 else {
  859.                     delay = JPEG_TIMEOUT_DELAY;
  860.                 }
  861.                 
  862.                 js->timeout = FE_SetTimeout(jpeg_timeout_callback, js, delay);
  863.             
  864.             }
  865.  
  866.             /* Eat all the available input data in the netlib buffer. */
  867.             do {
  868.                 status = jpeg_consume_input(jd);
  869.             } while (!((status == JPEG_SUSPENDED) ||
  870.                        (status == JPEG_REACHED_EOI)));
  871.  
  872.             /* If we've parsed the whole input, do final display immediately. */
  873.             if (status == JPEG_REACHED_EOI) {
  874.                 js->state = JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT;
  875.                 break;
  876.             }
  877.             
  878.             input_exhausted = TRUE;
  879.             
  880.             break;
  881.  
  882.         case JPEG_FINAL_PROGRESSIVE_SCAN_OUTPUT:
  883.  
  884.             if ((jd->input_scan_number == jd->output_scan_number) &&
  885.                 (js->pass_num == js->completed_output_passes + 1)) {
  886.                 output_jpeg_scanlines(ic, -1);
  887.                 jpeg_finish_output(jd);
  888.             } else {
  889.  
  890.                 /* Abort the last output scan.
  891.                  * We need to redraw the whole image.
  892.                  */
  893.                 if (js->pass_num == js->completed_output_passes + 1)
  894.                     jpeg_finish_output(jd);
  895.  
  896.                 jpeg_start_output(jd, jd->input_scan_number);
  897.                 output_jpeg_scanlines(ic, -1);
  898.                 jpeg_finish_output(jd);
  899.             }
  900.  
  901.             js->state = JPEG_DONE;
  902.  
  903.             /* Fall through ... */
  904.  
  905.         case JPEG_DONE:
  906.             status = jpeg_finish_decompress(jd);
  907.             
  908.             /* Clear any pending timeouts */
  909.             if (js->timeout) {
  910.                 FE_ClearTimeout(js->timeout);
  911.                 js->timeout = NULL;
  912.             }
  913.  
  914.             input_exhausted = TRUE;
  915.             js->state = JPEG_SINK_NON_JPEG_TRAILER;  /* Be prepared for     */
  916.                                                      /* non-JPEG data after */
  917.                                                      /* EOI marker.         */
  918.             break;
  919.  
  920.         case JPEG_SINK_NON_JPEG_TRAILER: /* Ignore non-JPEG trailer, if any */
  921.             input_exhausted = TRUE;
  922.             break;
  923.  
  924.         default:
  925.             XP_ASSERT(0);
  926.             break;
  927.         }
  928.     }
  929.  
  930.     return 0;
  931. }
  932.  
  933. void
  934. il_jpeg_abort(il_container *ic)
  935. {
  936.     jpeg_struct *js = (jpeg_struct *)ic->ds;
  937.     
  938.     if (js) {
  939.         il_source_mgr *src = (il_source_mgr*) js->jd.src;
  940.  
  941.         /*
  942.          * Free up the memory that we allocated ourselves (not memory we
  943.          * allocated using the IJG memory manager - it will be freed in
  944.          * a moment.)
  945.          */
  946.         if (src) {
  947.             if (src->backtrack_buffer) {
  948.                 XP_FREE(src->backtrack_buffer);
  949.                 src->backtrack_buffer = NULL;
  950.             }
  951.             XP_FREE(src);
  952.             js->jd.src = NULL;
  953.         }
  954.  
  955.         /* Clear any pending timeouts */
  956.         if (js->timeout) {
  957.             FE_ClearTimeout(js->timeout);
  958.             js->timeout = NULL;
  959.         }
  960.         
  961.         /*
  962.          * Free all the ancillary memory used during JPEG decoding by the
  963.          * IJG JPEG library. This has the side effect of freeing up js->samples
  964.          * and js->samples3 which were allocated using the IJG memory manager.
  965.          */
  966.         jpeg_destroy_decompress(&js->jd);
  967.         js->samples = NULL;
  968.         js->samples3 = NULL;
  969.  
  970.         /* Finally, free up our private decoder structure. */
  971.         XP_FREE(js);
  972.         ic->ds = NULL;
  973.     }
  974. }
  975.  
  976. void
  977. il_jpeg_complete(il_container *ic)
  978. {
  979.     il_jpeg_abort(ic);
  980.     il_image_complete(ic);
  981.     il_frame_complete_notify(ic);
  982. }
  983.  
  984. #ifdef PROFILE
  985. #     pragma profile off
  986. #endif
  987.  
  988.