home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /* -*- Mode: C; tab-width: 4 -*-
- scale.c --- Controls rendering of scan lines to screen, including scaling
- and transparency
- */
-
-
- /*
- #include "xp.h" Cross-platform definitions
- */
-
- #include "if.h" /* Image library internal declarations */
- #include "il.h" /* Image library external API */
- #include "il_strm.h" /* For image types. */
-
- /* Approximate size of pixel data chunks sent to the FE for display */
- #ifdef XP_OS2
- #define OUTPUT_CHUNK_SIZE 30000
- #else
- #define OUTPUT_CHUNK_SIZE 15000
- #endif
-
- /* Delay from decode to display of first scanline, in milliseconds. */
- #define ROW_OUTPUT_INITIAL_DELAY 50
-
- /* Delays between subsequent sets of scanlines */
- #define ROW_OUTPUT_DELAY 300
-
- /* for png */
- typedef struct _IL_IRGBGA {
- uint8 index;
- uint8 red, green, blue, gray, alpha;
- } IL_IRGBGA;
-
- static void
- il_timeout_callback(void *closure)
- {
- int delay;
- il_container *ic = (il_container *)closure;
- NI_PixmapHeader *img_header = &ic->image->header;
-
- ic->row_output_timeout = NULL;
- if (ic->state == IC_ABORT_PENDING)
- return;
-
- /*
- * Don't schedule any more timeouts once we start decoding the
- * second image in a multipart image sequence. Instead display
- * will take place when the entire image is decoded.
- */
- if (ic->multi &&
- ((uint32)img_header->height * img_header->width < 100000)) {
- return;
- }
-
- il_flush_image_data(ic);
-
- delay = (ic->pass > 1) ? 2 * ROW_OUTPUT_DELAY : ROW_OUTPUT_DELAY;
-
- ic->row_output_timeout = FE_SetTimeout(il_timeout_callback, ic, delay);
- }
-
- /*-----------------------------------------------------------------------------
- * Display a specified number of rows of pixels for the purpose of
- * progressive image display. The data is accumulated without forwarding
- * it to the front-end for display until either the row-output timeout
- * fires or the image is fully decoded.
- *---------------------------------------------------------------------------*/
- void
- il_partial(
- il_container *ic, /* The image container */
- int row, /* Starting row; zero is top row of image */
- int row_count, /* Number of rows to output, including starting row */
- int pass) /* Zero, unless interlaced GIF,
- in which case ranges 1-4, or progressive JPEG,
- in which case ranges from 1-n. */
- {
- NI_PixmapHeader *img_header = &ic->image->header;
-
- if (!ic->new_data_for_fe) {
- ic->update_start_row = row;
- ic->update_end_row = row + row_count - 1;
- ic->new_data_for_fe = TRUE;
- } else {
- if (row < ic->update_start_row)
- ic->update_start_row = row;
-
- if ((row + row_count - 1) > ic->update_end_row)
- ic->update_end_row = row + row_count - 1;
- }
-
- ic->pass = pass;
-
- if (ic->img_cx->progressive_display)
- {
- #ifdef XP_WIN
- /* The last pass of an image is displayed with less delay. */
- if (!ic->multi && (pass == IL_FINAL_PASS))
- #else
- /* The first and last pass of an image are displayed with less
- delay. */
- if (!ic->multi && ((pass <= 1) || (pass == IL_FINAL_PASS)))
- #endif
- {
- int num_rows = ic->update_end_row - ic->update_start_row + 1;
- if (num_rows * img_header->widthBytes > OUTPUT_CHUNK_SIZE)
- il_flush_image_data(ic);
- }
-
-
- /*
- * Don't schedule any more timeouts once we start decoding the
- * second image in a multipart image sequence. Instead display
- * will take place when the entire image is decoded.
- */
- if (ic->multi &&
- ((uint32)img_header->height * img_header->width < 100000)) {
- return;
- }
-
- if (!ic->row_output_timeout){
- /* Set a timer that will actually display the image data. */
- ic->row_output_timeout = FE_SetTimeout(il_timeout_callback, ic,
- ROW_OUTPUT_INITIAL_DELAY);
- }
- }
- }
-
-
- /*-----------------------------------------------------------------------------
- * Force the front-end to to display any lines in the image bitmap
- * that have been decoded, but haven't yet been sent to the screen.
- * (Progressively displayed images are normally displayed several
- * lines at a time for efficiency. This routine flushes out the last
- * few undisplayed lines in the image.)
- *---------------------------------------------------------------------------*/
- void
- il_flush_image_data(il_container *ic)
- {
- IL_GroupContext *img_cx = ic->img_cx;
- IL_Pixmap *image = ic->image;
- IL_Pixmap *mask = ic->mask;
- NI_PixmapHeader *img_header = &image->header;
- NI_PixmapHeader *mask_header = mask ? &mask->header : NULL;
- int row, start_row, end_row, row_interval;
-
- /* If we never called il_size(), we have no data for the FE. There
- may also be no new data if a previous flush has occurred. */
- if (!image->bits || !ic->new_data_for_fe)
- return;
-
- start_row = ic->update_start_row;
- end_row = ic->update_end_row;
- row_interval = (2 * OUTPUT_CHUNK_SIZE) / img_header->widthBytes;
- row = start_row;
-
- #ifdef XP_UNIX
- /* If the amount of image data becomes really large, break it
- * up into chunks to BLT out to the screen. Otherwise, there
- * can be a noticeable delay as the FE processes a large image.
- * (In the case of the XFE, it can take a long time to send
- * it to the server.)
- */
- for (;row < (end_row - row_interval); row += row_interval) {
- IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, image, 0, row,
- img_header->width, row_interval);
- if (mask)
- IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, mask, 0, row,
- mask_header->width, row_interval);
- }
- #endif /* XP_UNIX */
-
- /* Draw whatever is leftover after sending the chunks */
- IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, image, 0, row,
- img_header->width, end_row - row + 1);
- if (mask)
- IMGCBIF_UpdatePixmap(img_cx->img_cb, img_cx->dpy_cx, mask, 0, row,
- mask_header->width, end_row - row + 1);
-
- /* Update the displayable area of the pixmap. */
- ic->displayable_rect.x_origin = 0;
- ic->displayable_rect.y_origin = 0;
- ic->displayable_rect.width = img_header->width;
- ic->displayable_rect.height = MAX(ic->displayable_rect.height,
- end_row + 1);
-
- /* Notify observers that the image pixmap has been updated. */
- il_pixmap_update_notify(ic);
-
- /* Notify observers of image progress. */
- il_progress_notify(ic);
-
- ic->new_data_for_fe = FALSE;
- ic->update_end_row = ic->update_start_row = 0;
- }
-
-
- /* Copy a packed RGB triple */
- #define COPY_RGB(src, dest) \
- {dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2];}
-
- /*-----------------------------------------------------------------------------
- * Scale a row of packed RGB pixels using the Bresenham algorithm.
- * Output is also packed RGB pixels.
- *---------------------------------------------------------------------------*/
- static void
- il_scale_RGB_row(
- uint8 XP_HUGE *src, /* Source row of packed RGB pixels */
- int src_len, /* Number of pixels in source row */
- uint8 *dest, /* Destination, packed RGB pixels */
- int dest_len) /* Length of target row, in pixels */
- {
- uint8 *dest_end = dest + (3 * dest_len);
- int n = 0;
-
- XP_ASSERT(dest);
- XP_ASSERT(src_len != dest_len);
-
- /* Two cases */
-
- /* Scaling down ? ... */
- if (src_len > dest_len)
- {
- while (dest < dest_end) {
- COPY_RGB(src, dest);
- dest += 3;
- n += src_len;
- while (n >= dest_len) {
- src += 3;
- n -= dest_len;
- }
- }
- }
- else
- /* Scaling up. */
- {
- while (dest < dest_end) {
- n += dest_len;
- while (n >= src_len) {
- COPY_RGB(src, dest);
- dest += 3;
- n -= src_len;
- }
- src += 3;
- }
- }
- }
-
- #ifdef M12N
- /*-----------------------------------------------------------------------------
- * Scale a row of single-byte pixels using the Bresenham algorithm.
- * Output is also single-byte pixels.
- *---------------------------------------------------------------------------*/
- static void
- il_scale_CI_row(
- uint8 XP_HUGE *src, /* Source row of packed RGB pixels */
- int src_len, /* Number of pixels in source row */
- uint8 *dest, /* Destination, packed RGB pixels */
- int dest_len, /* Length of target row, in pixels */
- uint8* indirect_map,/* image-to-FE color mapping */
- int transparent_pixel_color)
- {
- int src_pixel, mapped_src_pixel;
- uint8 *dest_end = dest + dest_len;
- int n = 0;
-
- XP_ASSERT(dest);
- XP_ASSERT(src_len != dest_len);
-
- /* Two cases */
-
- /* Scaling down ? ... */
- if (src_len > dest_len)
- {
- while (dest < dest_end) {
- if (*src != transparent_pixel_color)
- *dest = indirect_map[*src];
- dest ++;
- n += src_len;
- while (n >= dest_len) {
- src ++;
- n -= dest_len;
- }
- }
- }
- else
- /* Scaling up. */
- {
- while (dest < dest_end) {
- n += dest_len;
- src_pixel = *src;
- mapped_src_pixel = indirect_map[src_pixel];
- while (n >= src_len) {
- if (src_pixel != transparent_pixel_color)
- *dest = mapped_src_pixel;
- dest ++;
- n -= src_len;
- }
- src++;
- }
- }
- }
- #endif /* M12N */
-
- /* Convert row coordinate from image space to display space. */
- #define SCALE_YCOORD(ih, sh, y) \
- ((int)((uint32)(y) * (ih)->height / (sh)->height))
-
- #define SCALE_XCOORD(ih, sh, x) \
- ((int)((uint32)(x) * (ih)->width / (sh)->width))
-
-
- /*-----------------------------------------------------------------------------
- * 24 bit transparency:
- * Create an alpha mask bitmap. Perform horizontal scaling if
- * requested using a Bresenham algorithm. Accumulate the mask in
- * 32-bit chunks for efficiency.
- *---------------------------------------------------------------------------*/
- static void
- il_alpha_mask(
- int HasAlphaCh, /* flag */
- uint8 *src, /* RGBa, input data */
- int src_len, /* Number of pixels in source row */
- int x_offset, /* Destination offset from left edge */
- uint8 XP_HUGE *maskp, /* Output pointer, left-justified bitmask */
- int mask_len, /* Number of pixels in output row */
- il_draw_mode draw_mode) /* ilOverlay or ilErase */
- {
- int not_transparent,n =0;
- int output_bits_remaining = mask_len;
-
- uint32 bgmask32 = 0; /* 32-bit temporary mask accumulators */
- uint32 fgmask32 = 0;
-
- int mask_bit; /* next bit to write in setmask32 */
-
- uint32 *m = ((uint32*)maskp) + (x_offset >> 5);
- mask_bit = ~x_offset & 0x1f;
-
- XP_ASSERT(mask_len);
-
- /* Handle case in which we have a mask for a non-transparent
- image. This can happen when we have a LOSRC that is a transparent
- GIF and a SRC that is a JPEG. For now, we avoid crashing. Later
- we should fix that case so it does the right thing and gets rid
- of the mask. */
- if (!src)
- return;
-
- /* Add a bit to the row of mask bits. Flush accumulator to memory if full. */
- #define SHIFT_IMAGE_MASK(not_transparent_flag) \
- { \
- fgmask32 |= ((uint32)not_transparent_flag ) << M32(mask_bit); \
- bgmask32 |= ((uint32)not_transparent_flag ^ 1) << M32(mask_bit); \
- \
- /* Filled up 32-bit mask word. Write it to memory. */ \
- if (mask_bit-- == 0) { \
- uint32 mtmp = *m; \
- mtmp |= fgmask32; \
- if (draw_mode == ilErase) \
- mtmp &= ~bgmask32; \
- *m++ = mtmp; \
- mask_bit = 31; \
- bgmask32 = 0; \
- fgmask32 = 0; \
- } \
- output_bits_remaining--; \
- }
-
-
- /* Two cases */
- /* Scaling down ? (or source and dest same size) ... */
-
- if (src_len >= mask_len)
- {
- while (output_bits_remaining ) {
- not_transparent = (*(src+3) > 0x60 );
- SHIFT_IMAGE_MASK(not_transparent);
- n += src_len;
-
- while ( n >= mask_len){
- src += 4;
- n -= mask_len;
- }
- }
- }
- else
- /* Scaling up */
- {
- while (output_bits_remaining) {
- n += mask_len;
- not_transparent = (*src != 0);
-
- while (n >= src_len) {
- SHIFT_IMAGE_MASK(not_transparent);
- n -= src_len;
- }
- src++;
- }
-
- }
-
- /* End of scan line. Write out any remaining mask bits. */
- if (mask_bit < 31) {
- uint32 mtmp = *m;
- mtmp |= fgmask32;
- if (draw_mode == ilErase)
- mtmp &= ~bgmask32;
- *m = mtmp;
- }
-
- }
-
-
- /*-----------------------------------------------------------------------------
- * Create a transparency mask bitmap. Perform horizontal scaling if
- * requested using a Bresenham algorithm. Accumulate the mask in
- * 32-bit chunks for efficiency.
- *---------------------------------------------------------------------------*/
- static void
- il_generate_scaled_transparency_mask(
- IL_IRGB *transparent_pixel, /* The transparent pixel */
- uint8 *src, /* Row of pixels, 8-bit pseudocolor data */
- int src_len, /* Number of pixels in source row */
- int x_offset, /* Destination offset from left edge */
- uint8 XP_HUGE *maskp, /* Output pointer, left-justified bitmask */
- int mask_len, /* Number of pixels in output row */
- il_draw_mode draw_mode) /* ilOverlay or ilErase */
- {
- int not_transparent, n = 0;
- int src_trans_pixel_index =
- transparent_pixel ? transparent_pixel->index : -1;
- int output_bits_remaining = mask_len;
-
- uint32 bgmask32 = 0; /* 32-bit temporary mask accumulators */
- uint32 fgmask32 = 0;
-
- int mask_bit; /* next bit to write in setmask32 */
-
- uint32 *m = ((uint32*)maskp) + (x_offset >> 5);
- mask_bit = ~x_offset & 0x1f;
-
- XP_ASSERT(mask_len);
-
- /* Handle case in which we have a mask for a non-transparent
- image. This can happen when we have a LOSRC that is a transparent
- GIF and a SRC that is a JPEG. For now, we avoid crashing. Later
- we should fix that case so it does the right thing and gets rid
- of the mask. */
- if (!src)
- return;
-
- /* Two cases */
- /* Scaling down ? (or source and dest same size) ... */
- if (src_len >= mask_len)
- {
- while (output_bits_remaining) {
- not_transparent = (*src != src_trans_pixel_index);
-
- SHIFT_IMAGE_MASK(not_transparent);
- n += src_len;
-
- while (n >= mask_len) {
- src++;
- n -= mask_len;
- }
- }
- }
- else
- /* Scaling up */
- {
- while (output_bits_remaining) {
- n += mask_len;
- not_transparent = (*src != src_trans_pixel_index);
-
- while (n >= src_len) {
- SHIFT_IMAGE_MASK(not_transparent);
- n -= src_len;
- }
- src++;
- }
- }
-
- /* End of scan line. Write out any remaining mask bits. */
- if (mask_bit < 31) {
- uint32 mtmp = *m;
- mtmp |= fgmask32;
- if (draw_mode == ilErase)
- mtmp &= ~bgmask32;
- *m = mtmp;
- }
-
- #undef SHIFT_IMAGE_MASK
- }
-
-
- /*-----------------------------------------------------------------------------
- * When color quantization (possibly accompanied by dithering) takes
- * place, the background pixels in a transparent image that overlays a
- * solid-color background, e.g. <BODY BGCOLOR=#c5c5c5>, will get
- * mapped to a color in the color-cube. The real background color,
- * however, may not be one of these colors reserved for images. This
- * routine serves to return transparent pixels to their background
- * color. This routine must performing scaling because the source
- * pixels are in the image space and the target pixels are in the
- * display space.
- *---------------------------------------------------------------------------*/
- static void
- il_reset_background_pixels(
- il_container *ic, /* The image container */
- uint8 *src, /* Row of pixels, 8-bit pseudocolor data */
- int src_len, /* Number of pixels in row */
- uint8 XP_HUGE *dest, /* Output pointer, 8-bit pseudocolor data */
- int dest_len) /* Width of output pixel row */
- {
- int is_transparent, n = 0;
- uint8 XP_HUGE *dest_end = dest + dest_len;
- NI_PixmapHeader *img_header = &ic->image->header;
- int src_trans_pixel_index = ic->src_header->transparent_pixel->index;
- int img_trans_pixel_index = img_header->transparent_pixel->index;
- int dpy_trans_pixel_index =
- img_header->color_space->cmap.index[img_trans_pixel_index];
-
- /* Two cases */
-
- /* Scaling down ? (or not scaling ?) ... */
- if (src_len >= dest_len) {
- while (dest < dest_end) {
- is_transparent = (*src == src_trans_pixel_index);
- if (is_transparent)
- *dest = dpy_trans_pixel_index;
- dest++;
- n += src_len;
-
- while (n >= dest_len) {
- src++;
- n -= dest_len;
- }
- }
- } else {
- /* Scaling up */
- while (dest < dest_end) {
- n += dest_len;
- is_transparent = (*src++ == src_trans_pixel_index);
-
- if (is_transparent)
- while (n >= src_len) {
- *dest++ = dpy_trans_pixel_index;
- n -= src_len;
- }
- else
- while (n >= src_len) {
- dest++;
- n -= src_len;
- }
- }
- }
- }
-
- static void
- il_generate_byte_mask(
- il_container *ic, /* The image container */
- uint8 *src, /* Row of pixels, 8-bit pseudocolor data */
- int src_len, /* Number of pixels in row */
- uint8 *dest, /* Output pointer, 8-bit pseudocolor data */
- int dest_len) /* Width of output pixel row */
- {
- int is_transparent, n = 0;
- uint8 XP_HUGE *dest_end = dest + dest_len;
- int src_trans_pixel_index = ic->src_header->transparent_pixel->index;
-
- /* Two cases */
-
- /* Scaling down ? (or not scaling ?) ... */
- if (src_len >= dest_len) {
- while (dest < dest_end) {
- is_transparent = (*src == src_trans_pixel_index);
- *dest = is_transparent - 1;
- dest++;
- n += src_len;
-
- while (n >= dest_len) {
- src++;
- n -= dest_len;
- }
- }
- } else {
- /* Scaling up */
- while (dest < dest_end) {
- n += dest_len;
- is_transparent = (*src++ == src_trans_pixel_index);
-
- if (is_transparent)
- while (n >= src_len) {
- *dest++ = 0;
- n -= src_len;
- }
- else
- while (n >= src_len) {
- *dest++ = (uint8)-1;
- n -= src_len;
- }
- }
- }
- }
-
- static void
- il_overlay(uint8 *src, uint8 *dest, uint8 *byte_mask, int num_cols,
- int bytes_per_pixel)
- {
- int i, col;
- #if 0
- uint8 *s = src;
- uint8 *s_end = src + (num_cols * bytes_per_pixel);
- #endif
- for (col = num_cols; col > 0; col--) {
- if (*byte_mask++) {
- for (i = bytes_per_pixel-1; i >= 0; i--) {
- dest[i] = src[i];
- }
- }
- dest += bytes_per_pixel;
- src += bytes_per_pixel;
- }
- }
-
- static uint8 il_tmpbuf[MAX_IMAGE_WIDTH];
-
- /*-----------------------------------------------------------------------------
- * Emit a complete row of pixel data into the image. This routine
- * provides any necessary conversion to the display depth, optional dithering
- * for pseudocolor displays, scaling and transparency, including mask
- * generation, if necessary. If sufficient data is accumulated, the screen
- * image is updated, as well.
- *---------------------------------------------------------------------------*/
- void
- il_emit_row(
- il_container *ic, /* The image container */
- uint8 *cbuf, /* Color index data source, or NULL if source
- is RGB data */
- uint8 *rgbbuf, /* Packed RGBa data or RGBa workspace if <cbuf> != NULL */
- int x_offset, /* First column to write data into */
- int len, /* Width of source image, in pixels */
- int row, /* Starting row of image */
- int dup_row_count, /* Number of times to duplicate row */
- il_draw_mode draw_mode, /* ilOverlay or ilErase */
- int pass) /* Zero, unless interlaced GIF,
- in which case ranges 1-4, or progressive JPEG,
- in which case ranges from 1-n. */
- {
- IL_GroupContext *img_cx = ic->img_cx;
- IL_Pixmap *image = ic->image;
- IL_Pixmap *mask = ic->mask;
- NI_PixmapHeader *src_header = ic->src_header;
- NI_PixmapHeader *img_header = &image->header;
- NI_PixmapHeader *mask_header;
- NI_ColorSpace *src_color_space = src_header->color_space;
- NI_ColorSpace *img_color_space = img_header->color_space;
- uint8 XP_HUGE *out;
- uint8 XP_HUGE *dp;
- uint8 XP_HUGE *mp;
- uint8 XP_HUGE *maskp = NULL;
- uint8 *byte_mask = NULL;
- uint8 XP_HUGE *srcbuf = rgbbuf;
- uint8 *p = cbuf;
- uint8 *pl = cbuf+len;
- int drow_start, drow_end, row_count, color_index, dup, do_dither;
- int dcolumn_start, dcolumn_end, column_count, offset, src_len, dest_len;
-
- XP_ASSERT(row >= 0);
-
- if(row >= src_header->height) {
- ILTRACE(2,("il: ignoring extra row (%d)", row));
- return;
- }
-
- /* Set first and last destination row in the image. Assume no scaling. */
- drow_start = row;
- drow_end = row + dup_row_count - 1;
- dcolumn_start = x_offset;
- dcolumn_end = x_offset + len - 1;
-
- /* If scaling, convert vertical image coordinates to display space. */
- if (img_header->height != src_header->height) {
- int d = drow_start;
- int next_drow_start = SCALE_YCOORD(img_header, src_header, drow_end+1);
- drow_start = SCALE_YCOORD(img_header, src_header, drow_start);
-
- /*
- * Don't emit a row of pixels that will be overwritten later.
- * (as may happen during when images are being reduced vertically).
- */
- if (drow_start == next_drow_start) {
- /*
- * Except that the bottom line of pixels can never be
- * overwritten by a subsequent line.
- */
- if (d != (src_header->height - 1))
- return;
- else
- drow_end = drow_start;
- } else {
- drow_end = next_drow_start - 1;
- if (drow_end >= img_header->height)
- drow_end = img_header->height - 1;
- }
- }
-
- /* If scaling, convert horizontal image coordinates to display space. */
- if (img_header->width != src_header->width) {
- int d = dcolumn_start;
- int next_dcolumn_start = SCALE_XCOORD(img_header, src_header,
- dcolumn_end+1);
- dcolumn_start = SCALE_XCOORD(img_header, src_header, dcolumn_start);
-
- /*
- * Don't emit a column of pixels that will be overwritten later.
- * (as may happen during when images are being reduced vertically).
- */
- if (dcolumn_start == next_dcolumn_start) {
- /*
- * Except that the right column of pixels can never be
- * overwritten by a subsequent column.
- */
- if (d != (src_header->width - 1))
- return;
- else
- dcolumn_end = dcolumn_start;
- } else {
- dcolumn_end = next_dcolumn_start - 1;
- if (dcolumn_end >= img_header->width)
- dcolumn_end = img_header->width - 1;
- }
- }
-
- /* Number of pixel rows and columns to emit into framebuffer */
- row_count = drow_end - drow_start + 1;
- column_count = dcolumn_end - dcolumn_start + 1;
-
- /* If a transparent image appears over a background image ... */
- if (mask) {
- mask_header = &mask->header;
-
- /* Bug, we retain the mask from a transparent
- LOSRC GIF when the SRC is a JPEG. */
- /* XP_ASSERT(cbuf); */
-
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, mask,
- IL_LOCK_BITS);
-
- #ifdef _USD
- maskp = (uint8 XP_HUGE *)mask->bits +
- (mask_header->height - drow_start - 1) * mask_header->widthBytes;
- #else
- maskp = (uint8 XP_HUGE *)mask->bits +
- drow_start * mask_header->widthBytes;
- #endif
-
- if(!ic->image->header.is_interleaved_alpha){
- il_generate_scaled_transparency_mask(src_header->transparent_pixel,
- cbuf, (int)len,
- dcolumn_start,
- maskp, column_count,
- draw_mode);
- }else{ /* is alpha */
-
- uint8 *tmpbuf;
- int i;
-
- il_alpha_mask(1,rgbbuf, (int)len, dcolumn_start,
- maskp, column_count,draw_mode);
-
- tmpbuf = rgbbuf;
- for(i=0; i<column_count; i++){
- *rgbbuf++ = *tmpbuf++;
- *rgbbuf++ = *tmpbuf++;
- *rgbbuf++ = *tmpbuf++;
- tmpbuf++; /* strip off alpha channel */
- }
-
- }
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, mask,
- IL_UNLOCK_BITS);
- }
-
- if (!ic->converter) {
-
- #ifndef M12N /* XXXM12N fixme */
- int i;
- int src_trans_pixel_index;
- uint8 XP_HUGE * dest;
- uint8 *indirect_map = ic->cs->current_indirect_map;/* XXXM12N fixme */
-
- if ((draw_mode == ilErase) || !src_header->transparent_pixel)
- src_trans_pixel_index = -1; /* no transparency */
- else
- src_trans_pixel_index = src_header->transparent_pixel->index;
-
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
- IL_LOCK_BITS);
-
- /* No converter, image is already rendered in pseudocolor. */
- #ifdef _USD
- out = (uint8 XP_HUGE *)image->bits +
- (img_header->height - drow_start - 1) * img_header->widthBytes;
- #else
- out = (uint8 XP_HUGE *)image->bits +
- drow_start * img_header->widthBytes;
- #endif
-
- dest = out + dcolumn_start;
-
- /* If horizontal scaling ... */
- if (len != column_count) {
- il_scale_CI_row(cbuf, len, dest, column_count,
- indirect_map, src_trans_pixel_index);
- } else {
-
- /* Convert to FE's palette indices */
- for (i = 0; i < len; i++)
- if (cbuf[i] != src_trans_pixel_index)
- dest[i] = indirect_map[cbuf[i]];
- }
-
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
- IL_UNLOCK_BITS);
- #endif /* M12N */
-
- } else {
-
- /* Generate the output row in RGB space, regardless of screen depth. */
- if (cbuf) {
- uint8 *r = rgbbuf;
- IL_RGB *map = src_color_space->cmap.map, *entry;
-
- if (!src_header->transparent_pixel) {
- /* Simple case: no transparency */
- while (p < pl) {
- color_index = *p++;
- entry = map + color_index;
- r[0] = entry->red;
- r[1] = entry->green;
- r[2] = entry->blue;
- r += 3 ;
- }
- } else {
- /*
- * There are two kinds of transparency, depending on whether
- * the image is overlaying:
- * 1) a solid color background, or
- * 2) another image
- *
- * The first case is easy. We just substitute the background
- * color for all the transparent pixels in the image. No mask
- * is necessary. The second case requires that we generate a
- * bit mask (see the code above). It also seems to require that
- * all the transparent pixels in the image be set to black.
- * XXX - Why ? Is this some platform-specific thing ? - fur
- */
- int background_r, background_g, background_b;
- IL_IRGB *src_trans_pixel = src_header->transparent_pixel;
- int src_trans_pixel_index = src_trans_pixel->index;
-
- background_r = background_g = background_b = 0;
- if (!ic->mask) {
- /* Solid background color */
- background_r = src_trans_pixel->red;
- background_g = src_trans_pixel->green;
- background_b = src_trans_pixel->blue;
- }
-
- /* Remap transparent pixels */
- while (p < pl) {
- color_index = *p++;
- if (color_index == src_trans_pixel_index) {
- r[0] = background_r;
- r[1] = background_g;
- r[2] = background_b;
- r += 3;
- } else {
- entry = map + color_index;
- r[0] = entry->red;
- r[1] = entry->green;
- r[2] = entry->blue;
- r += 3;
- }
- }
- }
- }
-
-
- /* Now we are in RGB space. */
-
- /* Simple anamorphic scaling (in RGB space for now) */
- src_len = len;
- dest_len = column_count;
- if (src_len != dest_len) {
- uint8 XP_HUGE *src = rgbbuf;
- uint8 *dest = ic->scalerow;
- srcbuf = dest;
-
- /* Scale the pixel data (mask data already scaled) */
- il_scale_RGB_row(src, src_len, dest, dest_len);
- }
-
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
- IL_LOCK_BITS);
-
- #ifdef _USD
- out = (uint8 XP_HUGE *)image->bits +
- (img_header->height-drow_start-1) * (uint32)img_header->widthBytes;
- #else
- out = (uint8 XP_HUGE *)image->bits +
- drow_start * img_header->widthBytes;
- #endif
-
- if (src_header->transparent_pixel && (draw_mode == ilOverlay))
- {
- if( cbuf ){
- il_generate_byte_mask(ic, cbuf, len, il_tmpbuf, column_count);
- byte_mask = il_tmpbuf;
- }
- }
-
-
- /*
- * Convert RGB to display depth. If display is pseudocolor, this may
- * also color-quantize and dither.
- */
- (*ic->converter)(ic, byte_mask, srcbuf, dcolumn_start,
- column_count, out);
-
- IMGCBIF_ControlPixmapBits(img_cx->img_cb, img_cx->dpy_cx, image,
- IL_UNLOCK_BITS);
-
- /*
- * Have to reset transparent pixels to background color
- * because color quantization may have mutated them.
- */
- if (src_header->transparent_pixel &&
- (img_color_space->type == NI_PseudoColor) &&
- !mask && (draw_mode == ilErase))
- il_reset_background_pixels(ic, cbuf, len,
- out + dcolumn_start, column_count);
- }
-
- /*
- * We now have one row of pixels and, if required for transparency, a row
- * of mask data. If the pixels in this row of the image cover span more
- * than one pixel vertically when displayed, the row needs to be
- * replicated in the framebuffer. (This replication is necessary when
- * displaying interlaced GIFs and/or vertical scaling of any image type.)
- * Actually, pixel rows are not simply copied: Dithering may need to be
- * applied on a line-by-line basis.
- */
- dp = out;
- mp = maskp;
- dup = row_count - 1;
- offset = dcolumn_start * (img_color_space->pixmap_depth / 8);
-
- #ifndef M12N /* Clean this up */
- if (ic->image->pixmap_depth == 1)
- do_dither = TRUE;
- else
- do_dither = ic->converter && (row_count <= 4) &&
- ((ic->dither_mode == IL_Dither) || (ic->type == IL_JPEG));
- #else
- do_dither = (ic->dither_mode == IL_Dither);
- if ((ic->type == IL_GIF) && (!ic->converter || (row_count > 4)))
- do_dither = FALSE;
-
- #endif /* M12N */
-
- while (dup--) {
- #ifdef _USD
- dp -= img_header->widthBytes;
- if (mask)
- mp -= mask_header->widthBytes;
- #else
- dp += img_header->widthBytes;
- if (mask)
- mp += mask_header->widthBytes;
- #endif
- /* Is dithering being done (either mono or pseudocolor) ... ? */
- if (do_dither) {
-
- /* Dither / color-quantize */
- (*ic->converter)(ic, byte_mask, srcbuf, dcolumn_start,
- column_count, dp);
-
- /*
- * Have to reset transparent pixels to background color
- * because color quantization may have mutated them.
- */
- if (img_header->transparent_pixel &&
- (img_color_space->type == NI_PseudoColor) &&
- !mask && (draw_mode == ilErase))
- il_reset_background_pixels(ic, cbuf, len, dp + dcolumn_start,
- column_count);
- } else {
- /* If no dithering, each row of pixels is exactly the same. */
- if (byte_mask)
- il_overlay(out + offset, dp + offset, byte_mask, column_count,
- (img_color_space->pixmap_depth/8));
- else
- XP_MEMCPY(dp + offset, out + offset,
- (img_color_space->pixmap_depth/8) * column_count);
- }
-
- /* Duplicate the mask also. */
- if (maskp) {
- if (column_count == img_header->width) /* easy case */
- XP_MEMCPY(mp, maskp, mask_header->widthBytes);
- else
- il_generate_scaled_transparency_mask(
- img_header->transparent_pixel, cbuf, (int)len,
- dcolumn_start, mp, column_count, draw_mode);
- }
- }
-
-
- /* If enough rows accumulated, send to the front-end for display. */
- il_partial(ic, drow_start, row_count, pass);
- }
-
-
-