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 -*-
- * xbm.c --- Decoding of X bit-map format images
- * $Id: xbm.c,v 3.1 1998/03/28 03:35:04 ltabb Exp $
- */
-
-
- /*
- #include "xp.h"
- */
-
- #include "if.h"
-
- #define CR '\015'
- #define LF '\012'
- #include "merrors.h"
-
- #include "il.h"
-
- extern int MK_OUT_OF_MEMORY;
-
- typedef enum {
- xbm_gather,
- xbm_init,
- xbm_width,
- xbm_height,
- xbm_start_data,
- xbm_data,
- xbm_hex,
- xbm_done,
- xbm_oom,
- xbm_error
- } xstate;
-
- #define MAX_HOLD 512
-
- typedef void(*il_xbm_converter)(void *, unsigned char, unsigned int);
-
- typedef struct xbm_struct {
- xstate state;
- unsigned char hold[MAX_HOLD];
- intn gathern; /* gather n chars */
- unsigned char gatherc; /* gather until char c */
- intn gathered; /* bytes accumulated */
- xstate gathers; /* post-gather state */
- uint32 xpos, ypos;
- unsigned char *p; /* raster position */
- unsigned char *m; /* mask position (if mask is used) */
- il_xbm_converter converter; /* colorspace converter */
- uint8 bg_pixel; /* destination image background pixel index */
- uint8 fg_pixel; /* destination image foreground pixel index */
- } xbm_struct;
-
- #define MAX_LINE MAX_HOLD /* XXX really bad xbms will hose us */
-
-
- #define GETN(n,s) {xs->state=xbm_gather; xs->gathern=n; xs->gathers=s;}
- #define GETC(c,s) {xs->state=xbm_gather; xs->gatherc=c; xs->gathers=s;}
-
- char hex_table_initialized = FALSE;
- static uint8 hex[256];
-
- static void
- il_init_hex_table(void)
- {
- hex['0'] = 0; hex['1'] = 8;
- hex['2'] = 4; hex['3'] = 12;
- hex['4'] = 2; hex['5'] = 10;
- hex['6'] = 6; hex['7'] = 14;
- hex['8'] = 1; hex['9'] = 9;
- hex['A'] = hex['a'] = 5;
- hex['B'] = hex['b'] = 13;
- hex['C'] = hex['c'] = 3;
- hex['D'] = hex['d'] = 11;
- hex['E'] = hex['e'] = 7;
- hex['F'] = hex['f'] = 15;
-
- hex_table_initialized = TRUE;
- }
-
- int il_xbm_init(il_container *ic)
- {
- xbm_struct *xs;
- NI_ColorSpace *src_color_space = ic->src_header->color_space;
-
- if (!hex_table_initialized)
- il_init_hex_table();
-
- xs = XP_NEW_ZAP (xbm_struct);
- if (xs)
- {
- xs->state = xbm_init;
- xs->gathers = xbm_error;
- ic->ds = xs;
- }
-
- /* Initialize the container's source image header. */
- src_color_space->type = NI_GreyScale;
- src_color_space->pixmap_depth = 1;
- src_color_space->bit_alloc.index_depth = 1;
- src_color_space->cmap.num_colors = 2;
-
- return xs != 0;
- }
-
-
- static int
- il_xbm_init_transparency(il_container *ic)
- {
- IL_IRGB *src_trans_pixel = ic->src_header->transparent_pixel;
- IL_IRGB *img_trans_pixel;
-
- if (!src_trans_pixel) {
- src_trans_pixel = XP_NEW_ZAP(IL_IRGB);
- if (!src_trans_pixel)
- return FALSE;
- ic->src_header->transparent_pixel = src_trans_pixel;
-
- /* Initialize the destination image's transparent pixel. */
- il_init_image_transparent_pixel(ic);
-
- /* Set the source image's transparent pixel color to be the preferred
- transparency color of the destination image. */
- img_trans_pixel = ic->image->header.transparent_pixel;
- src_trans_pixel->red = img_trans_pixel->red;
- src_trans_pixel->green = img_trans_pixel->green;
- src_trans_pixel->blue = img_trans_pixel->blue;
-
- /* Set the source image's transparent pixel index. */
- src_trans_pixel->index = 1;
- }
-
- return TRUE;
- }
-
-
- /* Since the XBM decoder writes directly to the image bits, we need to provide
- our own color space conversion routines. ConvertDefault is the preferred
- routine from an efficiency standpoint, but it requires the Front Ends to
- agree to receive 1-bit deep data. The other routines are provided since
- the Front Ends can request the Image Library to decode to the display
- colorspace, which may not be 1-bit deep. */
- static void
- ConvertDefault(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- xbm_struct *xs = ds;
-
- *xs->p = val;
- xs->p++;
- }
-
- static void
- ConvertBWToRGB8(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- unsigned int bit_mask;
- xbm_struct *xs = ds;
- uint8 *ptr = (uint8 *)xs->p;
-
- for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
- if (val & bit_mask)
- *ptr = 0;
- else
- *ptr = (uint8)~0;
- ptr++;
- }
- xs->p = (unsigned char *)ptr;
- }
-
- static void
- ConvertBWToRGB16(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- unsigned int bit_mask;
- xbm_struct *xs = ds;
- uint16 *ptr = (uint16 *)xs->p;
-
- for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
- if (val & bit_mask)
- *ptr = 0;
- else
- *ptr = (uint16)~0;
- ptr++;
- }
- xs->p = (unsigned char *)ptr;
- }
-
- static void
- ConvertBWToRGB24(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- unsigned int bit_mask;
- xbm_struct *xs = ds;
- uint8 *ptr = (uint8 *)xs->p;
-
- for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
- if (val & bit_mask) {
- *ptr++ = 0;
- *ptr++ = 0;
- *ptr++ = 0;
- }
- else {
- *ptr++ = (uint8)~0;
- *ptr++ = (uint8)~0;
- *ptr++ = (uint8)~0;
- }
- }
- xs->p = (unsigned char *)ptr;
- }
-
- static void
- ConvertBWToRGB32(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- unsigned int bit_mask;
- xbm_struct *xs = ds;
- uint32 *ptr = (uint32 *)xs->p;
-
- for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
- if (val & bit_mask)
- *ptr = 0;
- else
- *ptr = (uint32)~0;
- ptr++;
- }
- xs->p = (unsigned char *)ptr;
- }
-
- static void
- ConvertBWToCI(void *ds, unsigned char val, unsigned int last_bit_mask)
- {
- unsigned int bit_mask;
- xbm_struct *xs = ds;
- uint8 *ptr = (uint8 *)xs->p;
- uint8 bg_pixel = xs->bg_pixel;
- uint8 fg_pixel = xs->fg_pixel;
-
- for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
- if (val & bit_mask)
- *ptr = fg_pixel;
- else
- *ptr = bg_pixel;
- ptr++;
- }
- xs->p = (unsigned char *)ptr;
- }
-
-
- static void
- il_xbm_setup_color_space_converter(il_container *ic)
- {
- IL_ColorSpace *img_color_space = ic->image->header.color_space;
- xbm_struct *xs = (xbm_struct *)ic->ds;
-
- switch (img_color_space->type) {
- case NI_GreyScale:
- switch (img_color_space->pixmap_depth) {
- case 1:
- xs->converter = ConvertDefault;
- break;
-
- case 8:
- xs->converter = ConvertBWToRGB8;
- break;
-
- default:
- XP_ASSERT(0);
- break;
- }
- break;
-
- case NI_TrueColor:
- switch (img_color_space->pixmap_depth) {
- case 8:
- xs->converter = ConvertBWToRGB8;
- break;
-
- case 16:
- xs->converter = ConvertBWToRGB16;
- break;
-
- case 24:
- xs->converter = ConvertBWToRGB24;
- break;
-
- case 32:
- xs->converter = ConvertBWToRGB32;
- break;
-
- default:
- XP_ASSERT(0);
- break;
- }
- break;
-
- case NI_PseudoColor:
- xs->converter = ConvertBWToCI;
- break;
-
- default:
- XP_ASSERT(0);
- break;
- }
- }
-
-
- static void
- copyline(char *d, const unsigned char *s)
- {
- int i=0;
- while( i++ < MAX_LINE && *s && *s != LF )
- *d++ = *s++;
- *d=0;
- }
-
- int il_xbm_write(il_container *ic, const unsigned char *buf, int32 len)
- {
- int status, input_exhausted;
- xbm_struct *xs = (xbm_struct *)ic->ds;
- const unsigned char *q, *p=buf, *ep=buf+len;
- IL_Pixmap *image = ic->image;
- IL_Pixmap *mask = ic->mask;
- NI_PixmapHeader *img_header = &image->header;
- NI_PixmapHeader *mask_header = mask ? &mask->header : NULL;
- NI_PixmapHeader *src_header = ic->src_header;
- char lbuf[MAX_LINE+1];
-
- /* If this assert fires, chances are the netlib screwed up and
- continued to send data after the image stream was closed. */
- XP_ASSERT(xs);
- if (!xs) {
- #ifdef DEBUG
- XP_TRACE(("Netlib just took a shit on the imagelib\n"));
- #endif
- return MK_IMAGE_LOSSAGE;
- }
-
- q = NULL; /* Initialize to shut up gcc warnings */
- input_exhausted = FALSE;
-
- while(!input_exhausted)
- {
- ILTRACE(9,("il:xbm: state %d len %d buf %u p %u ep %u",xs->state,len,buf,p,ep));
-
- switch(xs->state)
- {
- case xbm_data:
- GETN(2,xbm_hex);
- break;
-
- case xbm_hex:
- {
- int num_pixels; /* Number of pixels remaining to be
- processed in current scanline. */
- unsigned char val = (hex[q[1]]<<4) + hex[q[0]];
-
- if (xs->xpos == 0) {
- /* XXX -kevina Locking of the bits pointers is
- currently done on per-scanline basis. The XBM
- decoder, however, does not process a full scanline
- at a time, (only a single byte,) so if we return in
- the middle of a scanline, the bits pointers will
- remain locked until the next write call. I would
- like to eventually make the XBM decoder process a
- full scanline at a time, since this would eliminate
- the locking anomaly, and it would also permit the
- colorspace converters to be modelled along the
- lines of (and hence bundled with) the per-scanline
- colorspace converters in the core image library. */
- IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
- ic->img_cx->dpy_cx,
- ic->image, IL_LOCK_BITS);
- IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
- ic->img_cx->dpy_cx,
- ic->mask, IL_LOCK_BITS);
-
- #ifdef _USD
- xs->p = (unsigned char *)image->bits +
- (img_header->height-xs->ypos-1) *
- (img_header->widthBytes);
- if (mask)
- xs->m = (unsigned char *)mask->bits +
- (mask_header->height-xs->ypos-1) *
- (mask_header->widthBytes);
- #else
- xs->p = (unsigned char *)image->bits +
- xs->ypos * (img_header->widthBytes);
- if (mask)
- xs->m = (unsigned char *)mask->bits +
- xs->ypos * (mask_header->widthBytes);
- #endif
- }
-
- if (mask) {
- *xs->m = val;
- xs->m++;
- }
-
- num_pixels = img_header->width - xs->xpos;
- if (num_pixels <= 8) {
- xs->converter((void*)xs, val, 1<<(8-num_pixels));
-
- IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
- ic->img_cx->dpy_cx,
- ic->image, IL_UNLOCK_BITS);
- IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
- ic->img_cx->dpy_cx,
- ic->mask, IL_UNLOCK_BITS);
-
- xs->xpos=0;
- xs->ypos++;
- /* The image library does not scale XBMs, so if the
- requested target height does not match the source
- height, we stop when the smaller of the two is
- reached. */
- if (xs->ypos == src_header->height ||
- xs->ypos == img_header->height) {
- xs->state = xbm_done;
- }
- else {
- GETC('x',xbm_data);
- }
- }
- else {
- xs->converter((void*)xs, val, 1);
- xs->xpos+=8;
- GETC('x',xbm_data);
- }
- }
- break;
-
- case xbm_init:
- GETC(LF,xbm_width);
- break;
-
- case xbm_width:
- {
- copyline(lbuf, q);
- if(sscanf(lbuf, "#define %*s %d",
- (int *)&ic->src_header->width)==1)
- {
- GETC(LF,xbm_height);
- }
- else
- {
- /* Accept any of CR/LF, CR, or LF.
- Allow multiple instances of each. */
- GETC(LF,xbm_width);
- }
- }
- break;
-
- case xbm_height:
- {
- copyline(lbuf, q);
- if(sscanf(lbuf, "#define %*s %d",
- (int *)&ic->src_header->height)==1)
- {
- IL_RGB* map;
-
- if (!il_xbm_init_transparency(ic))
- return MK_OUT_OF_MEMORY;
-
- if ((status = il_size(ic)) < 0)
- {
- if (status == MK_OUT_OF_MEMORY)
- xs->state = xbm_oom;
- else
- xs->state = xbm_error;
- break;
- }
-
- /* Determine the background and foreground pixel
- indices of the destination image if this is a
- PseudoColor display. Note: it is assumed that
- the index of the black pixel in the IL_ColorMap
- is 0. */
- if (img_header->color_space->type == NI_PseudoColor) {
- xs->bg_pixel =
- img_header->transparent_pixel->index;
- xs->fg_pixel =
- img_header->color_space->cmap.index[0];
- }
-
- if (ic->mask) {
- mask = ic->mask;
- mask_header = &mask->header;
- }
-
- if((map = (IL_RGB*)XP_CALLOC(2, sizeof(IL_RGB)))!=0)
- {
- src_header->color_space->cmap.map = map;
- map++; /* first index is black */
- map->red = src_header->transparent_pixel->red;
- map->green = src_header->transparent_pixel->green;
- map->blue = src_header->transparent_pixel->blue;
- }
- GETC('{',xbm_start_data);
- il_xbm_setup_color_space_converter(ic);
- }
- else
- {
- /* Accept any of CR/LF, CR, or LF.
- Allow multiple instances of each. */
- GETC(LF,xbm_height);
- }
- }
- break;
-
- case xbm_start_data:
- GETC('x',xbm_data);
- break;
-
- case xbm_gather:
- {
- if(xs->gatherc)
- {
- const unsigned char *s;
- /* We may need to look ahead one character, so don't point
- at the last character in the buffer. */
- for(s = p; s < ep; s++)
- {
- if (xs->gatherc == LF)
- {
- if ((s[0] == LF) || (s[0] == CR))
- {
- xs->gatherc = 0;
- break;
- }
- }
- else if (s[0] == xs->gatherc)
- {
- xs->gatherc = 0;
- break;
- }
- }
-
- if(xs->gatherc)
- {
- if((xs->gathered+ep-p) > MAX_HOLD)
- {
- /* we will never find it */
- xs->state = xbm_error;
- }
- else
- {
- XP_MEMCPY(xs->hold+xs->gathered, p, ep-p);
- xs->gathered += ep-p;
- input_exhausted = TRUE;
- }
- }
- else
- { /* found it */
- if(xs->gathered)
- {
- XP_MEMCPY(xs->hold+xs->gathered, p, s-p+1);
- q = xs->hold;
- }
- else
- {
- q = p;
- }
- p = s+1;
- xs->gathered=0;
- xs->state=xs->gathers;
- }
- }
-
- if(xs->gathern)
- {
- if( (ep - p) >= xs->gathern)
- { /* there is enough */
- if(xs->gathered)
- { /* finish a prior gather */
- XP_MEMCPY(xs->hold+xs->gathered, p, xs->gathern);
- q = xs->hold;
- xs->gathered=0;
- }
- else
- {
- q = p;
- }
- p += xs->gathern;
- xs->gathern=0;
- xs->state=xs->gathers;
- }
- else
- {
- XP_MEMCPY(xs->hold+xs->gathered, p, ep-p);
- xs->gathered += ep-p;
- xs->gathern -= ep-p;
- input_exhausted = TRUE;
- }
- }
- }
- break;
-
- case xbm_done:
- il_partial(ic, 0, img_header->height, 0);
- return 0;
-
- case xbm_oom:
- ILTRACE(1,("il:xbm: reached oom state"));
- return MK_OUT_OF_MEMORY;
-
- case xbm_error:
- ILTRACE(2,("il:xbm: reached error state"));
- return MK_IMAGE_LOSSAGE;
-
- default:
- ILTRACE(0,("il:xbm: unknown state %d", xs->state));
- XP_ASSERT(0);
- break;
- }
- }
- return 0;
- }
-
- void
- il_xbm_abort(il_container *ic)
- {
- if (ic->ds)
- {
- xbm_struct *xs = (xbm_struct*) ic->ds;
- XP_FREE(xs);
- ic->ds = 0;
- }
- }
-
- void
- il_xbm_complete(il_container *ic)
- {
- il_xbm_abort(ic);
- il_image_complete(ic);
- il_frame_complete_notify(ic);
- }
-