static void drawSelectionPolygon(XmHTMLWidget html, XmHTMLImage *image, mapArea *area) { ToolkitAbstraction *tka = HTML_ATTR(tka); XPoint *points; int i, npoints; int x = image->owner->x - html->html.scroll_x; int y = image->owner->y - html->html.scroll_y; npoints = area->ncoords/2; points = (XPoint*)calloc(npoints+1, sizeof(XPoint)); for(i = 0; i < npoints; i++) { points[i].x = area->coords[i*2] + x; points[i].y = area->coords[i*2+1] + y; } /* last point is same as first point */ points[npoints].x = points[0].x; points[npoints].y = points[0].y; tka->SetForeground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(imagemap_fg)); tka->DrawLines(tka->dpy, tka->win, HTML_ATTR(gc), points, npoints+1, tka->coord_mode[GC_COORDMODE_ORIGIN]); free(points); }
static void drawSelectionRectangle(XmHTMLWidget html, XmHTMLImage *image, mapArea *area) { ToolkitAbstraction *tka = HTML_ATTR(tka); int x = image->owner->x - html->html.scroll_x + area->coords[0]; int y = image->owner->y - html->html.scroll_y + area->coords[1]; int width = area->coords[2] - area->coords[0]; int height = area->coords[3] - area->coords[1]; tka->SetForeground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(imagemap_fg)); tka->DrawRectangle(tka->dpy, tka->win, HTML_ATTR(gc), x, y, width, height); }
static void drawSelectionArc(XmHTMLWidget html, XmHTMLImage *image, mapArea *area) { ToolkitAbstraction *tka = HTML_ATTR(tka); int x = image->owner->x - html->html.scroll_x + area->coords[0]; int y = image->owner->y - html->html.scroll_y + area->coords[1]; int radius = area->coords[2]; /* upper-left corner of bounding rectangle */ x -= radius; y -= radius; tka->SetForeground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(imagemap_fg)); tka->DrawArc(tka->dpy, tka->win, HTML_ATTR(gc), x, y, 2*radius, 2*radius, 0, 23040); }
*/ #undef HTML_ATTR #define HTML_ATTR(t,a) { #a } #undef HTML_ATTRIBUTES #define HTML_ATTRIBUTES(t) { 0 } /* ** ATTRIBUTE LISTS */ PRIVATE HTAttr no_attr[1] = {{ 0 }}; PRIVATE HTAttr body_attr[HTML_BODY_ATTRIBUTES+1] = { /* to catch images */ HTML_ATTR(BODY,ALINK), HTML_ATTR(BODY,BACKGROUND), HTML_ATTR(BODY,BGCOLOR), HTML_ATTR(BODY,CLASS), HTML_ATTR(BODY,DIR), HTML_ATTR(BODY,ID), HTML_ATTR(BODY,LANG), HTML_ATTR(BODY,LINK), HTML_ATTR(BODY,STYLE), HTML_ATTR(BODY,TEXT), HTML_ATTR(BODY,TITLE), HTML_ATTR(BODY,VLINK), HTML_ATTRIBUTES(BODY) }; PRIVATE HTAttr frame_attr[HTML_FRAME_ATTRIBUTES+1] = { /* frame attributes */
/***** * Name: _PLC_GIF_Init * Return Type: void * Description: image initializer for GIF images * In: * plc: current PLC * Returns: * Nothing but PLC is updated. * Note: * As this routine must be fully re-entrant, it needs a lot of checks * to make sure we have the data we want fully available. * The drawback is that if we are being suspended while doing this * initialization, everything must be reset and repeated the next time * this routine is called. *****/ void _PLC_GIF_Init(PLC *plc) { Byte buf[16], c; PLCImageGIF *gif; gif = &(plc->object->plc_gif_image); _XmHTMLDebug(15, ("plc.c: _PLC_GIF_Init for %s\n", plc->url)); /* this plc is active */ plc->plc_status = PLC_ACTIVE; /***** * When this routine is called, the init method of this PLC has already * been called to determine the type of this PLC Image object. Therefore * we already have data available and we need to rewind the input buffer * back to the beginning. *****/ _PLCRewindInputBuffer(plc); /* we know this is a gif image, so skip magic */ gif->info->type = IMAGE_GIF; (void)_PLCReadOK(plc, buf, 6); /* read logical screen descriptor */ (void)_PLCReadOK(plc, buf, 7); /* image dimensions */ gif->width = LM_to_uint(buf[0],buf[1]); gif->height = LM_to_uint(buf[2],buf[3]); /* set colorspace and allocate a colormap */ gif->colorclass = XmIMAGE_COLORSPACE_INDEXED; gif->cmapsize = 2<<(buf[4]&0x07); /* * We may have been called before (but returned 'cause not enough data * was available). */ if(gif->cmap == NULL) gif->cmap = (XCOLOR*)calloc(gif->cmapsize, sizeof(XCOLOR)); /* image is initially fully opaque */ gif->transparency = XmNONE; gif->bg_pixel = -1; /* * Incoming data buffer. This is *way* too much as the incoming data * will be compressed (but it does make sure there is enough room) */ gif->buf_size = gif->width*gif->height; gif->buf_pos = 0; /* current pos in data received so far */ gif->byte_count = 0; /* size of data received so far */ if(gif->buffer == NULL) gif->buffer = (Byte*)calloc(gif->buf_size + 1, sizeof(Byte)); /* check if a global colormap is available */ if(BitSet(buf[4], LOCALCOLORMAP)) { if(!(ReadColormap(plc, gif))) { /* premature end of data. */ if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "global"); plc->plc_status = PLC_ABORT; } return; /* no global colormap! */ } } /* process all extensions */ c = 0; while(c != ',') { if(!_PLCReadOK(plc, &c, 1)) return; if (c == ';') /* GIF terminator */ { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "pixel data"); plc->plc_status = PLC_ABORT; return; } if(c == '!') /* Extension */ { if(!_PLCReadOK(plc,&c,1)) { if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "extension block type"); plc->plc_status = PLC_ABORT; } return; } if(!(DoExtension(plc, c))) { if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_107, plc->url, "extension block"); plc->plc_status = PLC_ABORT; } return; } continue; } if (c != ',') continue; /* Not a valid start character */ } /* get image descriptor */ if(!_PLCReadOK(plc, buf, 9)) return; /* see if we are to use a local colormap */ if(BitSet(buf[8], LOCALCOLORMAP)) { /* local colormap size */ gif->ncolors = 1<<((buf[8]&0x07)+1); /* do we also have a glocal colormap? */ if(gif->cmap) free(gif->cmap); gif->cmapsize = gif->ncolors; gif->cmap = (XCOLOR*)calloc(gif->cmapsize, sizeof(XCOLOR)); if(!(ReadColormap(plc, gif))) { /* premature end of data. */ if(plc->plc_data_status == STREAM_END) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "local"); plc->plc_status = PLC_ABORT; } return; /* no global colormap! */ } } gif->ncolors = gif->cmapsize; /* sanity check: image *must* have a colormap */ if(gif->cmap == NULL) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_106, plc->url, "global or local"); plc->plc_status = PLC_ABORT; return; /* no global colormap! */ } /* image depth (= codeSize in GIF images, unused in GZF images) */ if(!(_PLCReadOK(plc, &c, 1))) return; gif->depth = (int)(c & 0xff); /* check interlacing */ if(BitSet(buf[8], INTERLACE)) { /* interlaced gifs require 4 passes and use an initial rowstride of 8 */ gif->npasses = 4; gif->stride = 8; } else { /* regular gif, 1 pass will get us the entire image */ gif->npasses = 1; gif->stride = 0; } gif->curr_pass = 0; gif->curr_scanline = 0; /***** * This routine is also used for GZF images, so before initializing * the LZWStream object we need to make sure we have been called for * a true GIF image. *****/ if(plc->object->type == plcGIF) { XmHTMLWidget html = plc->object->plc_any.owner; if(HTML_ATTR(gif_proc) != NULL) { gif->external_codec = True; gif->inflate = HTML_ATTR(gif_proc); if((gif->gstream = (XmHTMLGIFStream*)malloc(sizeof(XmHTMLGIFStream))) == NULL) { /* out of memory, too bad then */ _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_113, plc->url, sizeof(XmHTMLGIFStream)); plc->plc_status = PLC_ABORT; return; } /* initialize GIFStream object */ memset(gif->gstream, 0, sizeof(XmHTMLGIFStream)); gif->gstream->codesize = (int)c; gif->gstream->state = GIF_STREAM_INIT; gif->gstream->next_out = gif->buffer; gif->gstream->avail_out = gif->buf_size + 1; gif->gstream->is_progressive = True; /* * and call external decoder so it can initialize its own data * structures */ if((gif->inflate(gif->gstream)) != GIF_STREAM_OK) { if(gif->gstream->msg != NULL) { _XmHTMLWarning(__WFUNC__(gif->owner, "_PLC_GIF_Init"), XMHTML_MSG_109, plc->url, gif->gstream->msg ? gif->gstream->msg : "(unknown error)"); } /* external decoder initalization failed, abort and return */ plc->plc_status = PLC_ABORT; return; } gif->gstream->state = GIF_STREAM_OK; } else { /* initialize local data buffer */ gif->ib.file = plc->url; gif->ib.buffer = gif->buffer; gif->ib.size = 0; gif->ib.next = 0; gif->ib.type = IMAGE_GIF; gif->ib.depth = gif->depth; gif->ib.may_free = False; /* initialize LZWStream object */ if(gif->lstream == NULL) { if((gif->lstream = LZWStreamCreate(&(gif->ib), html->html.zCmd)) == NULL) { /* couldn't create stream, abort and return */ plc->plc_status = PLC_ABORT; return; } /* set read functions */ gif->lstream->readOK = _XmHTMLGifReadOK; gif->lstream->getData = _XmHTMLGifGetDataBlock; } /* first byte in buffer is gif codesize */ gif->ib.buffer[0] = c; gif->ib.size = 1; } /* allocate room for final image data */ if(gif->data == NULL) { gif->data = (Byte*)calloc(gif->buf_size + 1, sizeof(Byte)); /* don't allocate clipmask yet, it's done in the plc code */ } gif->data_size = gif->buf_size; gif->data_pos = 0; } /* object has been initialized */ plc->initialized = True; plc->curr_obj_func = 0; /* move to GIF scanline reader */ return; }
/***** * Name: XmHTMLTextGetFormatted * Return Type: String * Description: returns a formatted copy of the current document. * In: * w: XmHTMLWidget id; * papertype: type of paper to use (any of the XmHTMLTEXT_PAPERSIZE enums); * papersize: size of paper for custom stuff, or default overrides; * type: type of output wanted, plain, formatted or PS; * PSoptions: options to use when creating postscript output. * Returns: * a string which needs to be freed by the caller. *****/ String XmHTMLTextGetFormatted(Widget w, unsigned char papertype, XmHTMLPaperSize *paperdef, unsigned char type, unsigned char PSoptions) { XmHTMLWidget html; XmHTMLPaperSize *pdef, pbase; String ret_val = NULL; /* sanity check */ if(!w || !XmIsHTML(w)) { _XmHTMLBadParent(w, "TextGetFormatted"); return(NULL); } /* custom papersize requires a paper definition. */ if(papertype == XmHTMLTEXT_PAPERSIZE_CUSTOM && paperdef == NULL) { _XmHTMLWarning(__WFUNC__(w, "XmHTMLTextGetFormatted"), XMHTML_MSG_23); return(NULL); } /* widget ptr */ html = (XmHTMLWidget)w; /***** * get appropriate papersize definitions if not given. *****/ if(papertype != XmHTMLTEXT_PAPERSIZE_CUSTOM && paperdef == NULL) { /* formatting routines use point size */ if(papertype == XmHTMLTEXT_PAPERSIZE_A4) { pbase.unit_type = XmHTML_POINT; pbase.paper_type = XmHTMLTEXT_PAPERSIZE_A4; pbase.width = 597; /* 210mm */ pbase.height = 845; /* 297mm */ pbase.left_margin = 57; /* 20mm */ pbase.right_margin = 57; pbase.top_margin = 57; pbase.bottom_margin = 57; } else /* XmHTMLTEXT_PAPERSIZE_LETTER */ { pbase.unit_type = XmHTML_POINT; pbase.paper_type = XmHTMLTEXT_PAPERSIZE_LETTER; pbase.width = 614; /* 8.5in */ pbase.height = 795; /* 11in */ pbase.left_margin = 65; /* 0.9in */ pbase.right_margin = 65; pbase.top_margin = 65; pbase.bottom_margin = 51; /* 0.7in */ } /* convert to correct output type */ pdef = _XmHTMLTextCheckAndConvertPaperDef(html, &pbase, type); } else /* check validity of paper definition and convert to correct type */ pdef = _XmHTMLTextCheckAndConvertPaperDef(html, paperdef, type); if(pdef == NULL) return(NULL); switch(type) { case XmHTMLTEXT_PLAIN: ret_val = _XmHTMLTextGetPlain(html, pdef, HTML_ATTR(formatted), NULL, 0); break; case XmHTMLTEXT_FORMATTED: ret_val = _XmHTMLTextGetFormatted(html, pdef, HTML_ATTR(formatted), NULL, 0); break; case XmHTMLTEXT_POSTSCRIPT: ret_val = _XmHTMLTextGetPS(html, pdef, HTML_ATTR(formatted), NULL, PSoptions); break; default: _XmHTMLWarning(__WFUNC__(w, "XmHTMLTextGetFormatted"), XMHTML_MSG_24); } /* no longer needed */ free(pdef); return(ret_val); }
/***** * Name: _XmHTMLTextGetPS * Return Type: String * Description: converts text between start & end into a postscript document * In: * html: XmHTMLWidget id; * pdef: papersize definition. unittype must be XmHTML_POINT; * start: start object; * end: end object; * options: postscript options (font to use, header, footer cmds); * Returns: * a String with postscript commands. Must be freed by caller. *****/ String _XmHTMLTextGetPS(XmHTMLWidget html, XmHTMLPaperSize *pdef, XmHTMLObjectTableElement start, XmHTMLObjectTableElement end, Byte options) { PIXMAP pixmap; WINDOW save; int scroll_x, scroll_y; int paint_x, paint_y, paint_w, paint_h; int margin_w, margin_h, work_w; ToolkitAbstraction *tka; String buf, ret_val = NULL; XpmAttributes xpm; int xpm_err = XpmSuccess; GC gc, bg_gc; int y = 0; XmHTMLObjectTable *pstart, *pend; if(pdef->unit_type != XmHTML_POINT) { _XmHTMLWarning(__WFUNC__(html, "_XmHTMLTextGetPS"), XMHTML_MSG_88, "POINT"); return(NULL); } /***** * dirty trick: create a single pixmap in which we will draw each * page. Set it as the drawable in the current tka, adjust the document * dimensions to reflect the selected paper properties, recalculate * the layout and paint each page. When a page has been rendered, * convert it to postscript and append to the return buffer. *****/ tka = HTML_ATTR(tka); if(pdef->width > (Dimension)~0 || pdef->height > (Dimension)~0) { _XmHTMLWarning(__WFUNC__(html, "_XmHTMLTextGetPS"), "Selected paper to large. Can't convert to postscript (yet)"); return(NULL); } if((pixmap = tka->CreatePixmap(tka->dpy, tka->DefaultRoot, pdef->width, pdef->height, XCCGetDepth(HTML_ATTR(xcc)))) == None) { _XmHTMLWarning(__WFUNC__(html, "_XmHTMLTextGetPS"), XMHTML_MSG_66, "(postscript stage 1 output)"); return(NULL); } /* save current drawable */ save = (WINDOW)tka->win; /* save all settins that will get altered */ scroll_x = HTML_ATTR(scroll_x); scroll_y = HTML_ATTR(scroll_y); paint_y = HTML_ATTR(paint_y); paint_h = HTML_ATTR(paint_height); paint_x = HTML_ATTR(paint_x); paint_w = HTML_ATTR(paint_width); pstart = HTML_ATTR(paint_start); pend = HTML_ATTR(paint_end); margin_w = HTML_ATTR(margin_width); margin_h = HTML_ATTR(margin_height); work_w = HTML_ATTR(work_width); gc = HTML_ATTR(gc); bg_gc = HTML_ATTR(bg_gc); /* reset and set paper properties */ HTML_ATTR(scroll_x) = 0; HTML_ATTR(scroll_y) = 0; HTML_ATTR(paint_y) = 0; HTML_ATTR(paint_x) = 0; HTML_ATTR(paint_width) = pdef->width; HTML_ATTR(paint_height) = pdef->height - pdef->bottom_margin; HTML_ATTR(paint_start) = NULL; HTML_ATTR(paint_end) = NULL; HTML_ATTR(margin_width) = pdef->left_margin; HTML_ATTR(margin_height) = pdef->top_margin; HTML_ATTR(work_width) = pdef->width - pdef->right_margin; /* we also will be needing seperate GC's for this */ HTML_ATTR(gc) = tka->CreateGC(tka->dpy, pixmap, 0, NULL); tka->SetFunction(tka->dpy, HTML_ATTR(gc), tka->gc_func[GC_GXcopy]); tka->SetForeground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(body_fg)); tka->SetBackground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(body_bg)); HTML_ATTR(bg_gc) = tka->CreateGC(tka->dpy, pixmap, 0, NULL); tka->CopyGC(tka->dpy, HTML_ATTR(gc), 0xFFFF, HTML_ATTR(bg_gc)); /* set new drawable */ _XmHTMLToolkitAbstractionSetDrawable(tka, pixmap); /* Recompute layout for new paper definition */ _XmHTMLComputeLayout(html); /* and paint & convert each page in turn */ while(HTML_ATTR(scroll_y) < HTML_ATTR(formatted_height)) { /***** * Initialize pixmap if we don't have a body image. Refresh will * do perform background image stuff. *****/ if(!HTML_ATTR(body_image)) { tka->SetForeground(tka->dpy, HTML_ATTR(gc), HTML_ATTR(body_bg)); tka->FillRectangle(tka->dpy, tka->win, HTML_ATTR(gc), 0, 0, pdef->width, pdef->height); } /* paint this page */ _XmHTMLRefresh(html, 0, 0, pdef->width, pdef->height); /* move to next page */ HTML_ATTR(scroll_y) += pdef->height; /***** * For now, let xpm create an XPM data buffer from the created * pixmap (libXpm puts the pixmap into an XImage and converts * the resulting data). * Later on we will do this by ourselves. *****/ xpm.width = pdef->width; xpm.height = pdef->height; xpm.valuemask = XpmSize; xpm_err = XpmCreateBufferFromPixmap(tka->dpy, &buf, pixmap, None, &xpm); /* too bad if it fails */ if(xpm_err != XpmSuccess) { if(buf != NULL) free(buf); switch(xpm_err) { case XpmColorError: case XpmColorFailed: fprintf(stderr, "XPM: color allocation error.\n"); break; case XpmNoMemory: fprintf(stderr, "XPM: out of memory\n"); break; default: fprintf(stderr, "XPM: unknown error\n"); } if(ret_val) free(ret_val); ret_val = NULL; goto done; } else { /***** * TODO * Convert the xpm data to an XmImageInfo structure and convert * that to postscript. * * For now, we append the xpm data to the already received * pages. This will result in a multi-image pixmap, which * only few programs support (ImageMagick is one if I'm not * mistaking). Postscript output can be obtained by splitting * the return buffer into seperate pages and then running * each page through netpbm * (xpmtoppm image.xpm | pnmtops > page.ps) *****/ if(ret_val) { ret_val = realloc(ret_val, strlen(ret_val) + strlen(buf) + 1); strcat(ret_val, buf); } else ret_val = strdup(buf); free(buf); } } done: /* reset everything */ HTML_ATTR(scroll_x) = scroll_x; HTML_ATTR(scroll_y) = scroll_y; HTML_ATTR(paint_y) = paint_y; HTML_ATTR(paint_x) = paint_x; HTML_ATTR(paint_width) = paint_w; HTML_ATTR(paint_height) = paint_h; HTML_ATTR(paint_start) = pstart; HTML_ATTR(paint_end) = pend; HTML_ATTR(margin_width) = margin_w; HTML_ATTR(margin_height) = margin_h; HTML_ATTR(work_width) = work_w; /* free allocated gc's */ tka->FreeGC(tka->dpy, HTML_ATTR(gc)); tka->FreeGC(tka->dpy, HTML_ATTR(bg_gc)); /* restore original gc's */ HTML_ATTR(gc) = gc; HTML_ATTR(bg_gc) = bg_gc; _XmHTMLToolkitAbstractionSetDrawable(tka, save); /* Do a redisplay to restore everyting correctly */ XmHTMLRedisplay((Widget)html); return(ret_val); }