home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libimg / src / scale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  36.6 KB  |  1,044 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. /* -*- Mode: C; tab-width: 4 -*-
  20.    scale.c --- Controls rendering of scan lines to screen, including scaling
  21.                and transparency
  22. */
  23.  
  24.  
  25. /*
  26. #include "xp.h"                    Cross-platform definitions
  27. */
  28.  
  29. #include "if.h"                 /* Image library internal declarations */
  30. #include "il.h"                 /* Image library external API */
  31. #include "il_strm.h"            /* For image types. */
  32.  
  33. /* Approximate size of pixel data chunks sent to the FE for display */
  34. #ifdef XP_OS2
  35. #define OUTPUT_CHUNK_SIZE        30000
  36. #else
  37. #define OUTPUT_CHUNK_SIZE        15000
  38. #endif
  39.  
  40. /* Delay from decode to display of first scanline, in milliseconds. */
  41. #define ROW_OUTPUT_INITIAL_DELAY    50
  42.  
  43. /* Delays between subsequent sets of scanlines */
  44. #define ROW_OUTPUT_DELAY           300
  45.  
  46. /* for png */
  47. typedef struct _IL_IRGBGA {
  48.      uint8 index;
  49.     uint8 red, green, blue, gray, alpha;
  50. } IL_IRGBGA;
  51.  
  52. static void
  53. il_timeout_callback(void *closure)
  54. {
  55.     int delay;
  56.     il_container *ic = (il_container *)closure;
  57.     NI_PixmapHeader *img_header = &ic->image->header;
  58.  
  59.     ic->row_output_timeout = NULL;
  60.     if (ic->state == IC_ABORT_PENDING)
  61.         return;
  62.  
  63.     /*
  64.      * Don't schedule any more timeouts once we start decoding the
  65.      * second image in a multipart image sequence.  Instead display
  66.      * will take place when the entire image is decoded.
  67.      */
  68.     if (ic->multi &&
  69.         ((uint32)img_header->height * img_header->width < 100000)) {
  70.         return;
  71.     }
  72.     
  73.     il_flush_image_data(ic);
  74.  
  75.     delay = (ic->pass > 1) ? 2 * ROW_OUTPUT_DELAY : ROW_OUTPUT_DELAY;
  76.  
  77.     ic->row_output_timeout = FE_SetTimeout(il_timeout_callback, ic, delay);
  78. }
  79.  
  80. /*-----------------------------------------------------------------------------
  81.  * Display a specified number of rows of pixels for the purpose of
  82.  * progressive image display.  The data is accumulated without forwarding
  83.  * it to the front-end for display until either the row-output timeout
  84.  * fires or the image is fully decoded.
  85.  *---------------------------------------------------------------------------*/
  86. void
  87. il_partial(
  88.     il_container *ic,   /* The image container */
  89.     int row,            /* Starting row; zero is top row of image */
  90.     int row_count,      /* Number of rows to output, including starting row */
  91.     int pass)           /* Zero, unless  interlaced GIF,
  92.                            in which case ranges 1-4, or progressive JPEG,
  93.                            in which case ranges from 1-n. */
  94. {    
  95.     NI_PixmapHeader *img_header = &ic->image->header;
  96.  
  97.     if (!ic->new_data_for_fe) {
  98.         ic->update_start_row = row;
  99.         ic->update_end_row = row + row_count - 1;
  100.         ic->new_data_for_fe = TRUE;
  101.     } else {
  102.         if (row < ic->update_start_row)
  103.             ic->update_start_row = row;
  104.         
  105.         if ((row + row_count - 1) > ic->update_end_row)
  106.             ic->update_end_row = row + row_count - 1;
  107.     }
  108.  
  109.     ic->pass = pass;
  110.  
  111.     if (ic->img_cx->progressive_display)
  112.     {
  113. #ifdef XP_WIN
  114.         /* The last pass of an image is displayed with less delay. */
  115.         if (!ic->multi && (pass == IL_FINAL_PASS))
  116. #else
  117.             /* The first and last pass of an image are displayed with less
  118.                delay. */
  119.         if (!ic->multi && ((pass <= 1) || (pass == IL_FINAL_PASS)))
  120. #endif
  121.             {
  122.                 int num_rows = ic->update_end_row - ic->update_start_row + 1;
  123.                 if (num_rows * img_header->widthBytes > OUTPUT_CHUNK_SIZE)
  124.                     il_flush_image_data(ic);
  125.             }
  126.         
  127.         
  128.         /*
  129.          * Don't schedule any more timeouts once we start decoding the
  130.          * second image in a multipart image sequence.  Instead display
  131.          * will take place when the entire image is decoded.
  132.         */
  133.         if (ic->multi &&
  134.             ((uint32)img_header->height * img_header->width < 100000)) {
  135.             return;
  136.         }
  137.     
  138.         if (!ic->row_output_timeout){
  139.             /* Set a timer that will actually display the image data. */
  140.             ic->row_output_timeout = FE_SetTimeout(il_timeout_callback, ic,
  141.                                                    ROW_OUTPUT_INITIAL_DELAY);
  142.         }
  143.     }
  144. }
  145.  
  146.  
  147. /*-----------------------------------------------------------------------------
  148.  * Force the front-end to to display any lines in the image bitmap
  149.  * that have been decoded, but haven't yet been sent to the screen.
  150.  * (Progressively displayed images are normally displayed several
  151.  * lines at a time for efficiency.  This routine flushes out the last
  152.  * few undisplayed lines in the image.)
  153.  *---------------------------------------------------------------------------*/
  154. void
  155. il_flush_image_data(il_container *ic)
  156. {
  157.     IL_GroupContext *img_cx = ic->img_cx;
  158.     IL_Pixmap *image = ic->image;
  159.     IL_Pixmap *mask = ic->mask;
  160.     NI_PixmapHeader *img_header = &image->header;
  161.     NI_PixmapHeader *mask_header = mask ? &mask->header : NULL;
  162.     int row, start_row, end_row, row_interval;
  163.  
  164.     /* If we never called il_size(), we have no data for the FE.  There
  165.        may also be no new data if a previous flush has occurred. */
  166.     if (!image->bits || !ic->new_data_for_fe)
  167.         return;
  168.  
  169.     start_row = ic->update_start_row;
  170.     end_row = ic->update_end_row;
  171.     row_interval = (2 * OUTPUT_CHUNK_SIZE) / img_header->widthBytes;
  172.     row = start_row;
  173.  
  174. #ifdef XP_UNIX
  175.     /* If the amount of image data becomes really large, break it
  176.      * up into chunks to BLT out to the screen.  Otherwise, there
  177.      * can be a noticeable delay as the FE processes a large image.
  178.      * (In the case of the XFE, it can take a long time to send
  179.      * it to the server.)
  180.      */
  181.     for (;row < (end_row - row_interval); row += row_interval) {
  182.         IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, image, 0, row,
  183.                            img_header->width, row_interval);
  184.         if (mask)
  185.             IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, mask, 0, row,
  186.                                mask_header->width, row_interval);
  187.     }
  188. #endif /* XP_UNIX */
  189.  
  190.     /* Draw whatever is leftover after sending the chunks */
  191.     IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, image, 0, row,
  192.                        img_header->width, end_row - row + 1);
  193.     if (mask)
  194.         IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, mask, 0, row,
  195.                            mask_header->width, end_row - row + 1);
  196.  
  197.     /* Update the displayable area of the pixmap. */
  198.     ic->displayable_rect.x_origin = 0;
  199.     ic->displayable_rect.y_origin = 0;
  200.     ic->displayable_rect.width = img_header->width;
  201.     ic->displayable_rect.height = MAX(ic->displayable_rect.height,
  202.                                       end_row + 1);
  203.  
  204.     /* Notify observers that the image pixmap has been updated. */
  205.     il_pixmap_update_notify(ic);
  206.  
  207.     /* Notify observers of image progress. */
  208.     il_progress_notify(ic);
  209.  
  210.     ic->new_data_for_fe = FALSE;
  211.     ic->update_end_row = ic->update_start_row = 0;
  212. }
  213.  
  214.  
  215. /* Copy a packed RGB triple */
  216. #define COPY_RGB(src, dest)                                 \
  217.     {dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2];}
  218.  
  219. /*-----------------------------------------------------------------------------
  220.  * Scale a row of packed RGB pixels using the Bresenham algorithm.
  221.  * Output is also packed RGB pixels.
  222.  *---------------------------------------------------------------------------*/
  223. static void
  224. il_scale_RGB_row(
  225.     uint8 XP_HUGE *src, /* Source row of packed RGB pixels */
  226.     int src_len,        /* Number of pixels in source row  */
  227.     uint8 *dest,        /* Destination, packed RGB pixels */
  228.     int dest_len)       /* Length of target row, in pixels */
  229. {
  230.     uint8 *dest_end = dest + (3 * dest_len);
  231.     int n = 0;
  232.     
  233.     XP_ASSERT(dest);
  234.     XP_ASSERT(src_len != dest_len);
  235.  
  236.     /* Two cases */
  237.  
  238.     /* Scaling down ? ... */
  239.     if (src_len > dest_len)
  240.     {
  241.         while (dest < dest_end) {
  242.             COPY_RGB(src, dest);
  243.             dest += 3;
  244.             n += src_len;
  245.             while (n >= dest_len) {
  246.                 src += 3;
  247.                 n -= dest_len;
  248.             }
  249.         }
  250.     }
  251.     else
  252.     /* Scaling up. */
  253.     {
  254.         while (dest < dest_end) {
  255.             n += dest_len;
  256.             while (n >= src_len) {
  257.                 COPY_RGB(src, dest);
  258.                 dest += 3;
  259.                 n -= src_len;
  260.             }
  261.             src += 3;
  262.         }
  263.     }
  264. }
  265.  
  266. #ifdef M12N
  267. /*-----------------------------------------------------------------------------
  268.  * Scale a row of single-byte pixels using the Bresenham algorithm.
  269.  * Output is also single-byte pixels.
  270.  *---------------------------------------------------------------------------*/
  271. static void
  272. il_scale_CI_row(
  273.     uint8 XP_HUGE *src, /* Source row of packed RGB pixels */
  274.     int src_len,        /* Number of pixels in source row  */
  275.     uint8 *dest,        /* Destination, packed RGB pixels */
  276.     int dest_len,       /* Length of target row, in pixels */
  277.     uint8* indirect_map,/* image-to-FE color mapping */
  278.     int transparent_pixel_color)
  279. {
  280.     int src_pixel, mapped_src_pixel;
  281.     uint8 *dest_end = dest + dest_len;
  282.     int n = 0;
  283.     
  284.     XP_ASSERT(dest);
  285.     XP_ASSERT(src_len != dest_len);
  286.  
  287.     /* Two cases */
  288.  
  289.     /* Scaling down ? ... */
  290.     if (src_len > dest_len)
  291.     {
  292.         while (dest < dest_end) {
  293.             if (*src != transparent_pixel_color)
  294.                 *dest = indirect_map[*src];
  295.             dest ++;
  296.             n += src_len;
  297.             while (n >= dest_len) {
  298.                 src ++;
  299.                 n -= dest_len;
  300.             }
  301.         }
  302.     }
  303.     else
  304.     /* Scaling up. */
  305.     {
  306.         while (dest < dest_end) {
  307.             n += dest_len;
  308.             src_pixel = *src;
  309.             mapped_src_pixel = indirect_map[src_pixel];
  310.             while (n >= src_len) {
  311.                 if (src_pixel != transparent_pixel_color)
  312.                     *dest = mapped_src_pixel;
  313.                 dest ++;
  314.                 n -= src_len;
  315.             }
  316.             src++;
  317.         }
  318.     }
  319. }
  320. #endif /* M12N */
  321.  
  322. /* Convert row coordinate from image space to display space. */
  323. #define SCALE_YCOORD(ih, sh, y)                        \
  324.     ((int)((uint32)(y) * (ih)->height / (sh)->height))
  325.  
  326. #define SCALE_XCOORD(ih, sh, x)                        \
  327.     ((int)((uint32)(x) * (ih)->width / (sh)->width))
  328.  
  329.  
  330. /*-----------------------------------------------------------------------------
  331.  * 24 bit transparency:
  332.  * Create an alpha mask bitmap.  Perform horizontal scaling if
  333.  * requested using a Bresenham algorithm. Accumulate the mask in
  334.  * 32-bit chunks for efficiency.
  335.  *---------------------------------------------------------------------------*/
  336. static void
  337. il_alpha_mask(
  338.     int HasAlphaCh,            /* flag */
  339.     uint8 *src,                 /* RGBa, input data */
  340.     int src_len,                /* Number of pixels in source row */
  341.     int x_offset,               /* Destination offset from left edge */
  342.     uint8 XP_HUGE *maskp,       /* Output pointer, left-justified bitmask */
  343.     int mask_len,               /* Number of pixels in output row */
  344.     il_draw_mode draw_mode)     /* ilOverlay or ilErase */
  345. {
  346.     int not_transparent,n =0;
  347.     int output_bits_remaining = mask_len;
  348.  
  349.     uint32 bgmask32 = 0;        /* 32-bit temporary mask accumulators */
  350.     uint32 fgmask32 = 0;
  351.  
  352.     int mask_bit;               /* next bit to write in setmask32 */
  353.     
  354.     uint32 *m = ((uint32*)maskp) + (x_offset >> 5);
  355.     mask_bit = ~x_offset & 0x1f;
  356.  
  357.     XP_ASSERT(mask_len);
  358.  
  359.     /* Handle case in which we have a mask for a non-transparent
  360.        image.  This can happen when we have a LOSRC that is a transparent
  361.        GIF and a SRC that is a JPEG.  For now, we avoid crashing.  Later
  362.        we should fix that case so it does the right thing and gets rid
  363.        of the mask. */
  364.     if (!src)
  365.         return;
  366.  
  367. /* Add a bit to the row of mask bits.  Flush accumulator to memory if full. */
  368. #define SHIFT_IMAGE_MASK(not_transparent_flag)                                  \
  369.     {                                                                          \
  370.         fgmask32 |=  ((uint32)not_transparent_flag    ) << M32(mask_bit);     \
  371.         bgmask32 |=  ((uint32)not_transparent_flag ^ 1) << M32(mask_bit);     \
  372.                                                                               \
  373.         /* Filled up 32-bit mask word.  Write it to memory. */                  \
  374.         if (mask_bit-- == 0) {                                                \
  375.             uint32 mtmp = *m;                                                 \
  376.             mtmp |= fgmask32;                                                 \
  377.              if (draw_mode == ilErase)                                         \
  378.                 mtmp &= ~bgmask32;                                            \
  379.             *m++ = mtmp;                                                      \
  380.             mask_bit = 31;                                                      \
  381.             bgmask32 = 0;                                                     \
  382.             fgmask32 = 0;                                                     \
  383.         }                                                                      \
  384.         output_bits_remaining--;                                              \
  385.     }
  386.  
  387.  
  388.     /* Two cases */
  389.     /* Scaling down ? (or source and dest same size) ... */   
  390.  
  391.     if (src_len >= mask_len)
  392.     {      
  393.         while (output_bits_remaining ) {
  394.             not_transparent = (*(src+3) > 0x60 );
  395.             SHIFT_IMAGE_MASK(not_transparent);
  396.             n += src_len;
  397.  
  398.             while ( n >= mask_len){
  399.                 src += 4;
  400.                 n -= mask_len;
  401.             }
  402.         }
  403.     }
  404.     else  
  405.     /* Scaling up */
  406.     {
  407.         while (output_bits_remaining) {
  408.             n += mask_len;
  409.             not_transparent = (*src != 0);
  410.  
  411.             while (n >= src_len) {
  412.                 SHIFT_IMAGE_MASK(not_transparent);
  413.                 n -= src_len;
  414.             }
  415.             src++;
  416.         }
  417.  
  418.     }
  419.     
  420.     /* End of scan line. Write out any remaining mask bits. */ 
  421.     if (mask_bit < 31) {
  422.         uint32 mtmp = *m;
  423.         mtmp |= fgmask32;
  424.         if (draw_mode == ilErase)
  425.             mtmp &= ~bgmask32; 
  426.         *m = mtmp; 
  427.     }
  428.   
  429. }
  430.  
  431.  
  432. /*-----------------------------------------------------------------------------
  433.  * Create a transparency mask bitmap.  Perform horizontal scaling if
  434.  * requested using a Bresenham algorithm. Accumulate the mask in
  435.  * 32-bit chunks for efficiency.
  436.  *---------------------------------------------------------------------------*/
  437. static void
  438. il_generate_scaled_transparency_mask(
  439.     IL_IRGB *transparent_pixel,  /* The transparent pixel */
  440.     uint8 *src,                 /* Row of pixels, 8-bit pseudocolor data */
  441.     int src_len,                /* Number of pixels in source row */
  442.     int x_offset,               /* Destination offset from left edge */
  443.     uint8 XP_HUGE *maskp,       /* Output pointer, left-justified bitmask */
  444.     int mask_len,               /* Number of pixels in output row */
  445.     il_draw_mode draw_mode)     /* ilOverlay or ilErase */
  446. {
  447.     int not_transparent, n = 0;
  448.     int src_trans_pixel_index =
  449.         transparent_pixel ? transparent_pixel->index : -1;
  450.     int output_bits_remaining = mask_len;
  451.  
  452.     uint32 bgmask32 = 0;        /* 32-bit temporary mask accumulators */
  453.     uint32 fgmask32 = 0;
  454.  
  455.     int mask_bit;               /* next bit to write in setmask32 */
  456.  
  457.     uint32 *m = ((uint32*)maskp) + (x_offset >> 5);
  458.     mask_bit = ~x_offset & 0x1f;
  459.  
  460.     XP_ASSERT(mask_len);
  461.  
  462.     /* Handle case in which we have a mask for a non-transparent
  463.        image.  This can happen when we have a LOSRC that is a transparent
  464.        GIF and a SRC that is a JPEG.  For now, we avoid crashing.  Later
  465.        we should fix that case so it does the right thing and gets rid
  466.        of the mask. */
  467.     if (!src)
  468.         return;
  469.  
  470.     /* Two cases */
  471.     /* Scaling down ? (or source and dest same size) ... */
  472.     if (src_len >= mask_len)
  473.     {
  474.         while (output_bits_remaining) {
  475.             not_transparent = (*src != src_trans_pixel_index);
  476.  
  477.             SHIFT_IMAGE_MASK(not_transparent);
  478.             n += src_len;
  479.  
  480.             while (n >= mask_len) {
  481.                 src++;
  482.                 n -= mask_len;
  483.             }
  484.         }
  485.     }
  486.     else
  487.     /* Scaling up */
  488.     {
  489.         while (output_bits_remaining) {
  490.             n += mask_len;
  491.             not_transparent = (*src != src_trans_pixel_index);
  492.  
  493.             while (n >= src_len) {
  494.                 SHIFT_IMAGE_MASK(not_transparent);
  495.                 n -= src_len;
  496.             }
  497.             src++;
  498.         }
  499.     }
  500.     
  501.     /* End of scan line. Write out any remaining mask bits. */ 
  502.     if (mask_bit < 31) {
  503.         uint32 mtmp = *m;
  504.         mtmp |= fgmask32;
  505.         if (draw_mode == ilErase)
  506.             mtmp &= ~bgmask32; 
  507.         *m = mtmp; 
  508.     }
  509.  
  510. #undef SHIFT_IMAGE_MASK    
  511. }
  512.  
  513.  
  514. /*-----------------------------------------------------------------------------
  515.  * When color quantization (possibly accompanied by dithering) takes
  516.  * place, the background pixels in a transparent image that overlays a
  517.  * solid-color background, e.g. <BODY BGCOLOR=#c5c5c5>, will get
  518.  * mapped to a color in the color-cube.  The real background color,
  519.  * however, may not be one of these colors reserved for images.  This
  520.  * routine serves to return transparent pixels to their background
  521.  * color.  This routine must performing scaling because the source
  522.  * pixels are in the image space and the target pixels are in the
  523.  * display space.
  524.  *---------------------------------------------------------------------------*/
  525. static void
  526. il_reset_background_pixels(
  527.     il_container *ic,    /* The image container */
  528.     uint8 *src,          /* Row of pixels, 8-bit pseudocolor data */
  529.     int src_len,         /* Number of pixels in row */
  530.     uint8 XP_HUGE *dest, /* Output pointer, 8-bit pseudocolor data */
  531.     int dest_len)        /* Width of output pixel row */
  532. {
  533.     int is_transparent, n = 0;
  534.     uint8 XP_HUGE *dest_end = dest + dest_len;
  535.     NI_PixmapHeader *img_header = &ic->image->header;
  536.     int src_trans_pixel_index = ic->src_header->transparent_pixel->index;
  537.     int img_trans_pixel_index = img_header->transparent_pixel->index;
  538.     int dpy_trans_pixel_index =
  539.         img_header->color_space->cmap.index[img_trans_pixel_index];
  540.  
  541.     /* Two cases */
  542.  
  543.     /* Scaling down ? (or not scaling ?) ... */
  544.     if (src_len >= dest_len) {
  545.         while (dest < dest_end) {
  546.             is_transparent = (*src == src_trans_pixel_index);
  547.             if (is_transparent)
  548.                 *dest = dpy_trans_pixel_index;
  549.             dest++;
  550.             n += src_len;
  551.  
  552.             while (n >= dest_len) {
  553.                 src++;
  554.                 n -= dest_len;
  555.             }
  556.         }
  557.     } else {
  558.     /* Scaling up */
  559.         while (dest < dest_end) {
  560.             n += dest_len;
  561.             is_transparent = (*src++ == src_trans_pixel_index);
  562.             
  563.             if (is_transparent)
  564.                 while (n >= src_len) {
  565.                     *dest++ = dpy_trans_pixel_index;
  566.                     n -= src_len;
  567.                 }
  568.             else
  569.                 while (n >= src_len) {
  570.                     dest++;
  571.                     n -= src_len;
  572.                 }
  573.         }
  574.     }
  575. }
  576.  
  577. static void
  578. il_generate_byte_mask(
  579.     il_container *ic,    /* The image container */
  580.     uint8 *src,          /* Row of pixels, 8-bit pseudocolor data */
  581.     int src_len,         /* Number of pixels in row */
  582.     uint8 *dest,         /* Output pointer, 8-bit pseudocolor data */
  583.     int dest_len)        /* Width of output pixel row */
  584. {
  585.     int is_transparent, n = 0;
  586.     uint8 XP_HUGE *dest_end = dest + dest_len;
  587.     int src_trans_pixel_index = ic->src_header->transparent_pixel->index;
  588.  
  589.     /* Two cases */
  590.  
  591.     /* Scaling down ? (or not scaling ?) ... */
  592.     if (src_len >= dest_len) {
  593.         while (dest < dest_end) {
  594.             is_transparent = (*src == src_trans_pixel_index);
  595.             *dest = is_transparent - 1;
  596.             dest++;
  597.             n += src_len;
  598.  
  599.             while (n >= dest_len) {
  600.                 src++;
  601.                 n -= dest_len;
  602.             }
  603.         }
  604.     } else {
  605.     /* Scaling up */
  606.         while (dest < dest_end) {
  607.             n += dest_len;
  608.             is_transparent = (*src++ == src_trans_pixel_index);
  609.             
  610.             if (is_transparent)
  611.                 while (n >= src_len) {
  612.                     *dest++ = 0;
  613.                     n -= src_len;
  614.                 }
  615.             else
  616.                 while (n >= src_len) {
  617.                     *dest++ = (uint8)-1;
  618.                     n -= src_len;
  619.                 }
  620.         }
  621.     }
  622. }
  623.  
  624. static void
  625. il_overlay(uint8 *src, uint8 *dest, uint8 *byte_mask, int num_cols,
  626.            int bytes_per_pixel)
  627. {
  628.     int i, col;
  629. #if 0
  630.     uint8 *s = src;
  631.     uint8 *s_end = src + (num_cols * bytes_per_pixel);
  632. #endif
  633.     for (col = num_cols; col > 0; col--) {
  634.         if (*byte_mask++) {
  635.             for (i = bytes_per_pixel-1; i >= 0; i--) {
  636.                 dest[i] = src[i];
  637.             }
  638.         }
  639.         dest += bytes_per_pixel;
  640.         src += bytes_per_pixel;
  641.     }
  642. }
  643.  
  644. static uint8 il_tmpbuf[MAX_IMAGE_WIDTH];
  645.     
  646. /*-----------------------------------------------------------------------------
  647.  *  Emit a complete row of pixel data into the image.  This routine
  648.  *  provides any necessary conversion to the display depth, optional dithering
  649.  *  for pseudocolor displays, scaling and transparency, including mask
  650.  *  generation, if necessary.  If sufficient data is accumulated, the screen
  651.  *  image is updated, as well.
  652.  *---------------------------------------------------------------------------*/
  653. void
  654. il_emit_row(
  655.     il_container *ic,   /* The image container */
  656.     uint8 *cbuf,        /* Color index data source, or NULL if source
  657.                            is RGB data */
  658.     uint8 *rgbbuf,      /* Packed RGBa data or RGBa workspace if <cbuf> != NULL */
  659.     int x_offset,       /* First column to write data into */
  660.     int len,            /* Width of source image, in pixels */
  661.     int row,            /* Starting row of image */
  662.     int dup_row_count,          /* Number of times to duplicate row */
  663.     il_draw_mode draw_mode,     /* ilOverlay or ilErase */
  664.     int pass)           /* Zero, unless  interlaced GIF,
  665.                            in which case ranges 1-4, or progressive JPEG,
  666.                            in which case ranges from 1-n. */
  667. {
  668.     IL_GroupContext *img_cx = ic->img_cx;
  669.     IL_Pixmap *image = ic->image;
  670.     IL_Pixmap *mask = ic->mask;
  671.     NI_PixmapHeader *src_header = ic->src_header;
  672.     NI_PixmapHeader *img_header = &image->header;
  673.     NI_PixmapHeader *mask_header;
  674.     NI_ColorSpace *src_color_space = src_header->color_space;
  675.     NI_ColorSpace *img_color_space = img_header->color_space;
  676.     uint8 XP_HUGE *out;
  677.     uint8 XP_HUGE *dp;
  678.     uint8 XP_HUGE *mp;
  679.     uint8 XP_HUGE *maskp = NULL;
  680.     uint8 *byte_mask = NULL;
  681.     uint8 XP_HUGE *srcbuf = rgbbuf;
  682.     uint8 *p = cbuf;
  683.     uint8 *pl = cbuf+len;
  684.     int drow_start, drow_end, row_count, color_index, dup, do_dither;
  685.     int dcolumn_start, dcolumn_end, column_count, offset, src_len, dest_len;
  686.    
  687.     XP_ASSERT(row >= 0);
  688.  
  689.     if(row >= src_header->height) {
  690.         ILTRACE(2,("il: ignoring extra row (%d)", row));
  691.         return;
  692.     }
  693.  
  694.     /* Set first and last destination row in the image.  Assume no scaling. */
  695.     drow_start = row;
  696.     drow_end = row + dup_row_count - 1;
  697.     dcolumn_start = x_offset;
  698.     dcolumn_end = x_offset + len - 1;
  699.  
  700.     /* If scaling, convert vertical image coordinates to display space. */
  701.     if (img_header->height != src_header->height) {
  702.         int d = drow_start;
  703.         int next_drow_start = SCALE_YCOORD(img_header, src_header, drow_end+1);
  704.         drow_start = SCALE_YCOORD(img_header, src_header, drow_start);
  705.  
  706.         /*
  707.          * Don't emit a row of pixels that will be overwritten later.
  708.          * (as may happen during when images are being reduced vertically).
  709.          */
  710.         if (drow_start == next_drow_start) {
  711.             /*
  712.              * Except that the bottom line of pixels can never be
  713.              * overwritten by a subsequent line.
  714.              */
  715.             if (d != (src_header->height - 1))
  716.                 return;
  717.             else
  718.                 drow_end = drow_start;
  719.         } else {
  720.             drow_end = next_drow_start - 1;
  721.             if (drow_end >= img_header->height)
  722.                 drow_end = img_header->height - 1;
  723.         }
  724.     }
  725.  
  726.     /* If scaling, convert horizontal image coordinates to display space. */
  727.     if (img_header->width != src_header->width) {
  728.         int d = dcolumn_start;
  729.         int next_dcolumn_start = SCALE_XCOORD(img_header, src_header,
  730.                                               dcolumn_end+1);
  731.         dcolumn_start = SCALE_XCOORD(img_header, src_header, dcolumn_start);
  732.  
  733.         /*
  734.          * Don't emit a column of pixels that will be overwritten later.
  735.          * (as may happen during when images are being reduced vertically).
  736.          */
  737.         if (dcolumn_start == next_dcolumn_start) {
  738.             /*
  739.              * Except that the right column of pixels can never be
  740.              * overwritten by a subsequent column.
  741.              */
  742.             if (d != (src_header->width - 1))
  743.                 return;
  744.             else
  745.                 dcolumn_end = dcolumn_start;
  746.         } else {
  747.             dcolumn_end = next_dcolumn_start - 1;
  748.             if (dcolumn_end >= img_header->width)
  749.                 dcolumn_end = img_header->width - 1;
  750.         }
  751.     }
  752.  
  753.     /* Number of pixel rows and columns to emit into framebuffer */
  754.     row_count = drow_end - drow_start + 1;
  755.     column_count = dcolumn_end - dcolumn_start + 1;
  756.  
  757.     /* If a transparent image appears over a background image ... */
  758.     if (mask) {
  759.         mask_header = &mask->header;
  760.  
  761.         /* Bug, we retain the mask from a transparent
  762.            LOSRC GIF when the SRC is a JPEG. */
  763.         /* XP_ASSERT(cbuf); */
  764.         
  765.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, mask,
  766.                                 IL_LOCK_BITS);
  767.  
  768. #ifdef _USD
  769.         maskp = (uint8 XP_HUGE *)mask->bits + 
  770.             (mask_header->height - drow_start - 1) * mask_header->widthBytes;
  771. #else
  772.         maskp = (uint8 XP_HUGE *)mask->bits +
  773.             drow_start * mask_header->widthBytes;
  774. #endif
  775.        
  776.         if(!ic->image->header.is_interleaved_alpha){
  777.             il_generate_scaled_transparency_mask(src_header->transparent_pixel,
  778.                                              cbuf, (int)len,
  779.                                              dcolumn_start,
  780.                                              maskp, column_count,
  781.                                              draw_mode);                
  782.         }else{ /* is alpha */
  783.  
  784.             uint8 *tmpbuf;
  785.             int i;
  786.  
  787.             il_alpha_mask(1,rgbbuf, (int)len, dcolumn_start, 
  788.                 maskp, column_count,draw_mode);                
  789.  
  790.             tmpbuf = rgbbuf;
  791.             for(i=0; i<column_count; i++){
  792.                 *rgbbuf++ = *tmpbuf++;
  793.                 *rgbbuf++ = *tmpbuf++;
  794.                 *rgbbuf++ = *tmpbuf++;
  795.                 tmpbuf++;  /* strip off alpha channel */
  796.             }
  797.         
  798.         }
  799.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, mask,
  800.                                 IL_UNLOCK_BITS);
  801.     }
  802.  
  803.     if (!ic->converter) {
  804.  
  805. #ifndef M12N /* XXXM12N fixme */
  806.         int i;
  807.         int src_trans_pixel_index;
  808.         uint8 XP_HUGE * dest;
  809.         uint8 *indirect_map = ic->cs->current_indirect_map;/* XXXM12N fixme */
  810.  
  811.         if ((draw_mode == ilErase) || !src_header->transparent_pixel)
  812.             src_trans_pixel_index = -1; /* no transparency */
  813.         else
  814.             src_trans_pixel_index = src_header->transparent_pixel->index;
  815.  
  816.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
  817.                                 IL_LOCK_BITS);
  818.  
  819.         /* No converter, image is already rendered in pseudocolor. */
  820. #ifdef _USD
  821.         out = (uint8 XP_HUGE *)image->bits +
  822.             (img_header->height - drow_start - 1) * img_header->widthBytes;
  823. #else
  824.         out = (uint8 XP_HUGE *)image->bits +
  825.             drow_start * img_header->widthBytes;
  826. #endif
  827.  
  828.         dest = out + dcolumn_start;
  829.         
  830.         /* If horizontal scaling ... */
  831.         if (len != column_count) {
  832.             il_scale_CI_row(cbuf, len, dest, column_count,
  833.                             indirect_map, src_trans_pixel_index);
  834.         } else {
  835.  
  836.             /* Convert to FE's palette indices */
  837.             for (i = 0; i < len; i++)
  838.                 if (cbuf[i] != src_trans_pixel_index)
  839.                     dest[i] = indirect_map[cbuf[i]];
  840.         }
  841.  
  842.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
  843.                                 IL_UNLOCK_BITS);
  844. #endif /* M12N */
  845.  
  846.     } else {
  847.  
  848.         /* Generate the output row in RGB space, regardless of screen depth. */
  849.         if (cbuf) {
  850.             uint8 *r = rgbbuf;
  851.             IL_RGB *map = src_color_space->cmap.map, *entry;
  852.  
  853.             if (!src_header->transparent_pixel) {
  854.                 /* Simple case: no transparency */
  855.                 while (p < pl) {
  856.                     color_index = *p++;
  857.                     entry = map + color_index;
  858.                     r[0] = entry->red;
  859.                     r[1] = entry->green;
  860.                     r[2] = entry->blue;
  861.                     r += 3 ;
  862.                 }
  863.             } else {
  864.                 /*
  865.                  * There are two kinds of transparency, depending on whether
  866.                  * the image is overlaying:
  867.                  *   1) a solid color background, or
  868.                  *   2) another image
  869.                  *
  870.                  * The first case is easy.  We just substitute the background
  871.                  * color for all the transparent pixels in the image.  No mask
  872.                  * is necessary.  The second case requires that we generate a
  873.                  * bit mask (see the code above).  It also seems to require that
  874.                  * all the transparent pixels in the image be set to black.
  875.                  * XXX - Why ?  Is this some platform-specific thing ? - fur
  876.                  */
  877.                 int background_r, background_g, background_b;
  878.                 IL_IRGB *src_trans_pixel = src_header->transparent_pixel;
  879.                 int src_trans_pixel_index = src_trans_pixel->index;
  880.  
  881.                 background_r = background_g = background_b = 0;
  882.                 if (!ic->mask) {
  883.                     /* Solid background color */
  884.                     background_r = src_trans_pixel->red;
  885.                     background_g = src_trans_pixel->green;
  886.                     background_b = src_trans_pixel->blue;
  887.                 }
  888.                 
  889.                 /* Remap transparent pixels */
  890.                 while (p < pl) {
  891.                     color_index = *p++;
  892.                     if (color_index == src_trans_pixel_index) {
  893.                         r[0] = background_r;
  894.                         r[1] = background_g;
  895.                         r[2] = background_b;
  896.                         r += 3;
  897.                     } else {
  898.                         entry = map + color_index;
  899.                         r[0] = entry->red;
  900.                         r[1] = entry->green;
  901.                         r[2] = entry->blue;
  902.                         r += 3;
  903.                     }
  904.                 }
  905.             }
  906.         }
  907.  
  908.  
  909.         /* Now we are in RGB space. */
  910.  
  911.         /* Simple anamorphic scaling (in RGB space for now) */
  912.         src_len = len;
  913.         dest_len = column_count;
  914.         if (src_len != dest_len) {
  915.             uint8 XP_HUGE *src = rgbbuf;
  916.             uint8 *dest = ic->scalerow;
  917.             srcbuf = dest;
  918.  
  919.             /* Scale the pixel data (mask data already scaled) */
  920.             il_scale_RGB_row(src, src_len, dest, dest_len);
  921.         }
  922.  
  923.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
  924.                                 IL_LOCK_BITS);
  925.  
  926. #ifdef _USD
  927.         out = (uint8 XP_HUGE *)image->bits +
  928.             (img_header->height-drow_start-1) * (uint32)img_header->widthBytes;
  929. #else
  930.         out = (uint8 XP_HUGE *)image->bits +
  931.             drow_start * img_header->widthBytes;
  932. #endif
  933.  
  934.         if (src_header->transparent_pixel && (draw_mode == ilOverlay))
  935.         {
  936.             if( cbuf ){
  937.                 il_generate_byte_mask(ic, cbuf, len, il_tmpbuf, column_count);
  938.                 byte_mask = il_tmpbuf;
  939.             }
  940.         }
  941.  
  942.         
  943.         /*
  944.          * Convert RGB to display depth.  If display is pseudocolor, this may
  945.          * also color-quantize and dither.
  946.          */
  947.         (*ic->converter)(ic, byte_mask, srcbuf, dcolumn_start,
  948.                          column_count, out);
  949.  
  950.         IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
  951.                                 IL_UNLOCK_BITS);
  952.  
  953.         /*
  954.          * Have to reset transparent pixels to background color
  955.          * because color quantization may have mutated them.
  956.          */
  957.         if (src_header->transparent_pixel &&
  958.             (img_color_space->type == NI_PseudoColor) &&
  959.             !mask && (draw_mode == ilErase))
  960.             il_reset_background_pixels(ic, cbuf, len,
  961.                                        out + dcolumn_start, column_count);
  962.     }
  963.  
  964.     /*
  965.      * We now have one row of pixels and, if required for transparency, a row
  966.      * of mask data.  If the pixels in this row of the image cover span more
  967.      * than one pixel vertically when displayed, the row needs to be
  968.      * replicated in the framebuffer.  (This replication is necessary when
  969.      * displaying interlaced GIFs and/or vertical scaling of any image type.)
  970.      * Actually, pixel rows are not simply copied: Dithering may need to be
  971.      * applied on a line-by-line basis.
  972.      */
  973.     dp = out;
  974.     mp = maskp;
  975.     dup = row_count - 1;
  976.     offset = dcolumn_start * (img_color_space->pixmap_depth / 8);
  977.  
  978. #ifndef M12N                    /* Clean this up */
  979.     if (ic->image->pixmap_depth == 1)
  980.         do_dither = TRUE;
  981.     else
  982.         do_dither = ic->converter && (row_count <= 4) &&
  983.             ((ic->dither_mode == IL_Dither) || (ic->type == IL_JPEG));
  984. #else
  985.     do_dither = (ic->dither_mode == IL_Dither);
  986.     if ((ic->type == IL_GIF) && (!ic->converter || (row_count > 4)))
  987.         do_dither = FALSE;
  988.    
  989. #endif /* M12N */   
  990.  
  991.     while (dup--) {
  992. #ifdef _USD
  993.         dp -= img_header->widthBytes;
  994.         if (mask)
  995.             mp -= mask_header->widthBytes;
  996. #else
  997.         dp += img_header->widthBytes;
  998.         if (mask)
  999.             mp += mask_header->widthBytes;
  1000. #endif
  1001.         /* Is dithering being done (either mono or pseudocolor) ... ? */
  1002.         if (do_dither) {
  1003.             
  1004.             /* Dither / color-quantize */
  1005.             (*ic->converter)(ic, byte_mask, srcbuf, dcolumn_start,
  1006.                              column_count, dp);
  1007.  
  1008.             /*
  1009.              * Have to reset transparent pixels to background color
  1010.              * because color quantization may have mutated them.
  1011.              */
  1012.             if (img_header->transparent_pixel &&
  1013.                 (img_color_space->type == NI_PseudoColor) &&
  1014.                 !mask && (draw_mode == ilErase))
  1015.                 il_reset_background_pixels(ic, cbuf, len, dp + dcolumn_start,
  1016.                                            column_count);
  1017.         } else {
  1018.             /* If no dithering, each row of pixels is exactly the same. */
  1019.             if (byte_mask)
  1020.                 il_overlay(out + offset, dp + offset, byte_mask, column_count,
  1021.                            (img_color_space->pixmap_depth/8));
  1022.             else
  1023.                 XP_MEMCPY(dp + offset, out + offset,
  1024.                           (img_color_space->pixmap_depth/8) * column_count);
  1025.         }
  1026.  
  1027.         /* Duplicate the mask also. */
  1028.         if (maskp) {
  1029.             if (column_count == img_header->width) /* easy case */
  1030.                 XP_MEMCPY(mp, maskp, mask_header->widthBytes);
  1031.             else
  1032.                 il_generate_scaled_transparency_mask(
  1033.                     img_header->transparent_pixel, cbuf, (int)len,
  1034.                     dcolumn_start, mp, column_count, draw_mode);
  1035.         }
  1036.     }
  1037.  
  1038.  
  1039.     /* If enough rows accumulated, send to the front-end for display. */
  1040.     il_partial(ic, drow_start, row_count, pass);
  1041. }
  1042.  
  1043.  
  1044.