This repository has been archived on 2024-01-04. You can view files and clone it, but cannot push or open issues or pull requests.
ncsa-mosaic/libhtmlw/HTMLformat.c

7064 lines
142 KiB
C

/****************************************************************************
* NCSA Mosaic for the X Window System *
* Software Development Group *
* National Center for Supercomputing Applications *
* University of Illinois at Urbana-Champaign *
* 605 E. Springfield, Champaign IL 61820 *
* mosaic@ncsa.uiuc.edu *
* *
* Copyright (C) 1993, Board of Trustees of the University of Illinois *
* *
* NCSA Mosaic software, both binary and source (hereafter, Software) is *
* copyrighted by The Board of Trustees of the University of Illinois *
* (UI), and ownership remains with the UI. *
* *
* The UI grants you (hereafter, Licensee) a license to use the Software *
* for academic, research and internal business purposes only, without a *
* fee. Licensee may distribute the binary and source code (if released) *
* to third parties provided that the copyright notice and this statement *
* appears on all copies and that no charge is associated with such *
* copies. *
* *
* Licensee may make derivative works. However, if Licensee distributes *
* any derivative work based on or derived from the Software, then *
* Licensee will (1) notify NCSA regarding its distribution of the *
* derivative work, and (2) clearly notify users that such derivative *
* work is a modified version and not the original NCSA Mosaic *
* distributed by the UI. *
* *
* Any Licensee wishing to make commercial use of the Software should *
* contact the UI, c/o NCSA, to negotiate an appropriate license for such *
* commercial use. Commercial use includes (1) integration of all or *
* part of the source code into a product for sale or license by or on *
* behalf of Licensee to third parties, or (2) distribution of the binary *
* code or source code to third parties that need it to utilize a *
* commercial product sold or licensed by or on behalf of Licensee. *
* *
* UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
* WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
* USERS OF THIS SOFTWARE. *
* *
* By using or copying this Software, Licensee agrees to abide by the *
* copyright law and all other applicable laws of the U.S. including, but *
* not limited to, export control laws, and the terms of this license. *
* UI shall have the right to terminate this license immediately by *
* written notice upon Licensee's breach of, or non-compliance with, any *
* of its terms. Licensee may be held legally responsible for any *
* copyright infringement that is caused or encouraged by Licensee's *
* failure to abide by the terms of this license. *
* *
* Comments and questions are welcome and can be sent to *
* mosaic-x@ncsa.uiuc.edu. *
****************************************************************************/
#include "config.h"
#ifndef VMS
#include <sys/time.h>
struct timeval Tv;
struct timezone Tz;
#else
#include <time.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "HTMLP.h"
/*
* I need my own is ispunct function because I need a closing paren
* immediately after a word to act like punctuation.
*/
#define MY_ISPUNCT(val) (ispunct((int)(val)) || ((val) == ')'))
#define INDENT_SPACES 2
/* SWP -- Now using eptr->bwidth -- 02/08/96
#define IMAGE_BORDER 2 */
#define IMAGE_DEFAULT_BORDER 2
#define D_NONE 0
#define D_TITLE 1
#define D_TEXT 2
#define D_OLIST 3
#define D_ULIST 4
#ifndef DISABLE_TRACE
extern int htmlwTrace;
#endif
extern struct ele_rec *AddEle();
extern void FreeLineList();
extern void FreeObjList();
extern int SwapElements();
extern struct ele_rec **MakeLineList();
extern char *ParseMarkTag();
extern char *MaxTextWidth();
extern char *IsMapForm();
extern char *DelayedHRef();
extern int IsDelayedHRef();
extern int AnchoredHeight();
extern struct mark_up *HTMLParse();
extern struct ref_rec *FindHRef();
extern struct delay_rec *FindDelayedImage();
extern ImageInfo *NoImageData();
extern ImageInfo *DelayedImageData();
extern Pixmap NoImage();
extern Pixmap DelayedImage();
extern Pixmap InfoToImage();
extern int caseless_equal();
extern void clean_white_space();
extern void WidgetRefresh();
extern WidgetInfo *MakeWidget();
extern XFontStruct *GetWidgetFont();
extern void AddNewForm();
extern void PrepareFormEnd();
extern char *ComposeCommaList();
extern void FreeCommaList();
extern TableInfo *MakeTable();
extern void TableRefresh();
/* for selective image loading */
extern Boolean currently_delaying_images;
/*******************************/
/*SWP -- 8/14/95*/
int tableSupportEnabled;
/*
* To allow arbitrary nesting of lists
*/
typedef struct dtype_rec {
int type; /* D_NONE, D_TITLE, D_TEXT, D_OLIST, D_ULIST */
int count;
int compact;
struct dtype_rec *next;
} DescRec;
/*
* To allow arbitrary nesting of font changes
*/
typedef struct font_rec {
XFontStruct *font;
struct font_rec *next;
} FontRec;
static DescRec BaseDesc;
static DescRec *DescType;
static DescRec *ListData;
static FontRec FontBase;
static FontRec *FontStack;
static XFontStruct *currentFont;
static XFontStruct *saveFont;
static unsigned long Fg;
static unsigned long Bg;
static int Width;
static int MaxWidth;
static int ElementId;
static int WidgetId;
static int LineNumber;
static int LineHeight;
static int LineBottom;
static int BaseLine;
static int TextIndent;
static int MarginW;
static int Ignore;
static int Preformat;
static int PF_LF_State; /* Pre-formatted linefeed state. Hack for bad HTMLs */
static int NeedSpace;
static Boolean Internal;
static Boolean DashedUnderlines;
static Boolean Strikeout;
static int Underlines;
static int CharsInLine;
static int IndentLevel;
static struct ele_rec *Current;
static char *AnchorText;
static char *TitleText;
static char *TextAreaBuf;
static struct mark_up *Last;
static FormInfo *CurrentForm;
static MapInfo *CurrentMap=NULL; /* csi stuff -- swp */
static SelectInfo *CurrentSelect;
static int Superscript; /* amb */
static int Subscript;
static XFontStruct *nonScriptFont;
static int InDocHead;
static int InUnderlined;
static int Centered; // SAM
/*
* Turned out we were taking WAY too much time mallocing and freeing
* memory when composing the lines into elements. So this ineligent
* method minimizes all that.
*/
#define COMP_LINE_BUF_LEN 1024
static char *CompLine = NULL;
static int CompLineLen = 0;
static char *CompWord = NULL;
static int CompWordLen = 0;
/*
* Create a formatted element
*/
struct ele_rec *
CreateElement(hw, type, fp, x, y, edata, w, h, bw)
HTMLWidget hw;
int type;
XFontStruct *fp;
int x, y;
char *edata, *w, *h;
int bw;
{
struct ele_rec *eptr;
int baseline;
if (fp != NULL)
{
baseline = fp->max_bounds.ascent;
}
else
{
baseline = LineHeight;
}
eptr = (struct ele_rec *)malloc(sizeof(struct ele_rec));
if (eptr == NULL)
{
fprintf(stderr, "Cannot allocate space for element buffer\n");
exit(1);
}
memset(eptr, 0, sizeof(struct ele_rec));
eptr->type = type;
eptr->pic_data = NULL;
eptr->widget_data = NULL;
eptr->table_data = NULL;
eptr->font = fp;
eptr->alignment = ALIGN_BOTTOM;
eptr->selected = False;
eptr->internal = Internal;
eptr->strikeout = Strikeout;
eptr->bwidth = bw;
eptr->x = x;
eptr->y = y;
eptr->y_offset = 0;
eptr->width = 0;
eptr->line_number = LineNumber;
eptr->line_height = LineHeight;
eptr->fg = Fg;
eptr->bg = Bg;
eptr->underline_number = Underlines;
eptr->dashed_underline = DashedUnderlines;
eptr->indent_level = IndentLevel;
if(Centered && type != E_TABLE) eptr->alignment = ALIGN_CENTER;
switch(type)
{
case E_TEXT:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
eptr->y_offset = 0;
eptr->edata_len = strlen(edata) + 1;
eptr->edata = (char *)malloc(eptr->edata_len);
if (eptr->edata == NULL)
{
eptr->edata_len = 0;
fprintf(stderr, "Cannot allocate space for copy of text element data\n");
exit(1);
}
strcpy(eptr->edata, edata);
/*
* if this is an anchor, puts its href value into
* the element.
*/
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
break;
case E_BULLET:
eptr->ele_id = ElementId;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
else if (baseline < BaseLine)
{
eptr->y_offset = BaseLine - baseline;
}
/*
* Bullets can't be underlined!
*/
eptr->underline_number = 0;
eptr->edata = NULL;
eptr->edata_len = 0;
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
case E_HRULE:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
else if (baseline < BaseLine)
{
eptr->y_offset = BaseLine - baseline;
}
/*
* Rules can't be underlined!
*/
eptr->underline_number = 0;
eptr->edata = NULL;
eptr->edata_len = 0;
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
case E_LINEFEED:
eptr->ele_id = ElementId;
eptr->y_offset = 0;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
/*
* Linefeeds have to use the maximum line height.
* Deal with bad Lucidia descents.
*/
#ifdef NO_EXTRA_FILLS
eptr->line_height = eptr->font->ascent +
eptr->font->descent;
#else
eptr->line_height = LineHeight;
#endif /* NO_EXTRA_FILLS */
if ((BaseLine + LineBottom) > eptr->line_height)
{
eptr->line_height = BaseLine + LineBottom;
}
/*
* Linefeeds can't be underlined!
*/
eptr->underline_number = 0;
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this linefeed is part of a broken anchor put
* its href value into the element so we can reconnect
* it when activated.
* If it at the beginning of an anchor, don't put
* the href in, and change the color back.
*/
if (AnchorText != NULL)
{
char *tptr;
tptr = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
if ((Current != NULL)&&
((Current->anchorHRef == NULL)||
(tptr == NULL)||
(strcmp(Current->anchorHRef, tptr) != 0)))
{
if (tptr)
free(tptr);
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
/*
* Without motif we use our own foreground resource instead of
* using the manager's
*/
#ifdef MOTIF
eptr->fg = hw->manager.foreground;
#else
eptr->fg = hw->html.foreground;
#endif /* MOTIF */
}
else
{
eptr->anchorHRef = tptr;
eptr->anchorName =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
break;
case E_IMAGE:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
/*
* Images can't be underlined!
*/
eptr->underline_number = 0;
if (edata != NULL)
{
eptr->edata_len = strlen(edata) + 1;
eptr->edata = (char *)malloc(eptr->edata_len);
if (eptr->edata == NULL)
{
eptr->edata_len = 0;
fprintf(stderr, "Cannot allocate space for copy of image element data\n");
exit(1);
}
strcpy(eptr->edata, edata);
}
else
{
eptr->edata_len = 0;
eptr->edata = NULL;
}
/*
* if this image is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
/*
* Picture stuff
*/
/*
* if we have an image resolver, use it.
*/
if (hw->html.resolveImage != NULL)
{
int internal;
/*
* See if this is a special internal image
*/
if ((edata != NULL)&&
(strncmp(edata, INTERNAL_IMAGE,
strlen(INTERNAL_IMAGE)) == 0))
{
internal = 1;
}
else
{
internal = 0;
}
/*
* if we delay image fetching
* internal images are not delayed.
*/
if (((hw->html.delay_images == True) &&
(!internal)) ||
currently_delaying_images == 1 )
{
/*
* see if already cached.
*/
eptr->pic_data = (*(resolveImageProc)
(hw->html.resolveImage))(hw, edata, 1, w, h);
if (eptr->pic_data != NULL)
{
eptr->pic_data->delayed = 0;
/*
* Mark images we have sucessfully
* loaded at least once
*/
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->fetched = 1;
}
}
/*
* else, not cached.
*/
else
{
/*
* just image
*/
if (eptr->anchorHRef == NULL)
{
eptr->pic_data = DelayedImageData(hw,
False);
eptr->pic_data->delayed = 1;
eptr->anchorHRef = DelayedHRef(hw);
eptr->fg = hw->html.anchor_fg;
}
/*
* else anchor and image
*/
else
{
eptr->pic_data = DelayedImageData(hw,
True);
eptr->pic_data->delayed = 1;
}
}
}
else
{
eptr->pic_data = (*(resolveImageProc)
(hw->html.resolveImage))(hw, edata, 0, w, h);
if (eptr->pic_data != NULL)
{
eptr->pic_data->delayed = 0;
/*
* Mark images we have sucessfully
* loaded at least once
*/
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->fetched = 1;
}
}
}
if (eptr->pic_data != NULL)
{
eptr->pic_data->internal = internal;
}
}
if (eptr->pic_data == NULL)
{
eptr->pic_data = NoImageData(hw);
eptr->pic_data->delayed = 0;
eptr->pic_data->internal = 0;
}
break;
case E_TABLE:
ElementId++;
eptr->ele_id = ElementId;
/*
* Table's can't be underlined
*/
eptr->underline_number = 0;
/*
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
*/
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this table is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
/*
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
*/
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject= ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
eptr->table_data = MakeTable (hw, edata,
(x + IMAGE_DEFAULT_BORDER), (y + IMAGE_DEFAULT_BORDER));
break;
case E_WIDGET:
/*
* get a unique element id
*/
WidgetId++;
ElementId++;
eptr->ele_id = ElementId;
/*
* Widgets can't be underlined!
*/
eptr->underline_number = 0;
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this widget is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
/*
* Widget stuff
*/
eptr->widget_data = MakeWidget(hw, edata,
(x + IMAGE_DEFAULT_BORDER), (y + IMAGE_DEFAULT_BORDER),
WidgetId, CurrentForm);
/*
* I have no idea what to do if we can't create the
* widget. It probably means we are so messed up we
* will soon be crashing.
*/
if (eptr->widget_data == NULL)
{
}
break;
default:
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "CreateElement: Unknown type %d\n", type);
}
#endif
eptr->ele_id = ElementId;
eptr->edata = NULL;
eptr->edata_len = 0;
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
}
return(eptr);
} /* CreateElement() */
/*
* Set the formatted element into the format list. Use a pre-allocated
* list position if possible, otherwise allocate a new list position.
*/
void
SetElement(hw, type, fp, x, y, edata, w, h, bw)
HTMLWidget hw;
int type;
XFontStruct *fp;
int x, y;
char *edata;
char *w, *h;
int bw;
{
struct ele_rec *eptr;
int len;
int baseline;
if (fp != NULL)
{
baseline = fp->max_bounds.ascent;
}
else
{
baseline = LineHeight;
}
/*
* There is not pre-allocated format list, or we have reached
* the end of the pre-allocated list. Create a new element, and
* add it.
*/
if ((hw->html.formatted_elements == NULL)||
((Current != NULL)&&(Current->next == NULL)))
{
eptr = CreateElement(hw, type, fp, x, y, edata, w, h, bw);
Current = AddEle(&(hw->html.formatted_elements), Current, eptr);
return;
}
/*
* If current is null, but we have a pre-allocated format list, then
* this is the first SetElement() call for this formated text, and
* we must set current to the head of the formatted list. Otherwise
* we move current to the next pre-allocated list position.
*/
if (Current == NULL)
{
Current = hw->html.formatted_elements;
}
else
{
Current = Current->next;
}
eptr = Current;
if (eptr == NULL)
{
fprintf(stderr, "SetElement: Error, setting a null element\n");
exit(1);
}
eptr->type = type;
eptr->pic_data = NULL;
eptr->widget_data = NULL;
eptr->table_data = NULL;
eptr->font = fp;
eptr->alignment = ALIGN_BOTTOM;
eptr->selected = False;
eptr->internal = Internal;
eptr->strikeout = Strikeout;
eptr->bwidth = bw;
eptr->x = x;
eptr->y = y;
eptr->y_offset = 0;
eptr->width = 0;
eptr->line_number = LineNumber;
eptr->line_height = LineHeight;
eptr->fg = Fg;
eptr->bg = Bg;
eptr->underline_number = Underlines;
eptr->dashed_underline = DashedUnderlines;
eptr->indent_level = IndentLevel;
// SAM
if(Centered && type != E_TABLE) eptr->alignment = ALIGN_CENTER;
// SAM
switch(type)
{
case E_TEXT:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
eptr->y_offset = 0;
len = strlen(edata) + 1;
if (len > eptr->edata_len)
{
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = (char *)malloc(len);
if (eptr->edata == NULL)
{
eptr->edata_len = 0;
fprintf(stderr, "Cannot allocate space for copy of text element data\n");
exit(1);
}
}
eptr->edata_len = len;
strcpy(eptr->edata, edata);
/*
* if this is an anchor, puts its href and name
* values into the element.
*/
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject= ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
break;
case E_BULLET:
eptr->ele_id = ElementId;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
else if (baseline < BaseLine)
{
eptr->y_offset = BaseLine - baseline;
}
/*
* Bullets can't be underlined!
*/
eptr->underline_number = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
case E_HRULE:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
else if (baseline < BaseLine)
{
eptr->y_offset = BaseLine - baseline;
}
/*
* Rules can't be underlined!
*/
eptr->underline_number = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
case E_LINEFEED:
eptr->ele_id = ElementId;
eptr->y_offset = 0;
if (BaseLine == -100)
{
BaseLine = baseline;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
/*
* Linefeeds have to use the maximum line height.
* Deal with bad Lucidia descents.
*/
#ifdef NO_EXTRA_FILLS
eptr->line_height = eptr->font->ascent +
eptr->font->descent;
#else
eptr->line_height = LineHeight;
#endif /* NO_EXTRA_FILLS */
if ((BaseLine + LineBottom) > eptr->line_height)
{
eptr->line_height = (BaseLine + LineBottom);
}
/*
* Linefeeds can't be underlined!
*/
eptr->underline_number = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this linefeed is part of a broken anchor put
* its href and name values into the element
* so we can reconnect it when activated.
* If it at the beginning of an anchor, don't put
* the href in and change the color back.
*/
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
if (AnchorText != NULL)
{
char *tptr;
tptr = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
if ((eptr->prev != NULL)&&
((eptr->prev->anchorHRef == NULL)||
(tptr == NULL)||
(strcmp(eptr->prev->anchorHRef, tptr) != 0)))
{
if (tptr)
free(tptr);
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
/*
* Without motif we use our own foreground resource instead of
* using the manager's
*/
#ifdef MOTIF
eptr->fg = hw->manager.foreground;
#else
eptr->fg = hw->html.foreground;
#endif /* MOTIF */
}
else
{
eptr->anchorHRef = tptr;
eptr->anchorName =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
break;
case E_IMAGE:
/*
* get a unique element id
*/
ElementId++;
eptr->ele_id = ElementId;
/*
* Images can't be underlined!
*/
eptr->underline_number = 0;
if (edata != NULL)
{
len = strlen(edata) + 1;
if (len > eptr->edata_len)
{
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = (char *)malloc(len);
if (eptr->edata == NULL)
{
eptr->edata_len = 0;
fprintf(stderr, "Cannot allocate space for copy of text element data\n");
exit(1);
}
}
eptr->edata_len = len;
strcpy(eptr->edata, edata);
}
else
{
eptr->edata_len = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
}
/*
* if this image is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
/*
* Picture stuff
*/
/*
* if we have an image resolver, use it.
*/
if (hw->html.resolveImage != NULL)
{
int internal;
/*
* See if this is a special internal image
*/
if ((edata != NULL)&&
(strncmp(edata, INTERNAL_IMAGE,
strlen(INTERNAL_IMAGE)) == 0))
{
internal = 1;
}
else
{
internal = 0;
}
/*
* if we delay image fetching
* internal images are not delayed.
*/
if (((hw->html.delay_images == True) &&
(!internal)) ||
currently_delaying_images == 1 )
{
/*
* see if already cached.
*/
eptr->pic_data = (*(resolveImageProc)
(hw->html.resolveImage))(hw, edata, 1, w, h);
if (eptr->pic_data != NULL)
{
eptr->pic_data->delayed = 0;
/*
* Mark images we have sucessfully
* loaded at least once
*/
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->fetched = 1;
}
}
/*
* else, not cached.
*/
else
{
/*
* just image
*/
if (eptr->anchorHRef == NULL)
{
eptr->pic_data = DelayedImageData(hw,
False);
eptr->pic_data->delayed = 1;
eptr->anchorHRef = DelayedHRef(hw);
eptr->fg = hw->html.anchor_fg;
}
/*
* else anchor and image
*/
else
{
eptr->pic_data = DelayedImageData(hw,
True);
eptr->pic_data->delayed = 1;
}
}
}
else
{
eptr->pic_data = (*(resolveImageProc)
(hw->html.resolveImage))(hw, edata, 0, w, h);
if (eptr->pic_data != NULL)
{
eptr->pic_data->delayed = 0;
/*
* Mark images we have sucessfully
* loaded at least once
*/
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->fetched = 1;
}
}
}
if (eptr->pic_data != NULL)
{
eptr->pic_data->internal = internal;
}
}
if (eptr->pic_data == NULL)
{
eptr->pic_data = NoImageData(hw);
eptr->pic_data->delayed = 0;
eptr->pic_data->internal = 0;
}
break;
case E_TABLE:
ElementId++;
eptr->ele_id = ElementId;
/*
* Table's can't be underlined
*/
eptr->underline_number = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this table is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject= ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
}
eptr->table_data = MakeTable (hw, edata,
(x + IMAGE_DEFAULT_BORDER), (y + IMAGE_DEFAULT_BORDER));
break;
case E_WIDGET:
/*
* get a unique element id
*/
WidgetId++;
ElementId++;
eptr->ele_id = ElementId;
/*
* Widgets can't be underlined!
*/
eptr->underline_number = 0;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
/*
* if this widget is part of an anchor put
* its href and name values into the element
* so we can reconnect it when activated.
*/
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
if (AnchorText != NULL)
{
eptr->anchorHRef = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_HREF);
eptr->anchorName = ParseMarkTag(AnchorText,
MT_ANCHOR, AT_NAME);
eptr->anchorSubject= ParseMarkTag(AnchorText,
MT_ANCHOR, AT_SUBJECT);
if (!eptr->anchorSubject) {
eptr->anchorSubject =
ParseMarkTag(AnchorText,
MT_ANCHOR, AT_TITLE);
}
}
else
{
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject= NULL;
}
/*
* Widget stuff
*/
eptr->widget_data = MakeWidget(hw, edata,
(x + IMAGE_DEFAULT_BORDER), (y + IMAGE_DEFAULT_BORDER),
WidgetId, CurrentForm);
/*
* I have no idea what to do if we can't create the
* widget. It probably means we are so messed up we
* will soon be crashing.
*/
if (eptr->widget_data == NULL)
{
}
break;
default:
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "SetElement: Unknown type %d\n", type);
}
#endif
eptr->ele_id = ElementId;
if (eptr->edata != NULL)
{
free((char *)eptr->edata);
}
eptr->edata = NULL;
eptr->edata_len = 0;
if (eptr->anchorHRef != NULL)
{
free((char *)eptr->anchorHRef);
}
if (eptr->anchorName != NULL)
{
free((char *)eptr->anchorName);
}
if (eptr->anchorSubject != NULL)
{
free((char *)eptr->anchorSubject);
}
eptr->anchorHRef = NULL;
eptr->anchorName = NULL;
eptr->anchorSubject = NULL;
break;
}
} /* SetElement() */
/*
* Change our drawing font
*/
void
NewFont(fp)
XFontStruct *fp;
{
/*
* Deal with bad Lucidia descents.
*/
if (fp->descent > fp->max_bounds.descent)
{
LineHeight = fp->max_bounds.ascent + fp->descent;
}
else
{
LineHeight = fp->max_bounds.ascent + fp->max_bounds.descent;
}
}
/*
* Place a linefeed at the end of a line.
* Create and add the element record for it.
*/
void
LinefeedPlace(hw, x, y)
HTMLWidget hw;
int *x, *y;
{
// SAM
#if 0
if(Centered) {
struct ele_rec *eptr;
int width;
printf("LineFeedPlace\n");
for(eptr = Current; eptr; eptr = eptr->next) {
printf("type %d x %d y %d width %d bwidth %d alignment %d start %d end %d\n",
eptr->type, eptr->x, eptr->y, eptr->width, eptr->bwidth,
eptr->alignment,
eptr->start_pos, eptr->end_pos);
printf("\t'%.40s'\n", eptr->edata);
// SAM Simple and wrong
if(eptr->width) {
// SAM How to get canvas width?
if(eptr->width >= 640)
printf("TOO WIDE\n");
else {
int offset = (640 - eptr->width) / 2;
eptr->x += offset;
}
}
}
}
#endif
// SAM
/*
* At the end of every line check if we have a new MaxWidth
*/
if ((*x + hw->html.margin_width) > MaxWidth)
{
MaxWidth = *x + hw->html.margin_width;
}
SetElement(hw, E_LINEFEED, currentFont, *x, *y, (char *)NULL,NULL,NULL,IMAGE_DEFAULT_BORDER);
}
/*
* We have encountered a line break. Incrment the line counter,
* and move down some space.
*/
void
LineFeed(hw, x, y)
HTMLWidget hw;
int *x, *y;
{
/*
* Manipulate linefeed state for special pre-formatted linefeed
* hack for broken HTMLs
*/
if (Preformat)
{
switch(PF_LF_State)
{
/*
* First soft linefeed
*/
case 0:
PF_LF_State = 1;
break;
/*
* Collapse multiple soft linefeeds within a pre
*/
case 1:
return;
break;
/*
* Ignore soft linefeeds after hard linefeeds
* within a pre
*/
case 2:
return;
break;
default:
PF_LF_State = 1;
break;
}
}
/*
* No blank lines allowed at the start of a document.
*/
else if (ElementId == 0)
{
return;
}
/*
* For formatted documents there are 3 linefeed states.
* 0 = in the middle of a line.
* 1 = at left margin
* 2 = at left margin with blank line above
*/
else
{
PF_LF_State++;
if (PF_LF_State > 2)
{
PF_LF_State = 2;
}
}
/*
* sanity check to set some line height if none was specified.
*/
if (BaseLine <= 0)
{
BaseLine = LineHeight;
}
LinefeedPlace(hw, x, y);
CharsInLine = 0;
*x = TextIndent;
*y = *y + BaseLine + LineBottom;
LineBottom = 0;
BaseLine = -100;
NeedSpace = 0;
LineNumber++;
}
/*
* We want to make sure that future text starts at the left margin.
* But if we are already there, don't put in a new line.
*/
void
ConditionalLineFeed(hw, x, y, state)
HTMLWidget hw;
int *x, *y;
int state;
{
if (PF_LF_State < state)
{
/*
* If this funtion is being used to insert a blank line,
* we need to look at the percentVerticalSpace resource
* to see how high to make the line.
*/
if ((state == 2)&&(hw->html.percent_vert_space > 0))
{
int l_height;
l_height = LineHeight;
LineHeight = LineHeight *
hw->html.percent_vert_space / 100;
LineFeed(hw, x, y);
LineHeight = l_height;
}
else
{
LineFeed(hw, x, y);
}
}
}
/*
* hack to make broken HTMLs within pre-formatted text have nice
* looking linefeeds.
*/
void
HardLineFeed(hw, x, y)
HTMLWidget hw;
int *x, *y;
{
/*
* Manipulate linefeed state for special pre-formatted linefeed
* hack for broken HTMLs
*/
if (Preformat)
{
switch(PF_LF_State)
{
/*
* First hard linefeed
*/
case 0:
PF_LF_State = 2;
break;
/*
* Previous soft linefeed should have been ignored, so
* ignore this hard linefeed, but set state like it
* was not ignored.
*/
case 1:
PF_LF_State = 2;
return;
break;
/*
* Honor multiple hard linefeeds.
*/
case 2:
break;
default:
PF_LF_State = 2;
break;
}
}
/*
* sanity check to set some line height if none was specified.
*/
if (BaseLine <= 0)
{
BaseLine = LineHeight;
}
LinefeedPlace(hw, x, y);
CharsInLine = 0;
*x = TextIndent;
*y = *y + BaseLine + LineBottom;
LineBottom = 0;
BaseLine = -100;
NeedSpace = 0;
LineNumber++;
}
static void
AdjustBaseLine()
{
int baseline;
int supsubBaseline;
baseline = Current->font->max_bounds.ascent;
if ((Superscript>0) || (Subscript>0))
{
supsubBaseline = nonScriptFont->max_bounds.ascent;
baseline += ((supsubBaseline * .4) * Superscript);
baseline -= ((supsubBaseline * .4) * Subscript);
baseline += 2;
}
if (BaseLine == -100)
{
BaseLine = baseline;
Current->y_offset = 0;
if (LineBottom == 0)
{
LineBottom = LineHeight - baseline;
}
else
{
/*
* It is possible (with the first item
* in a line being a top aligned image)
* for LineBottom to have already been
* set. It now needs to be
* corrected as we set a real
* BaseLine
*/
if ((LineHeight - baseline) >
(LineBottom - baseline))
{
LineBottom = LineHeight -
baseline;
}
else
{
LineBottom = LineBottom -
baseline;
}
}
}
else if (baseline <= BaseLine)
{
if (baseline < BaseLine)
{
Current->y_offset = BaseLine - baseline;
}
else
{
Current->y_offset = 0;
}
if ((LineHeight - baseline) > LineBottom)
{
LineBottom = LineHeight - baseline;
}
}
else
{
struct ele_rec *eptr;
int line, incy;
incy = baseline - BaseLine;
BaseLine = baseline;
/*
* Go back over this line
* and move everything down
* a little.
*/
eptr = Current;
line = eptr->line_number;
while ((eptr->prev != NULL)&&
(eptr->prev->line_number == line))
{
eptr = eptr->prev;
eptr->y_offset = eptr->y_offset + incy;
}
if ((LineHeight - baseline) > LineBottom)
{
LineBottom = LineHeight - baseline;
}
}
}
/*
* Place the bullet at the beginning of an unnumbered
* list item. Create and add the element record for it.
*/
void
BulletPlace(hw, x, y)
HTMLWidget hw;
int *x, *y;
{
int width, l_height;
/*
* Save the font's line height, and set your own for this
* element. Restore the fonts height when done.
* Deal with bad Lucidia descents.
*/
l_height = LineHeight;
if (hw->html.font->descent > hw->html.font->max_bounds.descent)
{
LineHeight = hw->html.font->max_bounds.ascent +
hw->html.font->descent;
}
else
{
LineHeight = hw->html.font->max_bounds.ascent +
hw->html.font->max_bounds.descent;
}
NeedSpace = 0;
width = hw->html.font->max_bounds.width;
SetElement(hw, E_BULLET, hw->html.font, *x, *y, (char *)NULL, NULL, NULL,IMAGE_DEFAULT_BORDER);
LineHeight = l_height;
/*
* This should reall be here, but it is a hack for headers on list
* elements to work if we leave it out
PF_LF_State = 0;
*/
}
/*
* Place a horizontal rule across the page.
* Create and add the element record for it.
*/
void
HRulePlace(hw, x, y, width)
HTMLWidget hw;
int *x, *y;
unsigned int width;
{
NeedSpace = 0;
*x = hw->html.margin_width;
SetElement(hw, E_HRULE, currentFont, *x, *y, (char *)NULL, NULL, NULL, IMAGE_DEFAULT_BORDER);
*x = *x + width - (2 * hw->html.margin_width);
NeedSpace = 1;
PF_LF_State = 0;
}
/*
* Place the number at the beginning of an numbered
* list item. Create and add the element record for it.
*/
void
ListNumberPlace(hw, x, y, val)
HTMLWidget hw;
int *x, *y;
int val;
{
int width, my_x;
int dir, ascent, descent;
XCharStruct all;
char buf[20];
sprintf(buf, "%d.", val);
width = hw->html.font->max_bounds.lbearing +
hw->html.font->max_bounds.rbearing;
XTextExtents(currentFont, buf, strlen(buf), &dir,
&ascent, &descent, &all);
my_x = *x - (width / 2) - all.width;
/*
* Add a space after thenumber here so it will look right when
* cut and pasted from a selection.
*/
width = strlen(buf);
buf[width] = ' ';
buf[width + 1] = '\0';
SetElement(hw, E_TEXT, currentFont, my_x, *y, buf, NULL, NULL, IMAGE_DEFAULT_BORDER);
AdjustBaseLine();
CharsInLine = CharsInLine + strlen(buf);
NeedSpace = 0;
/*
* This should reall be here, but it is a hack for headers on list
* elements to work if we leave it out
PF_LF_State = 0;
*/
}
/*
* Place a piece of pre-formatted text. Add an element record for it.
*/
void
PreformatPlace(hw, mptr, x, y, width)
HTMLWidget hw;
struct mark_up *mptr;
int *x, *y;
unsigned int width;
{
char *text;
char *start;
char *end;
char *ptr;
char tchar;
int tab_count, char_cnt;
int dir, ascent, descent;
XCharStruct all;
char *line;
int line_x;
text = mptr->text;
line_x = *x;
line = CompLine;
if (line != NULL)
{
line[0] = '\0';
}
end = text;
while (*end != '\0')
{
tab_count = 0;
char_cnt = CharsInLine;
/*
* make start and end point to one word. A word is either
* a lone linefeed, or all whitespace before a word, plus
* the text of the word itself.
*/
start = end;
/*
* Throw out carriage returns and form-feeds
*/
if ((*end == '\r')||(*end == '\f'))
{
start++;
end++;
}
else if (*end == '\n')
{
end++;
char_cnt++;
}
else
{
/*
* Should be only spaces and tabs here, so if it
* is not a tab, make it a space.
* Break on linefeeds, they must be done separately
*/
while (((int)((unsigned char)*end) < 128)&&
(isspace(*end)))
{
if (*end == '\n')
{
break;
}
else if (*end == '\t')
{
tab_count++;
char_cnt = ((char_cnt / 8) + 1) * 8;
}
else
{
*end = ' ';
char_cnt++;
}
end++;
}
while (((int)((unsigned char)*end) > 127)||
((!isspace(*end))&&(*end != '\0')))
{
end++;
char_cnt++;
}
}
/*
* Add the word to the end of this line, or insert
* a linefeed if the word is a lone linefeed.
* tabs expand to 8 spaces.
*/
if (start != end)
{
int tlen;
tchar = *end;
*end = '\0';
tlen = char_cnt + 1;
if (tlen > CompWordLen)
{
CompWordLen += COMP_LINE_BUF_LEN;
if (tlen > CompWordLen)
{
CompWordLen = tlen;
}
if (CompWord != NULL)
{
free(CompWord);
}
CompWord = (char *)malloc(CompWordLen);
}
ptr = CompWord;
/*
* If we have any tabs, expand them into spaces.
*/
if (tab_count)
{
char *p1, *p2;
int i, new;
char_cnt = CharsInLine;
p1 = ptr;
p2 = start;
while (*p2 != '\0')
{
if (*p2 == '\t')
{
new = ((char_cnt / 8) + 1) * 8;
for (i=0; i<(new-char_cnt); i++)
{
*p1++ = ' ';
}
p2++;
char_cnt = new;
}
else
{
*p1++ = *p2++;
char_cnt++;
}
}
*p1 = '\0';
}
else
{
strcpy(ptr, start);
}
#ifdef ASSUME_FIXED_WIDTH_PRE
all.width = currentFont->max_bounds.width * strlen(ptr);
#else
XTextExtents(currentFont, ptr, strlen(ptr), &dir,
&ascent, &descent, &all);
#endif /* ASSUME_FIXED_WIDTH_PRE */
if (*start == '\n')
{
if ((line != NULL)&&(line[0] != '\0'))
{
SetElement(hw, E_TEXT, currentFont,
line_x, *y, line, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = *x - line_x + 1;
AdjustBaseLine();
PF_LF_State = 0;
line[0] = '\0';
}
HardLineFeed(hw, x, y);
line_x = *x;
NeedSpace = 0;
}
else
{
char *tptr;
int tlen;
if (line == NULL)
{
tlen = strlen(ptr) + 1;
}
else
{
tlen = strlen(line) +
strlen(ptr) + 1;
}
if (tlen > CompLineLen)
{
CompLineLen += COMP_LINE_BUF_LEN;
if (tlen > CompLineLen)
{
CompLineLen = tlen;
}
tptr = (char *)malloc(CompLineLen);
if (CompLine != NULL)
{
strcpy(tptr, CompLine);
free(CompLine);
}
else
{
tptr[0] = '\0';
}
CompLine = tptr;
}
line = CompLine;
strcat(line, ptr);
*x = *x + all.width;
CharsInLine = CharsInLine + strlen(ptr);
NeedSpace = 1;
}
*end = tchar;
}
}
if ((line != NULL)&&(line[0] != '\0'))
{
SetElement(hw, E_TEXT, currentFont,
line_x, *y, line, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = *x - line_x + 1;
AdjustBaseLine();
PF_LF_State = 0;
line[0] = '\0';
}
}
/*
* Format and place a piece of text. Add an element record for it.
*/
void
FormatPlace(hw, mptr, x, y, width)
HTMLWidget hw;
struct mark_up *mptr;
int *x, *y;
unsigned int width;
{
char *text;
char *start;
char *end;
char *ptr;
char tchar;
#ifdef DOUBLE_SPACE_AFTER_PUNCT
char tchar2;
#endif /* DOUBLE_SPACE_AFTER_PUNCT */
int stripped_space;
int added_space;
int double_space;
int dir, ascent, descent;
XCharStruct all;
char *line;
int line_x;
text = mptr->text;
line_x = *x;
line = CompLine;
if (line != NULL)
{
line[0] = '\0';
}
end = text;
while (*end != '\0')
{
/*
* make start and end point to one word.
* set flag if we removed any leading white space.
* set flag if we add any leading white space.
*/
stripped_space = 0;
added_space = 0;
start = end;
while (((int)((unsigned char)*start) < 128)&&(isspace(*start)))
{
stripped_space = 1;
start++;
}
end = start;
while (((int)((unsigned char)*end) > 127)||
((!isspace(*end))&&(*end != '\0')))
{
end++;
}
/*
* Add the word to the end of this line, or insert
* a linefeed an put the word at the start of the next line.
*/
if (start != end)
{
int nobreak;
int tlen;
/*
* nobreak is a horrible hack that specifies special
* conditions where line breaks are just not allowed
*/
nobreak = 0;
tchar = *end;
*end = '\0';
/*
* Malloc temp space if needed, leave room for
* 2 spaces and a end of string char
*/
tlen = strlen(start) + 3;
if (tlen > CompWordLen)
{
CompWordLen += COMP_LINE_BUF_LEN;
if (tlen > CompWordLen)
{
CompWordLen = tlen;
}
if (CompWord != NULL)
{
free(CompWord);
}
CompWord = (char *)malloc(CompWordLen);
}
ptr = CompWord;
if ((NeedSpace > 0)&&(stripped_space))
{
if (NeedSpace == 2)
{
strcpy(ptr, " ");
added_space = 2;
}
else
{
strcpy(ptr, " ");
added_space = 1;
}
}
else
{
strcpy(ptr, "");
}
strcat(ptr, start);
#ifdef DOUBLE_SPACE_AFTER_PUNCT
/*
* If this text ends in '.', '!', or '?' we need
* to set up the addition of two spaces after it.
*/
tchar2 = ptr[strlen(ptr) - 1];
if ((tchar2 == '.')||(tchar2 == '!')||(tchar2 == '?'))
{
double_space = 1;
}
else
{
double_space = 0;
}
#else
double_space = 0;
#endif /* DOUBLE_SPACE_AFTER_PUNCT */
XTextExtents(currentFont, ptr, strlen(ptr), &dir,
&ascent, &descent, &all);
/*
* Horrible hack for punctuation following
* font changes to not go on the next line.
*/
if ((MY_ISPUNCT(*ptr))&&(added_space == 0))
{
char *tptr;
/*
* Take into account whole streams of
* punctuation.
*/
nobreak = 1;
tptr = ptr;
while ((*tptr != '\0')&&(MY_ISPUNCT(*tptr)))
{
tptr++;
}
if (*tptr != '\0')
{
nobreak = 0;
}
}
/*
* No linebreaks if this whole line is just too
* long.
*/
if (*x == TextIndent)
{
nobreak = 1;
}
if (((*x + all.width + MarginW) <= width)||(nobreak))
{
char *tptr;
int tlen;
if (line == NULL)
{
tlen = strlen(ptr) + 1;
}
else
{
tlen = strlen(line) +
strlen(ptr) + 1;
}
if (tlen > CompLineLen)
{
CompLineLen += COMP_LINE_BUF_LEN;
if (tlen > CompLineLen)
{
CompLineLen = tlen;
}
tptr = (char *)malloc(CompLineLen);
if (CompLine != NULL)
{
strcpy(tptr, CompLine);
free(CompLine);
}
else
{
tptr[0] = '\0';
}
CompLine = tptr;
}
line = CompLine;
strcat(line, ptr);
}
else
{
char *tptr, *tptr2;
int tlen;
if ((line != NULL)&&(line[0] != '\0'))
{
SetElement(hw, E_TEXT, currentFont,
line_x, *y, line, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = *x - line_x + 1;
AdjustBaseLine();
PF_LF_State = 0;
line[0] = '\0';
}
LineFeed(hw, x, y);
line_x = *x;
/*
* If we added a space before, remove it now
* since we are at the beginning of a new line
*/
if (added_space)
{
tptr2 = (char *)(ptr + added_space);
}
else
{
tptr2 = ptr;
}
XTextExtents(currentFont, tptr2,
strlen(tptr2), &dir,
&ascent, &descent, &all);
if (line == NULL)
{
tlen = strlen(tptr2) + 1;
}
else
{
tlen = strlen(line) +
strlen(tptr2) + 1;
}
if (tlen > CompLineLen)
{
CompLineLen += COMP_LINE_BUF_LEN;
if (tlen > CompLineLen)
{
CompLineLen = tlen;
}
tptr = (char *)malloc(CompLineLen);
if (CompLine != NULL)
{
strcpy(tptr, CompLine);
free(CompLine);
}
else
{
tptr[0] = '\0';
}
CompLine = tptr;
}
line = CompLine;
strcat(line, tptr2);
}
/*
* Set NeedSpace for one or 2 spaces based on
* whether we are after a '.', '!', or '?'
* or not.
*/
if (double_space)
{
NeedSpace = 2;
}
else
{
NeedSpace = 1;
}
*x = *x + all.width;
*end = tchar;
}
/*
* Else if there is trailing whitespace, add it now
*/
else if ((NeedSpace > 0)&&(stripped_space))
{
char *tptr;
char *spc;
int tlen;
if (NeedSpace == 2)
{
spc = (char *)malloc(strlen(" ") + 1);
strcpy(spc, " ");
}
else
{
spc = (char *)malloc(strlen(" ") + 1);
strcpy(spc, " ");
}
XTextExtents(currentFont, spc, strlen(spc), &dir,
&ascent, &descent, &all);
/*
* Sigh, adding this one little space might force a
* line break.
*/
if ((*x + all.width + MarginW) <= width)
{
if (line == NULL)
{
tlen = strlen(spc) + 1;
}
else
{
tlen = strlen(line) +
strlen(spc) + 1;
}
if (tlen > CompLineLen)
{
CompLineLen += COMP_LINE_BUF_LEN;
if (tlen > CompLineLen)
{
CompLineLen = tlen;
}
tptr = (char *)malloc(CompLineLen);
if (CompLine != NULL)
{
strcpy(tptr, CompLine);
free(CompLine);
}
else
{
tptr[0] = '\0';
}
CompLine = tptr;
}
line = CompLine;
strcat(line, spc);
}
/*
* Ok, the space forced a linefeed, but now we must
* also drop the space since we don't want it if we
* have a linefeed here.
*/
else
{
if ((line != NULL)&&(line[0] != '\0'))
{
SetElement(hw, E_TEXT, currentFont,
line_x, *y, line, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = *x - line_x + 1;
AdjustBaseLine();
PF_LF_State = 0;
line[0] = '\0';
}
LineFeed(hw, x, y);
line_x = *x;
all.width = 0;
}
*x = *x + all.width;
if (spc)
free(spc);
NeedSpace = 0;
}
}
if ((line != NULL)&&(line[0] != '\0'))
{
SetElement(hw, E_TEXT, currentFont,
line_x, *y, line, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = *x - line_x + 1;
AdjustBaseLine();
PF_LF_State = 0;
line[0] = '\0';
}
}
TablePlace(hw,mptr,x,y,width)
HTMLWidget hw;
struct mark_up **mptr;
int *x, *y;
unsigned int width;
{
int extra;
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr,"TablePlace(hw,mptr,*x=%d,*y=%d,width = %d)\n", *x,*y,width);
}
#endif
if ((*mptr)->is_end) {
/* end of table */
return;
}
extra = 10;
LineFeed(hw, x, y);
SetElement(hw, E_TABLE, currentFont, *x, *y, (char *) mptr, NULL, NULL, IMAGE_DEFAULT_BORDER);
if (!Current->table_data) {
/* no table */
return;
}
Current->alignment = ALIGN_MIDDLE;
Current->width = Current->table_data->width;
Current->y_offset = Current->table_data->height-extra;
Current->line_height = Current->table_data->height + extra;
BaseLine = Current->table_data->height;
*x += Current->width + 1;
LineFeed(hw, x, y);
}
/*
* Place an image. Add an element record for it.
*/
void
ImagePlace(hw, mptr, x, y, width)
HTMLWidget hw;
struct mark_up *mptr;
int *x, *y;
unsigned int width;
{
char *tptr,*tmpPtr;
char *wTmp,*hTmp;
int border_width;
#ifdef SPACE_HACK
/*
* If we are starting an image in formatted
* text, and it needs a preceeding space, add
* that space now.
*/
if ((!Preformat)&&(NeedSpace > 0))
{
int dir, ascent, descent;
XCharStruct all;
if (NeedSpace == 2)
{
tptr = (char *)malloc(strlen(" ") + 1);
strcpy(tptr, " ");
}
else
{
tptr = (char *)malloc(strlen(" ") + 1);
strcpy(tptr, " ");
}
XTextExtents(currentFont, tptr,
strlen(tptr), &dir, &ascent,
&descent, &all);
SetElement(hw, E_TEXT, currentFont,
*x, *y, tptr, NULL, NULL, IMAGE_DEFAULT_BORDER);
/*
* Save width here to avoid an
* XTextExtents call later.
*/
Current->width = all.width;
AdjustBaseLine();
*x = *x + all.width;
CharsInLine = CharsInLine + strlen(tptr);
if (tptr)
free(tptr);
PF_LF_State = 0;
NeedSpace = 0;
}
#endif /* SPACE_HACK */
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
/**temp******/
if (!tptr) {
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "SRC");
}
/***********/
tmpPtr=tptr;
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "WIDTH");
/**temp******/
if (!tptr) {
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "WIDTH");
}
/***********/
wTmp=tptr;
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "HEIGHT");
/**temp******/
if (!tptr) {
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "HEIGHT");
}
/***********/
hTmp=tptr;
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "BORDER");
/**temp******/
if (!tptr) {
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "BORDER");
}
/***********/
if (!tptr || !*tptr) {
border_width=IMAGE_DEFAULT_BORDER;
}
else if ((border_width=atoi(tptr))<0) {
border_width=0;
}
if (tptr) {
free(tptr);
}
SetElement(hw, E_IMAGE, currentFont, *x, *y, tmpPtr, wTmp, hTmp, border_width);
/*
* Only after we have placed the image do we know its dimensions.
* So now look and see if the image is too wide, and if so go
* back and insert a linebreak.
*/
if ((Current->pic_data != NULL)&&(!Preformat))
{
int extra;
if ((hw->html.border_images == True)||
((Current->anchorHRef != NULL)&&
(!Current->pic_data->internal)))
{
if (Current->pic_data->delayed) {
extra=4;
}
else {
extra = 2*border_width;
}
}
else
{
extra = 0;
}
if (((*x + Current->pic_data->width + extra + MarginW) >width)&&
(Current->prev != NULL)&&
(Current->prev->line_number == LineNumber))
{
Current = Current->prev;
LineFeed(hw, x, y);
SetElement(hw, E_IMAGE, currentFont, *x, *y, tmpPtr, wTmp, hTmp, border_width);
}
}
/*
* Clean up parsed SRC string
*/
if (tmpPtr) {
free(tmpPtr);
}
if (wTmp) {
free(wTmp);
}
if (hTmp) {
free(hTmp);
}
/*
* Yank out the name field, and stick it in text.
* We may use this for ALT to at some later date.
*/
if (Current->pic_data != NULL)
{
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "NAME");
/*temp******/
if (!tptr) {
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "NAME");
}
/*temp******/
Current->pic_data->text = tptr;
}
/*
* Check if this image has the ISMAP attribute, so we know the
* x,y coordinates of the image click are important.
* Due to a special case (see below), this code can acutally
* change the size, or anchor status of the image, thus we MUST
* doit before we muck with the Baseline and stuff.
*/
if (Current->pic_data != NULL)
{
/*
* Handle the USEMAP attribute of IMG tags. This is used for
* client-side image map support.
* --SWP
*/
Current->pic_data->map=NULL;
Current->pic_data->usemap=NULL;
tptr=ParseMarkTag(mptr->start, MT_IMAGE, "USEMAP");
if (tptr!=NULL) {
if (*tptr) {
Current->pic_data->usemap=tptr;
}
else {
free(tptr);
}
}
Current->pic_data->fptr = NULL;
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "ISMAP");
if (tptr != NULL)
{
free(tptr);
Current->pic_data->ismap = 1;
/*
* SUPER SPECIAL CASE! (Thanks Marc)
* If you have an ISMAP image inside a form,
* And that form doesn't already have an HREF
* by being inside an anchor,
* (Being a DelayedHRef is considered no href)
* clicking in that image will submit the form,
* adding the x,y coordinates of the click as part
* of the list of name/value pairs.
*/
if ((CurrentForm != NULL)&&
((Current->anchorHRef == NULL)||
(IsDelayedHRef(hw, Current->anchorHRef))))
{
Current->pic_data->fptr = CurrentForm;
Current->anchorHRef = IsMapForm(hw);
Current->fg = hw->html.anchor_fg;
}
}
else
{
Current->pic_data->ismap = 0;
}
}
/*
* Check if this image will be top aligned
*/
tptr = ParseMarkTag(mptr->start, MT_IMAGE, "ALIGN");
/*temp******/
if (!tptr)
{
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "ALIGN");
}
/*temp******/
if (caseless_equal(tptr, "TOP"))
{
Current->alignment = ALIGN_TOP;
}
else if (caseless_equal(tptr, "MIDDLE"))
{
Current->alignment = ALIGN_MIDDLE;
}
else
{
Current->alignment = ALIGN_BOTTOM;
}
/*
* Clean up parsed ALIGN string
*/
if (tptr != NULL)
{
free(tptr);
}
/*
* Advance x position, and check the max
* line height. We need to follow this
* image with a space.
*/
if (Current->pic_data != NULL)
{
int extra;
if ((hw->html.border_images == True)||
((Current->anchorHRef != NULL)&&
(!Current->pic_data->internal)))
{
if (Current->pic_data->delayed) {
extra=4;
}
else {
extra = 2*border_width;
}
}
else
{
extra = 0;
}
if (BaseLine == -100)
{
BaseLine = 0;
}
*x = *x + Current->pic_data->width + extra;
if (Current->alignment == ALIGN_TOP)
{
Current->y_offset = 0;
if ((Current->pic_data->height + extra - BaseLine) >
LineBottom)
{
LineBottom = Current->pic_data->height + extra -
BaseLine;
}
}
else if (Current->alignment == ALIGN_MIDDLE)
{
int baseline;
baseline = (Current->pic_data->height + extra) / 2;
if (baseline <= BaseLine)
{
Current->y_offset = BaseLine - baseline;
}
else
{
struct ele_rec *eptr;
int line, incy;
Current->y_offset = 0;
incy = baseline - BaseLine;
BaseLine = baseline;
/*
* Go back over this line
* and move everything down
* a little.
*/
eptr = Current;
line = eptr->line_number;
while ((eptr->prev != NULL)&&
(eptr->prev->line_number == line))
{
eptr = eptr->prev;
eptr->y_offset = eptr->y_offset + incy;
}
}
if ((Current->pic_data->height + extra - BaseLine) >
LineBottom)
{
LineBottom = Current->pic_data->height + extra -
BaseLine;
}
}
else if ((Current->pic_data->height + extra) <= BaseLine)
{
Current->y_offset = BaseLine -
(Current->pic_data->height + extra);
}
else if ((Current->pic_data->height + extra) > BaseLine)
{
struct ele_rec *eptr;
int line, incy;
incy = Current->pic_data->height + extra - BaseLine;
BaseLine = Current->pic_data->height + extra;
/*
* Go back over this line
* and move everything down
* a little.
*/
eptr = Current;
line = eptr->line_number;
while ((eptr->prev != NULL)&&
(eptr->prev->line_number == line))
{
eptr = eptr->prev;
eptr->y_offset = eptr->y_offset + incy;
}
}
if (BaseLine == 0)
{
BaseLine = -100;
}
}
PF_LF_State = 0;
NeedSpace = 1;
}
/*
* Place a Widget. Add an element record for it.
*/
void
WidgetPlace(hw, mptr, x, y, width)
HTMLWidget hw;
struct mark_up *mptr;
int *x, *y;
unsigned int width;
{
SetElement(hw, E_WIDGET, currentFont, *x, *y, mptr->start,NULL,NULL,IMAGE_DEFAULT_BORDER);
/*
* Only after we have placed the widget do we know its dimensions.
* So now look and see if the widget is too wide, and if so go
* back and insert a linebreak.
*/
if ((Current->widget_data != NULL)&&(!Preformat))
{
int extra;
extra = 2 * IMAGE_DEFAULT_BORDER;
if (((*x + Current->widget_data->width + extra + MarginW) >
width)&&
(Current->prev != NULL)&&
(Current->prev->line_number == LineNumber))
{
WidgetId--;
Current = Current->prev;
LineFeed(hw, x, y);
SetElement(hw, E_WIDGET, currentFont, *x, *y,
mptr->start,NULL,NULL,IMAGE_DEFAULT_BORDER);
}
}
/*
* Advance x position, and check BaseLine and LineBottom.
* We need to follow this widget with a space.
*/
if (Current->widget_data != NULL)
{
int extra;
int baseline;
XFontStruct *fp;
extra = 2 * IMAGE_DEFAULT_BORDER;
/*
* Find the font used in this widget. Then find its baseline
*/
fp = GetWidgetFont(hw, Current->widget_data);
if (fp == NULL)
{
baseline = Current->widget_data->height + extra;
}
/*
* If no font, the baseline is the bottum of the widget
*/
else
{
int border;
border = ((Current->widget_data->height + extra) -
(fp->max_bounds.ascent + fp->max_bounds.descent));
baseline = (border / 2) + fp->max_bounds.ascent;
}
/*
* Baseline == -100 is the special unset baseline value.
*/
if (BaseLine == -100)
{
BaseLine = baseline;
Current->y_offset = 0;
/*
* If linebottom isn't set, set it to
* whatever of the height is below the baseline.
*/
if (LineBottom == 0)
{
LineBottom = Current->widget_data->height +
extra - baseline;
}
/*
* Else, it is possible that a linebottom has been
* set even when we have no baseline yet (like if
* the first item in the line was a top aligned image)
* It now needs to be corrected as we set a real
* BaseLine.
*/
else
{
if ((Current->widget_data->height +
extra - baseline) >
(LineBottom - baseline))
{
LineBottom =
Current->widget_data->height +
extra - baseline;
}
else
{
LineBottom = LineBottom - baseline;
}
}
}
/*
* Else we already have a baseline, and it is greater that
* the baseline for this widget.
* Set y_offset, and check linebottom.
*/
else if (baseline <= BaseLine)
{
if (baseline < BaseLine)
{
Current->y_offset = BaseLine - baseline;
}
else
{
Current->y_offset = 0;
}
/*
* Our line bottom may be greater than the
* old one.
*/
if ((Current->widget_data->height + extra - baseline) >
LineBottom)
{
LineBottom = Current->widget_data->height +
extra - baseline;
}
}
else
/*
* Else we have a new baseline greater than the old baseline.
*/
{
struct ele_rec *eptr;
int line, incy;
/*
* Figure out how much to move all the old stuff
*/
incy = baseline - BaseLine;
BaseLine = baseline;
/*
* Go back over this line
* and move everything down
* a little.
*/
eptr = Current;
line = eptr->line_number;
while ((eptr->prev != NULL)&&
(eptr->prev->line_number == line))
{
eptr = eptr->prev;
eptr->y_offset = eptr->y_offset + incy;
}
/*
* Our line bottom may be greater than the
* old one.
*/
if ((Current->widget_data->height + extra - baseline) >
LineBottom)
{
LineBottom = Current->widget_data->height +
extra - baseline;
}
}
/*
* Advance the X position.
*/
*x = *x + Current->widget_data->width + extra;
}
PF_LF_State = 0;
NeedSpace = 1;
}
static void
PushFont(font)
XFontStruct *font;
{
FontRec *fptr;
fptr = (FontRec *)malloc(sizeof(FontRec));
if (fptr == NULL)
{
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "No memory to expand font stack!\n");
}
#endif
return;
}
fptr->font = font;
fptr->next = FontStack;
FontStack = fptr;
}
static XFontStruct *
PopFont()
{
XFontStruct *font;
FontRec *fptr;
if (FontStack->next != NULL)
{
fptr = FontStack;
FontStack = FontStack->next;
font = fptr->font;
free((char *)fptr);
}
else
{
#ifndef DISABLE_TRACE
if (htmlwTrace) {
fprintf(stderr, "Warning, popping empty font stack!\n");
}
#endif
font = FontStack->font;
}
return(font);
}
/*
* We've just terminated the current OPTION.
* Put it in the proper place in the SelectInfo structure.
* Move option_buf into options, and maybe copy into
* value if is_value is set.
*/
static void
ProcessOption(sptr)
SelectInfo *sptr;
{
int i, cnt;
char **tarray;
clean_white_space(sptr->option_buf);
tarray = sptr->options;
cnt = sptr->option_cnt + 1;
sptr->options = (char **)malloc(sizeof(char *) * cnt);
for (i=0; i<(cnt - 1); i++)
{
sptr->options[i] = tarray[i];
}
if (tarray != NULL)
{
free((char *)tarray);
}
sptr->options[cnt - 1] = sptr->option_buf;
sptr->option_cnt = cnt;
tarray = sptr->returns;
cnt = sptr->option_cnt;
sptr->returns = (char **)malloc(sizeof(char *) * cnt);
for (i=0; i<(cnt - 1); i++)
{
sptr->returns[i] = tarray[i];
}
if (tarray != NULL)
{
free((char *)tarray);
}
sptr->returns[cnt - 1] = sptr->retval_buf;
if (sptr->is_value)
{
tarray = sptr->value;
cnt = sptr->value_cnt + 1;
sptr->value = (char **)malloc(sizeof(char *) * cnt);
for (i=0; i<(cnt - 1); i++)
{
sptr->value[i] = tarray[i];
}
if (tarray != NULL)
{
free((char *)tarray);
}
sptr->value[cnt - 1] = (char *)malloc(
strlen(sptr->option_buf) + 1);
strcpy(sptr->value[cnt - 1], sptr->option_buf);
sptr->value_cnt = cnt;
}
}
/*
* Horrible code for the TEXTAREA element. Escape '\' and ''' by
* putting a '\' in front of them, then replace all '"' with '''.
* This lets us safely put the resultant value between double quotes.
*/
char *
TextAreaAddValue(value, text)
char *value;
char *text;
{
int extra;
char *buf;
char *bptr;
char *tptr;
if ((text == NULL)||(text[0] == '\0'))
{
return(value);
}
extra = 0;
tptr = text;
while (*tptr != '\0')
{
if (*tptr == '\\')
{
extra++;
}
else if (*tptr == '\'')
{
extra++;
}
tptr++;
}
buf = (char *)malloc(strlen(value) + strlen(text) + extra + 1);
if (buf == NULL)
{
return(value);
}
strcpy(buf, value);
tptr = text;
bptr = (char *)(buf + strlen(value));
while (*tptr != '\0')
{
if ((*tptr == '\\')||(*tptr == '\''))
{
*bptr++ = '\\';
*bptr++ = *tptr++;
}
else if (*tptr == '\"')
{
*bptr++ = '\'';
tptr++;
}
else
{
*bptr++ = *tptr++;
}
}
*bptr = '\0';
free(value);
return(buf);
}
/*
* Make necessary changes to formatting, based on the type of the
* parsed HTML text we are formatting.
* Some calls create elements that are added to the formatted element list.
*/
static
void
TriggerMarkChanges(hw, mptr, x, y)
HTMLWidget hw;
struct mark_up **mptr;
int *x, *y;
{
struct mark_up *mark;
XFontStruct *font;
int type, width, curCoord;
char *tptr,*cptr,*endptr;
mark = *mptr;
type = mark->type;
font = NULL;
/* If we are not in a tag that belongs in the HEAD, end the HEAD
section - amb */
if (InDocHead)
if ((type != M_TITLE)&&(type != M_NONE)&&(type != M_BASE)&&
(type != M_INDEX)&&(type != M_COMMENT))
{
Ignore = 0;
InDocHead = 0;
}
/*
* If Ignore is set, we ignore all further elements until we get to the
* end of the Ignore
* Let text through so we can grab the title text.
* Let title through so we can hit the end title.
* Now also used for SELECT parseing
* Let SELECT through so we can hit the end SELECT.
* Let OPTION through so we can hit the OPTIONs.
* Let TEXTAREA through so we can hit the TEXTAREAs.
*/
if ((Ignore)&&(!InDocHead)&&(type != M_TITLE)&&(type != M_NONE)&&(type != M_COMMENT)&&
(type != M_SELECT)&&(type != M_OPTION)&&
(type != M_TEXTAREA)&&(type != M_DOC_HEAD))
{
return;
}
switch(type)
{
/*
* Place the text. Different functions based on whether it
* is pre-formatted or not.
*/
case M_NONE:
if ((Ignore)&&(CurrentSelect == NULL)&&
(TextAreaBuf == NULL))
{
if (TitleText == NULL)
{
TitleText = (char *)
malloc(strlen((*mptr)->text) + 1);
strcpy(TitleText, (*mptr)->text);
}
else
{
char *tptr;
tptr = (char *)
malloc(strlen(TitleText) +
strlen((*mptr)->text) + 1);
strcpy(tptr, TitleText);
strcat(tptr, (*mptr)->text);
free(TitleText);
TitleText = tptr;
}
}
else if ((Ignore)&&(CurrentSelect != NULL))
{
if (CurrentSelect->option_buf != NULL)
{
char *tptr;
tptr = (char *)malloc(strlen(
CurrentSelect->option_buf) +
strlen((*mptr)->text) + 1);
strcpy(tptr, CurrentSelect->option_buf);
strcat(tptr, (*mptr)->text);
free(CurrentSelect->option_buf);
CurrentSelect->option_buf = tptr;
}
}
else if ((Ignore)&&(TextAreaBuf != NULL))
{
TextAreaBuf = TextAreaAddValue(TextAreaBuf,
(*mptr)->text);
}
else if (Preformat)
{
PreformatPlace(hw, *mptr, x, y, Width);
}
else
{
FormatPlace(hw, *mptr, x, y, Width);
}
break;
/*
* Titles are just set into the widget for retrieval by
* XtGetValues().
*/
case M_TITLE:
if (mark->is_end)
{
if (!InDocHead)
Ignore = 0;
hw->html.title = TitleText;
TitleText = NULL;
}
else
{
Ignore = 1;
TitleText = NULL;
}
break;
/*
* Formatting commands just change the current font.
*/
case M_CODE:
case M_SAMPLE:
case M_KEYBOARD:
case M_FIXED:
if (mark->is_end)
{
font = PopFont();
}
else
{
PushFont(currentFont);
font = hw->html.fixed_font;
}
break;
case M_STRONG:
case M_BOLD:
if (mark->is_end)
{
font = PopFont();
}
else
{
PushFont(currentFont);
if (currentFont == hw->html.fixed_font ||
currentFont == hw->html.fixeditalic_font)
font = hw->html.fixedbold_font;
else if (currentFont == hw->html.plain_font ||
currentFont == hw->html.plainitalic_font)
font = hw->html.plainbold_font;
else
font = hw->html.bold_font;
}
break;
case M_EMPHASIZED:
case M_VARIABLE:
case M_CITATION:
case M_ITALIC:
if (mark->is_end)
{
font = PopFont();
}
else
{
PushFont(currentFont);
if (currentFont == hw->html.fixed_font ||
currentFont == hw->html.fixedbold_font)
font = hw->html.fixeditalic_font;
else if (currentFont == hw->html.plain_font ||
currentFont == hw->html.plainbold_font)
font = hw->html.plainitalic_font;
else
font = hw->html.italic_font;
}
break;
/*
* Strikeout means draw a line through the text.
* Right now we just set a boolean flag which gets shoved
* in the element record for all elements in the
* strikeout zone.
*/
case M_STRIKEOUT:
if (mark->is_end)
{
Strikeout = False;
}
else
{
Strikeout = True;
}
break;
case M_SUP:
if (mark->is_end)
{
Superscript--;
if ((Superscript==0) && (Subscript==0))
font = PopFont();
}
else
{
Superscript++;
if ((Superscript==1) && (Subscript==0))
{
nonScriptFont=currentFont;
PushFont(currentFont);
font = hw->html.supsub_font;
}
}
break;
case M_SUB:
if (mark->is_end)
{
Subscript--;
if ((Subscript==0) && (Superscript==0))
font = PopFont();
}
else
{
Subscript++;
if ((Subscript==1) && (Superscript==0))
{
nonScriptFont=currentFont;
PushFont(currentFont);
font = hw->html.supsub_font;
}
}
break;
case M_CENTER:
if (mark->is_end)
Centered = 0;
else
Centered = 1;
break;
/* amb - ignore text inside a HEAD element */
case M_DOC_HEAD:
if (mark->is_end)
{
InDocHead = 0;
Ignore = 0;
}
else
{
InDocHead = 1;
Ignore = 1;
}
break;
case M_DOC_BODY:
if (mark->is_end)
{
/* do nothing */
}
else
{
InDocHead = 0; /* end <head> section */
Ignore = 0;
}
break;
case M_UNDERLINED:
if (mark->is_end)
{
Underlines = 0;
InUnderlined = 0;
}
else
{
Underlines = 1;
InUnderlined = 1;
}
break;
/*
* Headers are preceeded and followed by a linefeed,
* and the change the font.
*/
case M_HEADER_1:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header1_font;
}
break;
case M_HEADER_2:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header2_font;
}
break;
case M_HEADER_3:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header3_font;
}
break;
case M_HEADER_4:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header4_font;
}
break;
case M_HEADER_5:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header5_font;
}
break;
case M_HEADER_6:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 2);
PushFont(currentFont);
font = hw->html.header6_font;
}
break;
case M_FRAME:
break;
/*
* Anchors change the text color, and may set
* underlineing attributes.
* No linefeeds, so they can be imbedded anywhere.
*/
case M_ANCHOR:
if (mark->is_end)
{
/*
* Without motif we use our own foreground resource instead of
* using the manager's
*/
#ifdef MOTIF
Fg = hw->manager.foreground;
#else
Fg = hw->html.foreground;
#endif /* MOTIF */
if (!InUnderlined) /* amb 2 */
Underlines = 0;
else
Underlines = 1;
DashedUnderlines = False;
AnchorText = NULL;
}
else
{
char *tptr;
/*
* Only change the color of anchors with
* HREF tags, because other anchors are
* not active.
*/
tptr = ParseMarkTag(mark->start,
MT_ANCHOR, AT_HREF);
if (tptr != NULL)
{
/*
* If internal check our internal list
* to change color if visited before.
*/
if (Internal == True)
{
struct ref_rec *hptr;
hptr = FindHRef(
hw->html.my_visited_hrefs,
tptr);
if (hptr != NULL)
{
Fg = hw->html.visitedAnchor_fg;
Underlines = hw->html.num_visitedAnchor_underlines;
DashedUnderlines = hw->html.dashed_visitedAnchor_lines;
}
else
{
Fg = hw->html.anchor_fg;
Underlines = hw->html.num_anchor_underlines;
DashedUnderlines = hw->html.dashed_anchor_lines;
}
}
/*
* Else we may want to send
* the href back somewhere else and
* find out if we've visited it before
*/
else if (hw->html.previously_visited_test !=
NULL)
{
if ((*(visitTestProc)
(hw->html.previously_visited_test))
(hw, tptr))
{
Fg = hw->html.visitedAnchor_fg;
Underlines = hw->html.num_visitedAnchor_underlines;
DashedUnderlines = hw->html.dashed_visitedAnchor_lines;
}
else
{
Fg = hw->html.anchor_fg;
Underlines = hw->html.num_anchor_underlines;
DashedUnderlines = hw->html.dashed_anchor_lines;
}
}
else
{
Fg = hw->html.anchor_fg;
Underlines = hw->html.num_anchor_underlines;
DashedUnderlines = hw->html.dashed_anchor_lines;
}
if (tptr)
free(tptr);
}
AnchorText = mark->start;
/* amb 2 */
if (InUnderlined)
{
DashedUnderlines = False;
if (!Underlines)
Underlines = 1;
}
}
break;
/*
* Just insert a linefeed, or ignore if this is prefomatted
* text because the <P> will be followed be a linefeed.
*/
case M_PARAGRAPH:
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
break;
/*
* Just insert the image for now
*/
case M_FIGURE:
case M_IMAGE:
if (mark->is_end)
{
/* do nothing */
}
else
{
ImagePlace(hw, *mptr, x, y, Width);
}
break;
/*
* Can only be inside a SELECT tag.
*/
case M_OPTION:
if (CurrentSelect != NULL)
{
char *tptr;
if (CurrentSelect->option_buf != NULL)
{
ProcessOption(CurrentSelect);
}
CurrentSelect->option_buf = (char *)malloc(1);
strcpy(CurrentSelect->option_buf, "");
/*
* Check if this option starts selected
*/
tptr = ParseMarkTag(mark->start,
MT_OPTION, "SELECTED");
if (tptr != NULL)
{
CurrentSelect->is_value = 1;
free(tptr);
}
else
{
CurrentSelect->is_value = 0;
}
/*
* Check if this option has an different
* return value field.
*/
tptr = ParseMarkTag(mark->start,
MT_OPTION, "VALUE");
if (tptr != NULL)
{
if (*tptr != '\0')
{
CurrentSelect->retval_buf = tptr;
}
else
{
CurrentSelect->retval_buf = NULL;
free(tptr);
}
}
else
{
CurrentSelect->retval_buf = NULL;
}
}
break;
/*
* Special INPUT tag. Allows an option menu or
* a scrolled list.
* Due to a restriction in SGML, this can't just be a
* subset of the INPUT markup. However, I can treat it
* that way to avoid duplicating code.
* As a result I combine SELECT and OPTION into a faked
* up INPUT mark.
*/
case M_SELECT:
if (CurrentForm != NULL)
{
if ((mark->is_end)&&(CurrentSelect != NULL))
{
int len;
char *buf;
char *start;
char *options, *returns, *value;
if (CurrentSelect->option_buf != NULL)
{
ProcessOption(CurrentSelect);
}
options = ComposeCommaList(
CurrentSelect->options,
CurrentSelect->option_cnt);
returns = ComposeCommaList(
CurrentSelect->returns,
CurrentSelect->option_cnt);
value = ComposeCommaList(
CurrentSelect->value,
CurrentSelect->value_cnt);
FreeCommaList(
CurrentSelect->options,
CurrentSelect->option_cnt);
FreeCommaList(
CurrentSelect->returns,
CurrentSelect->option_cnt);
FreeCommaList(
CurrentSelect->value,
CurrentSelect->value_cnt);
/*
* Construct a fake INPUT tag.
*/
len = strlen(MT_INPUT) +
strlen(options) +
strlen(returns) +
strlen(value) + strlen(
" type=select options=\"\" returns=\"\" value=\"\"");
buf = (char *)malloc(len +
strlen(CurrentSelect->mptr->start)
+ 1);
strcpy(buf, MT_INPUT);
strcat(buf, " type=select");
strcat(buf, " options=\"");
strcat(buf, options);
strcat(buf, "\" returns=\"");
strcat(buf, returns);
strcat(buf, "\" value=\"");
strcat(buf, value);
strcat(buf, "\"");
strcat(buf, (char *)
(CurrentSelect->mptr->start +
strlen(MT_SELECT)));
/*
* stick the fake in, saving the
* real one.
*/
start = CurrentSelect->mptr->start;
CurrentSelect->mptr->start = buf;
WidgetPlace(hw, CurrentSelect->mptr,
x, y, Width);
/*
* free the fake, put the original back
*/
free(buf);
free(options);
free(returns);
free(value);
CurrentSelect->mptr->start = start;
free((char *)CurrentSelect);
CurrentSelect = NULL;
Ignore = 0;
}
else if ((!mark->is_end)&&(CurrentSelect == NULL))
{
CurrentSelect = (SelectInfo *)malloc(
sizeof(SelectInfo));
CurrentSelect->hw = (Widget)hw;
CurrentSelect->mptr = *mptr;
CurrentSelect->option_cnt = 0;
CurrentSelect->returns = NULL;
CurrentSelect->retval_buf = NULL;
CurrentSelect->options = NULL;
CurrentSelect->option_buf = NULL;
CurrentSelect->value_cnt = 0;
CurrentSelect->value = NULL;
CurrentSelect->is_value = -1;
Ignore = 1;
}
}
break;
/*
* TEXTAREA is a replacement for INPUT type=text size=rows,cols
* because SGML will not allow an arbitrary length value
* field.
*/
case M_TEXTAREA:
if (CurrentForm != NULL)
{
if ((mark->is_end)&&(TextAreaBuf != NULL))
{
char *start;
char *buf;
/*
* Finish a fake INPUT tag.
*/
buf = (char *)malloc(
strlen(TextAreaBuf) + 2);
strcpy(buf, TextAreaBuf);
strcat(buf, "\"");
/*
* stick the fake in, saving the
* real one.
*/
start = mark->start;
mark->start = buf;
mark->is_end = 0;
WidgetPlace(hw, mark, x, y, Width);
/*
* free the fake, put the original back
*/
free(buf);
free(TextAreaBuf);
mark->start = start;
mark->is_end = 1;
TextAreaBuf = NULL;
Ignore = 0;
}
else if ((!mark->is_end)&&(TextAreaBuf == NULL))
{
char *buf;
int len;
/*
* Construct the start of
* a fake INPUT tag.
*/
len = strlen(MT_INPUT) +
strlen(
" type=textarea value=\"\"");
buf = (char *)malloc(len +
strlen(mark->start)
+ 1);
strcpy(buf, MT_INPUT);
strcat(buf, (char *)
(mark->start +
strlen(MT_TEXTAREA)));
strcat(buf, " type=textarea");
strcat(buf, " value=\"");
TextAreaBuf = buf;
Ignore = 1;
}
}
break;
/*
* Just insert the widget.
* Can only inside a FORM tag.
* Special case the type=image stuff to become a special
* IMG tag.
*/
case M_INPUT:
if (CurrentForm != NULL)
{
char *tptr;
char *tptr2;
tptr = ParseMarkTag((*mptr)->start,
MT_INPUT, "TYPE");
if ((tptr != NULL)&&
(caseless_equal(tptr, "image")))
{
free(tptr);
tptr = (char *)malloc(
strlen((*mptr)->start) +
strlen(" ISMAP") +
strlen(MT_IMAGE) -
strlen(MT_INPUT) + 1);
strcpy(tptr, MT_IMAGE);
strcat(tptr, (char *)
((*mptr)->start + strlen(MT_INPUT))
);
strcat(tptr, " ISMAP");
tptr2 = (*mptr)->start;
(*mptr)->start = tptr;
ImagePlace(hw, *mptr, x, y, Width);
(*mptr)->start = tptr2;
free(tptr);
}
/*
* hidden inputs have no element associated
* with them, just a widget record.
*/
else if ((tptr != NULL)&&
(caseless_equal(tptr, "hidden")))
{
free(tptr);
WidgetId++;
(void)MakeWidget(hw, (*mptr)->start, x, y,
WidgetId, CurrentForm);
}
else
{
if (tptr != NULL)
{
free(tptr);
}
WidgetPlace(hw, *mptr, x, y, Width);
}
}
break;
/*
* Fillout forms. Cannot be nested.
*/
case M_FORM:
ConditionalLineFeed(hw, x, y, 1);
if ((mark->is_end)&&(CurrentForm != NULL))
{
CurrentForm->end = WidgetId;
ConditionalLineFeed(hw, x, y, 2);
AddNewForm(hw, CurrentForm);
CurrentForm = NULL;
}
else if ((!mark->is_end)&&(CurrentForm == NULL))
{
ConditionalLineFeed(hw, x, y, 2);
CurrentForm = (FormInfo *)malloc(
sizeof(FormInfo));
CurrentForm->next = NULL;
CurrentForm->hw = (Widget)hw;
CurrentForm->action = ParseMarkTag(mark->start,
MT_FORM, "ACTION");
CurrentForm->format = ParseMarkTag(mark->start,
MT_FORM, "FORMAT");
CurrentForm->method = ParseMarkTag(mark->start,
MT_FORM, "METHOD");
CurrentForm->enctype = ParseMarkTag(mark->start,
MT_FORM, "ENCTYPE");
CurrentForm->enc_entity = ParseMarkTag(
mark->start, MT_FORM, "ENCENTITY");
CurrentForm->start = WidgetId;
CurrentForm->end = -1;
CurrentForm->button_pressed=NULL;
}
break;
/*
* Addresses are just like headers. A linefeed before and
* after, and change the font.
*/
case M_ADDRESS:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
font = PopFont();
}
else
{
PushFont(currentFont);
font = hw->html.address_font;
}
break;
/*
* Blockquotes increase the margin width.
* They cannot be nested.
*/
case M_BLOCKQUOTE:
ConditionalLineFeed(hw, x, y, 1);
if (mark->is_end)
{
MarginW = hw->html.margin_width;
/*
* Only unindent if we think we indented
* when we started the blockquote
*/
if (TextIndent <= (2 * MarginW))
{
TextIndent = MarginW;
}
ConditionalLineFeed(hw, x, y, 2);
/*
* The linefeed should have set x to TextIndent
* but since it is conditional, it might not
* have, so check it here.
*/
if (*x > TextIndent)
{
*x = TextIndent;
}
}
else
{
MarginW = 2 * hw->html.margin_width;
/*
* Only indent if the current indent
* is less than what we want.
*/
if (TextIndent < MarginW)
{
TextIndent = MarginW;
}
ConditionalLineFeed(hw, x, y, 2);
/*
* The linefeed should have set x to TextIndent
* but since it is conditional, it might not
* have, so check it here.
*/
if (*x < TextIndent)
{
*x = TextIndent;
}
}
break;
/*
* Plain text. A single pre-formatted chunk of text
* in its own font.
*/
case M_PLAIN_TEXT:
if (mark->is_end)
{
Preformat = 0;
/*
* Properly convert the Linefeed state
* variable from preformat to formatted
* state.
*/
if (PF_LF_State == 2)
{
PF_LF_State = 1;
}
else
{
PF_LF_State = 0;
}
ConditionalLineFeed(hw, x, y, 1);
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
Preformat = 1;
PF_LF_State = 0;
PushFont(currentFont);
font = hw->html.plain_font;
}
break;
/*
* Listing text. A different pre-formatted chunk of text
* in its own font.
*/
case M_LISTING_TEXT:
if (mark->is_end)
{
Preformat = 0;
/*
* Properly convert the Linefeed state
* variable from preformat to formatted
* state.
*/
if (PF_LF_State == 2)
{
PF_LF_State = 1;
}
else
{
PF_LF_State = 0;
}
ConditionalLineFeed(hw, x, y, 1);
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
Preformat = 1;
PF_LF_State = 0;
PushFont(currentFont);
font = hw->html.listing_font;
}
break;
/*
* Plain text. The rest of the text is pre-formatted.
* There is not end for this mark.
*/
case M_PLAIN_FILE:
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
Preformat = 1;
PF_LF_State = 0;
PushFont(currentFont);
font = hw->html.plain_font;
break;
/*
* Numbered lists, Unnumbered lists, Menus.
* Currently also lump directory listings into this.
* Save state for each indent level.
* Change the value of the TxtIndent (can be nested)
* Linefeed at the end of the list.
*/
case M_NUM_LIST:
case M_UNUM_LIST:
case M_MENU:
case M_DIRECTORY:
ConditionalLineFeed(hw, x, y, 1);
width = hw->html.font->max_bounds.width;
/*
* If this is the outermost level of indentation,
* add another linefeed for more white space.
*/
if ((TextIndent <= MarginW)||((mark->is_end)&&
((TextIndent - ((INDENT_SPACES + 1) * width)) <=
MarginW)))
{
ConditionalLineFeed(hw, x, y, 2);
}
if (mark->is_end)
{
TextIndent = TextIndent -
((INDENT_SPACES + 1) * width);
if (TextIndent < MarginW)
{
TextIndent = MarginW;
}
IndentLevel--;
if (IndentLevel < 0)
{
IndentLevel = 0;
}
/*
* restore the old state if there is one
*/
if (ListData->next != NULL)
{
DescRec *dptr;
dptr = ListData;
ListData = ListData->next;
free((char *)dptr);
}
}
else
{
DescRec *dptr;
dptr = (DescRec *)malloc(sizeof(DescRec));
/*
* Save the old state, and start a new
*/
if (type == M_NUM_LIST)
{
dptr->type = D_OLIST;
dptr->count = 1;
}
else
{
dptr->type = D_ULIST;
dptr->count = 0;
}
dptr->next = ListData;
ListData = dptr;
TextIndent = TextIndent +
((INDENT_SPACES + 1) * width);
IndentLevel++;
}
*x = TextIndent;
break;
/*
* Place the bullet element at the beginning of this item.
*/
case M_LIST_ITEM:
if (!mark->is_end)
{
ConditionalLineFeed(hw, x, y, 1);
/*
* for ordered/numbered lists
* put numbers in place of bullets.
*/
if (ListData->type == D_OLIST)
{
ListNumberPlace(hw, x, y,
ListData->count);
ListData->count++;
}
else
{
BulletPlace(hw, x, y);
}
}
break;
/*
* Description lists
*/
case M_DESC_LIST:
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
width = hw->html.font->max_bounds.width;
if (mark->is_end)
{
if (DescType->type == D_TEXT)
{
TextIndent = TextIndent -
((INDENT_SPACES + 1) * width);
if (TextIndent < MarginW)
{
TextIndent = MarginW;
}
}
/*
* restore the old state if there is one
*/
if (DescType->next != NULL)
{
DescRec *dptr;
dptr = DescType;
DescType = DescType->next;
free((char *)dptr);
/*
* If the old state had forced an
* indent, outdent it now.
*/
if (DescType->type == D_TITLE)
{
TextIndent = TextIndent -
((INDENT_SPACES + 1) * width);
if (TextIndent < MarginW)
{
TextIndent = MarginW;
}
}
}
}
else
{
DescRec *dptr;
char *tptr;
dptr = (DescRec *)malloc(sizeof(DescRec));
/*
* Check is this is a compact list
*/
tptr = ParseMarkTag(mark->start,
MT_DESC_LIST, "COMPACT");
if (tptr != NULL)
{
free(tptr);
dptr->compact = 1;
}
else
{
dptr->compact = 0;
}
/*
* Description list stared after a title needs
* a forced indentation here
*/
if (DescType->type == D_TITLE)
{
TextIndent = TextIndent +
((INDENT_SPACES + 1) * width);
}
/*
* Save the old state, and start a new
*/
dptr->type = D_TITLE;
dptr->next = DescType;
DescType = dptr;
}
*x = TextIndent;
break;
case M_DESC_TITLE:
ConditionalLineFeed(hw, x, y, 1);
width = hw->html.font->max_bounds.width;
/*
* Special hack. Don't indent again for
* multiple <dt>'s in a row.
*/
if (DescType->type == D_TEXT)
{
TextIndent = TextIndent -
((INDENT_SPACES + 1) * width);
if (TextIndent < MarginW)
{
TextIndent = MarginW;
}
}
DescType->type = D_TITLE;
*x = TextIndent;
break;
case M_DESC_TEXT:
width = hw->html.font->max_bounds.width;
/*
* For a compact list we want to stay on the same
* line if there is room and we are the first line
* after a title.
*/
if ((DescType->compact)&&(DescType->type == D_TITLE)&&
(*x < (TextIndent + (INDENT_SPACES * width))))
{
NeedSpace = 0;
}
else
{
ConditionalLineFeed(hw, x, y, 1);
}
/*
* Special hack. Don't indent again for
* multiple <dd>'s in a row.
*/
if (DescType->type == D_TITLE)
{
TextIndent = TextIndent +
((INDENT_SPACES + 1) * width);
}
DescType->type = D_TEXT;
*x = TextIndent;
break;
case M_PREFORMAT:
if (mark->is_end)
{
Preformat = 0;
/*
* Properly convert the Linefeed state
* variable from preformat to formatted
* state.
*/
if (PF_LF_State == 2)
{
PF_LF_State = 1;
}
else
{
PF_LF_State = 0;
}
ConditionalLineFeed(hw, x, y, 1);
if (saveFont != NULL)
{
hw->html.font = saveFont;
saveFont = NULL;
}
font = PopFont();
NewFont(font);
currentFont = font;
ConditionalLineFeed(hw, x, y, 2);
}
else
{
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
Preformat = 1;
PF_LF_State = 2;
if (saveFont == NULL)
{
saveFont = hw->html.font;
hw->html.font = hw->html.plain_font;
}
PushFont(currentFont);
font = hw->html.font;
}
break;
/*
* Now with forms, <INDEX> is the same as:
* <FORM>
* <HR>
* This is a searchable index. Enter search keywords:
* <INPUT NAME="isindex">
* <HR>
* </FORM>
* Also, <INDEX> will take an ACTION tag to specify a
* different URL to submit the query to.
*/
case M_INDEX:
hw->html.is_index = True;
/*
* No index inside a form
*/
if (CurrentForm == NULL)
{
struct mark_up mark_tmp;
/*
* Start the form
*/
ConditionalLineFeed(hw, x, y, 1);
ConditionalLineFeed(hw, x, y, 2);
CurrentForm = (FormInfo *)malloc(
sizeof(FormInfo));
CurrentForm->next = NULL;
CurrentForm->hw = (Widget)hw;
CurrentForm->action = NULL;
CurrentForm->action = ParseMarkTag(mark->start,
MT_INDEX, "ACTION");
CurrentForm->format = ParseMarkTag(mark->start,
MT_INDEX, "FORMAT");
CurrentForm->method = ParseMarkTag(mark->start,
MT_INDEX, "METHOD");
CurrentForm->enctype = ParseMarkTag(mark->start,
MT_INDEX, "ENCTYPE");
CurrentForm->enc_entity = ParseMarkTag(
mark->start, MT_INDEX, "ENCENTITY");
CurrentForm->start = WidgetId;
CurrentForm->end = -1;
/*
* Horizontal rule
*/
ConditionalLineFeed(hw, x, y, 1);
HRulePlace(hw, x, y, Width);
ConditionalLineFeed(hw, x, y, 1);
/*
* Text: "This is a searchable index.
* Enter search keywords: "
*/
mark_tmp.text = (char *)malloc(
strlen("This is a searchable index. Enter search keywords: ") + 1);
strcpy(mark_tmp.text,"This is a searchable index. Enter search keywords: ");
FormatPlace(hw, &mark_tmp, x, y, Width);
/*
* Fake up the text INPUT tag.
*/
mark_tmp.start = (char *)malloc(
strlen("input SIZE=25 NAME=\"isindex\"") + 1);
strcpy(mark_tmp.start,"input SIZE=25 NAME=\"isindex\"");
WidgetPlace(hw, &mark_tmp, x, y, Width);
#ifdef ISINDEX_SUBMIT
/*
* Text: ";<CR> press this button to submit
* the query: "
*/
mark_tmp.text = (char *)malloc(
strlen(";\n press this button to submit the query: ") + 1);
strcpy(mark_tmp.text,";\n press this button to submit the query: ");
FormatPlace(hw, &mark_tmp, x, y, Width);
/*
* Fake up the submit INPUT tag.
*/
mark_tmp.start = (char *)malloc(
strlen("input TYPE=\"submit\"") + 1);
strcpy(mark_tmp.start, "input TYPE=\"submit\"");
WidgetPlace(hw, &mark_tmp, x, y, Width);
/*
* Text: ".<CR>"
*/
mark_tmp.text = (char *)malloc(
strlen(".\n") + 1);
strcpy(mark_tmp.text, ".\n");
FormatPlace(hw, &mark_tmp, x, y, Width);
#endif /* ISINDEX_SUBMIT */
/*
* Horizontal rule
*/
ConditionalLineFeed(hw, x, y, 1);
HRulePlace(hw, x, y, Width);
ConditionalLineFeed(hw, x, y, 1);
/*
* Close the form
*/
ConditionalLineFeed(hw, x, y, 1);
CurrentForm->end = WidgetId;
ConditionalLineFeed(hw, x, y, 2);
AddNewForm(hw, CurrentForm);
CurrentForm = NULL;
}
break;
case M_HRULE:
ConditionalLineFeed(hw, x, y, 1);
HRulePlace(hw, x, y, Width);
ConditionalLineFeed(hw, x, y, 1);
break;
case M_LINEBREAK:
LineFeed(hw, x, y);
break;
case M_TABLE:
if (tableSupportEnabled) {
TablePlace(hw, mptr, x, y, Width);
}
break;
case M_COMMENT:
Ignore = !mark->is_end;
break;
default:
break;
}
if ((font != NULL)&&(font != currentFont))
{
NewFont(font);
currentFont = font;
}
} /* TriggerMarkChanges() */
/*
* Format all the objects in the passed Widget's
* parsed object list to fit the locally global Width.
* Passes in the x,y coords of where to start placing the
* formatted text.
* Returns the ending x,y in same variables.
* Title objects are ignored, and not formatted.
*
* The locally global variables are assumed to have been initialized
* before this function was called.
*/
void
FormatChunk(hw, x, y)
HTMLWidget hw;
int *x, *y;
{
struct mark_up *mptr;
/*
* Format all objects
*/
mptr = hw->html.html_objects;
Last = NULL;
while (mptr != NULL)
{
TriggerMarkChanges(hw, &mptr, x, y);
/*
* Save last non-text mark
*/
/* DDT: why is this here? it's not used anywhere? */
if (mptr->type != M_NONE)
{
Last = mptr;
}
/*****/
if (mptr) {
mptr = mptr->next;
}
}
}
/*
* Called by the widget to format all the objects in the
* parsed object list to fit its current window size.
* Returns the max_height of the entire document.
* Title objects are ignored, and not formatted.
*/
int
FormatAll(hw, Fwidth)
HTMLWidget hw;
int *Fwidth;
{
int x, y;
int width;
struct mark_up *msave;
#ifndef DISABLE_TRACE
if (htmlwTrace) {
#ifndef VMS
gettimeofday(&Tv, &Tz);
fprintf(stderr, "FormatAll enter (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
#else
fprintf(stderr, "FormatAll enter (%s)\n", asctime(localtime(&clock)));
#endif
}
#endif
width = *Fwidth;
MaxWidth = width;
/*
* Clear the is_index flag
*/
hw->html.is_index = False;
/*
* Initialize local variables, some from the widget
*/
MarginW = hw->html.margin_width;
/*
* Without motif we use our own foreground resource instead of
* using the manager's
*/
#ifdef MOTIF
Fg = hw->manager.foreground;
#else
Fg = hw->html.foreground;
#endif /* MOTIF */
Bg = hw->core.background_pixel;
Underlines = 0;
DashedUnderlines = False;
Width = width;
TextIndent = MarginW;
ElementId = 0;
WidgetId = 0;
LineNumber = 1;
LineBottom = 0;
BaseLine = -100;
CharsInLine = 0;
IndentLevel = 0;
Ignore = 0;
Preformat = 0;
PF_LF_State = 0;
NeedSpace = 0;
Internal = False;
Strikeout = False;
AnchorText = NULL;
DescType = &BaseDesc;
ListData = &BaseDesc;
DescType->type = D_NONE;
DescType->count = 0;
DescType->compact = 0;
DescType->next = NULL;
CurrentForm = NULL;
CurrentSelect = NULL;
TextAreaBuf = NULL;
Superscript = 0; /* amb */
Subscript = 0;
InDocHead = 0;
InUnderlined = 0;
/*
* Free the old title, if there is one.
*/
if (hw->html.title != NULL)
{
free(hw->html.title);
hw->html.title = NULL;
}
TitleText = NULL;
#ifdef THROW_AWAY_OLD_LIST
/*
* Free up previously formatted elements
*/
FreeLineList(hw->html.formatted_elements);
hw->html.formatted_elements = NULL;
#endif
/*
* Clear any previous selections
*/
hw->html.select_start = NULL;
hw->html.select_end = NULL;
hw->html.new_start = NULL;
hw->html.new_end = NULL;
/*
* Set up a starting font, and starting x, y, position
*/
NewFont(hw->html.font);
currentFont = hw->html.font;
saveFont = NULL;
FontStack = &FontBase;
FontStack->font = hw->html.font;
x = TextIndent;
y = hw->html.margin_height;
/*
* Start a null element list, to be filled in as we go.
*/
Current = NULL;
/*
* If we have parsed special header text, fill it in now.
*/
if (hw->html.html_header_objects != NULL)
{
msave = hw->html.html_objects;
hw->html.html_objects = hw->html.html_header_objects;
FormatChunk(hw, &x, &y);
if (saveFont != NULL)
{
hw->html.font = saveFont;
saveFont = NULL;
}
NewFont(hw->html.font);
currentFont = hw->html.font;
ConditionalLineFeed(hw, &x, &y, 1);
hw->html.html_objects = msave;
}
/*
* Format all objects for width
*/
FormatChunk(hw, &x, &y);
/*
* If we have parsed special footer text, fill it in now.
*/
if (hw->html.html_footer_objects != NULL)
{
if (saveFont != NULL)
{
hw->html.font = saveFont;
saveFont = NULL;
}
NewFont(hw->html.font);
currentFont = hw->html.font;
Preformat = 0;
PF_LF_State = 0;
NeedSpace = 0;
ConditionalLineFeed(hw, &x, &y, 1);
msave = hw->html.html_objects;
hw->html.html_objects = hw->html.html_footer_objects;
FormatChunk(hw, &x, &y);
hw->html.html_objects = msave;
}
/*
* Ensure a linefeed after the final element.
*/
ConditionalLineFeed(hw, &x, &y, 1);
/*
* Restore the proper font from unterminated preformatted text
* sequences.
*/
if (saveFont != NULL)
{
hw->html.font = saveFont;
saveFont = NULL;
}
/*
* Free any extra of the pre-allocated list.
* Terminate the element list.
*/
if ((Current != NULL)&&(Current->next != NULL))
{
FreeLineList(Current->next);
Current->next = NULL;
}
else if ((Current == NULL)&&(hw->html.formatted_elements != NULL))
{
FreeLineList(hw->html.formatted_elements);
hw->html.formatted_elements = NULL;
}
/*
* Add the bottom margin to the max height.
*/
y = y + hw->html.margin_height;
/*
* Make the line array indexed into the element list
* and store it into the widget
*/
hw->html.line_count = LineNumber;
if (hw->html.line_array != NULL)
{
free((char *)hw->html.line_array);
}
hw->html.line_array = MakeLineList(hw->html.formatted_elements,
LineNumber);
/*
* If the passed in MaxWidth was wrong, correct it.
*/
if (MaxWidth != width)
{
*Fwidth = MaxWidth;
}
#ifndef DISABLE_TRACE
if (htmlwTrace) {
#ifndef VMS
gettimeofday(&Tv, &Tz);
fprintf(stderr, "FormatAll exit (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
#else
fprintf(stderr, "FormatAll exit (%s)\n", asctime(localtime(&clock)));
#endif
}
#endif
return(y);
}
/*
* Redraw a linefeed.
* Basically a filled rectangle at the end of a line.
*/
void
LinefeedRefresh(hw, eptr)
HTMLWidget hw;
struct ele_rec *eptr;
{
int x1, y1;
unsigned int width, height;
#ifdef NO_EXTRA_FILLS
/*
* The actualt height of the rectangle to fill is strange, based
* an a differente between eptr->font->(ascent/descent) and
* eptr->font->max_bounds.(ascent/descent) which I don't quite
* understand. But it works.
* Deal with bad Lucidia descents.
*/
x1 = eptr->x;
if (x1 > (int)hw->core.width)
{
width = 0;
}
else
{
width = hw->core.width - x1;
}
#ifdef SHORT_LINEFEEDS
y1 = eptr->y + eptr->y_offset + eptr->font->max_bounds.ascent -
eptr->font->ascent;
height = eptr->font->ascent + eptr->font->descent;
#else
y1 = eptr->y + eptr->font->max_bounds.ascent - eptr->font->ascent;
height = eptr->line_height;
#endif /* SHORT_LINEFEEDS */
#else
x1 = eptr->x;
if (x1 > (int)hw->core.width)
{
width = 0;
}
else
{
width = hw->core.width - x1;
}
#ifdef SHORT_LINEFEEDS
y1 = eptr->y + eptr->y_offset;
if (eptr->font->descent > eptr->font->max_bounds.descent)
{
height = eptr->font->max_bounds.ascent +
eptr->font->descent;
}
else
{
height = eptr->font->max_bounds.ascent +
eptr->font->max_bounds.descent;
}
#else
y1 = eptr->y;
height = eptr->line_height;
#endif /* SHORT_LINEFEEDS */
#endif /* NO_EXTRA_FILLS */
x1 = x1 - hw->html.scroll_x;
y1 = y1 - hw->html.scroll_y;
if (eptr->selected == True)
{
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
}
else
{
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
}
/* Don't draw out past the end of the text if selecting */
if (eptr->selected == False) {
if (hw->html.bg_image) {
HTMLDrawBackgroundImage((Widget)hw,
x1,
y1,
width,
height);
}
else {
XFillRectangle(XtDisplay(hw->html.view),
XtWindow(hw->html.view),
hw->html.drawGC,
x1,
y1,
width,
height);
}
}
}
/*
* Redraw part of a formatted text element, in the passed fg and bg
*/
void
PartialRefresh(hw, eptr, start_pos, end_pos, fg, bg)
HTMLWidget hw;
struct ele_rec *eptr;
int start_pos, end_pos;
unsigned long fg, bg;
{
int ascent;
char *tdata;
int tlen;
int x, y, width;
int partial, descent;
unsigned long valuemask;
XGCValues values;
XSetFont(XtDisplay(hw), hw->html.drawGC, eptr->font->fid);
ascent = eptr->font->max_bounds.ascent;
width = -1;
partial = 0;
if (start_pos != 0)
{
int dir, nascent;
XCharStruct all;
#ifndef ASSUME_FIXED_WIDTH_PRE
if (eptr->font == hw->html.plain_font)
{
all.width = eptr->font->max_bounds.width * start_pos;
}
else
{
XTextExtents(eptr->font, (char *)eptr->edata,
start_pos, &dir, &nascent, &descent, &all);
}
#else
XTextExtents(eptr->font, (char *)eptr->edata,
start_pos, &dir, &nascent, &descent, &all);
#endif /* ASSUME_FIXED_WIDTH_PRE */
x = eptr->x + all.width;
tdata = (char *)(eptr->edata + start_pos);
partial = 1;
}
else
{
x = eptr->x;
tdata = (char *)eptr->edata;
}
if (end_pos != (eptr->edata_len - 2))
{
tlen = end_pos - start_pos + 1;
partial = 1;
}
else
{
tlen = eptr->edata_len - start_pos - 1;
}
y = eptr->y + eptr->y_offset;
x = x - hw->html.scroll_x;
y = y - hw->html.scroll_y;
#ifndef NO_EXTRA_FILLS
{
int dir, nascent, descent;
XCharStruct all;
int height;
/*
* May be safe to used the cached full width of this
* string, and thus avoid a call to XTextExtents
*/
if ((!partial)&&(eptr->width != 0))
{
all.width = eptr->width;
}
else
{
#ifdef ASSUME_FIXED_WIDTH_PRE
if (eptr->font == hw->html.plain_font)
{
all.width = eptr->font->max_bounds.width * tlen;
}
else
{
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent, &all);
}
#else
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent, &all);
#endif /* ASSUME_FIXED_WIDTH_PRE */
}
XSetForeground(XtDisplay(hw), hw->html.drawGC, bg);
height = (eptr->font->max_bounds.ascent - eptr->font->ascent);
if (height > 0)
{
if(!hw->html.bg_image)
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC, x, y,
(unsigned int)all.width, (unsigned int)height);
}
height = (eptr->font->max_bounds.descent - eptr->font->descent);
if (height > 0)
{
if(!hw->html.bg_image)
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC, x,
(int)(y + eptr->font->max_bounds.ascent +
eptr->font->descent),
(unsigned int)all.width, (unsigned int)height);
}
width = all.width;
}
#endif /* NO_EXTRA_FILLS */
if (bg!=hw->html.view->core.background_pixel || NoBodyImages(hw) || !hw->html.bg_image) {
XSetForeground(XtDisplay(hw), hw->html.drawGC, bg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, fg);
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
x,
y,
width,
ascent+eptr->font->descent);
XSetForeground(XtDisplay(hw), hw->html.drawGC, fg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, bg);
XDrawString(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
x,
y + ascent,
(char *)tdata,
tlen);
}
else {
XSetForeground(XtDisplay(hw), hw->html.drawGC, bg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, fg);
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
x,
y,
width,
ascent+eptr->font->descent);
XSetForeground(XtDisplay(hw), hw->html.drawGC, fg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, bg);
HTMLDrawBackgroundImage((Widget)hw,
(x<0 ?
0 :
x),
(y<0 ?
0 :
y),
(x<0 ?
(width+x) :
width),
(y<0 ?
(ascent+eptr->font->descent+y) :
(ascent+eptr->font->descent)));
XDrawString(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
x,
y + ascent,
(char *)tdata,
tlen);
}
if (eptr->underline_number)
{
int i, ly;
if (eptr->dashed_underline)
{
XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
LineOnOffDash, CapButt, JoinBevel);
}
else
{
XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
LineSolid, CapButt, JoinBevel);
}
if (width == -1)
{
int dir, nascent, descent;
XCharStruct all;
#ifdef ASSUME_FIXED_WIDTH_PRE
if (eptr->font == hw->html.plain_font)
{
all.width = eptr->font->max_bounds.width * tlen;
}
else
{
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent,&all);
}
#else
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent,&all);
#endif /* ASSUME_FIXED_WIDTH_PRE */
width = all.width;
}
ly = (int)(y + eptr->font->max_bounds.ascent +
eptr->font->descent - 1);
for (i=0; i<eptr->underline_number; i++)
{
XDrawLine(XtDisplay(hw),
XtWindow(hw->html.view), hw->html.drawGC,
x, ly, (int)(x + width), ly);
ly -= 2;
}
}
if (eptr->strikeout == True)
{
int ly;
XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
LineSolid, CapButt, JoinBevel);
if (width == -1)
{
int dir, nascent, descent;
XCharStruct all;
#ifdef ASSUME_FIXED_WIDTH_PRE
if (eptr->font == hw->html.plain_font)
{
all.width = eptr->font->max_bounds.width * tlen;
}
else
{
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent,&all);
}
#else
XTextExtents(eptr->font, (char *)tdata,
tlen, &dir, &nascent, &descent,&all);
#endif /* ASSUME_FIXED_WIDTH_PRE */
width = all.width;
}
ly = (int)(y + eptr->font->max_bounds.ascent +
eptr->font->descent - 1);
ly = ly - ((hw->html.font->max_bounds.ascent +
hw->html.font->descent) / 2);
XDrawLine(XtDisplay(hw), XtWindow(hw->html.view),
hw->html.drawGC,
x, ly, (int)(x + width), ly);
}
}
/*
* Redraw a formatted text element
*/
void
TextRefresh(hw, eptr, start_pos, end_pos)
HTMLWidget hw;
struct ele_rec *eptr;
int start_pos, end_pos;
{
if (eptr->selected == False)
{
PartialRefresh(hw, eptr, start_pos, end_pos,
eptr->fg, eptr->bg);
}
else if ((start_pos >= eptr->start_pos)&&(end_pos <= eptr->end_pos))
{
PartialRefresh(hw, eptr, start_pos, end_pos,
eptr->bg, eptr->fg);
}
else
{
if (start_pos < eptr->start_pos)
{
PartialRefresh(hw, eptr, start_pos, eptr->start_pos - 1,
eptr->fg, eptr->bg);
start_pos = eptr->start_pos;
}
if (end_pos > eptr->end_pos)
{
PartialRefresh(hw, eptr, eptr->end_pos + 1, end_pos,
eptr->fg, eptr->bg);
end_pos = eptr->end_pos;
}
PartialRefresh(hw, eptr, start_pos, end_pos,
eptr->bg, eptr->fg);
}
}
/*
* Redraw a formatted bullet element
*/
void
BulletRefresh(hw, eptr)
HTMLWidget hw;
struct ele_rec *eptr;
{
int width, line_height;
int x1, y1;
/*
width = eptr->font->max_bounds.width;
*/
width = eptr->font->max_bounds.lbearing +
eptr->font->max_bounds.rbearing;
/*
* Deal with bad Lucidia descents.
*/
if (eptr->font->descent > eptr->font->max_bounds.descent)
{
line_height = eptr->font->max_bounds.ascent +
eptr->font->descent;
}
else
{
line_height = eptr->font->max_bounds.ascent +
eptr->font->max_bounds.descent;
}
x1 = eptr->x;
y1 = eptr->y + eptr->y_offset + (line_height / 2) - (width / 4);
x1 = x1 - hw->html.scroll_x;
y1 = y1 - hw->html.scroll_y;
XSetFont(XtDisplay(hw), hw->html.drawGC, eptr->font->fid);
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
/*
* Rewritten to alternate circle, square and those paris alternate filled
* and not filled.
* --SWP
*/
if (eptr->indent_level && (eptr->indent_level % 2)) { /* odd & !0 */
XSetLineAttributes(XtDisplay(hw),
hw->html.drawGC,
1,
LineSolid,
CapButt,
JoinBevel);
if (eptr->indent_level==1 || (eptr->indent_level % 4)==1) {
XFillArc(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
(x1 - width),
y1,
(width / 2),
(width / 2),
0,
23040);
}
else {
XDrawArc(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
(x1 - width),
y1,
(width / 2),
(width / 2),
0,
23040);
}
}
else { /* even */
XSetLineAttributes(XtDisplay(hw),
hw->html.drawGC,
1,
LineSolid,
CapButt,
JoinBevel);
if (eptr->indent_level==0 || (eptr->indent_level % 4)==2) {
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
(x1 - width),
y1,
(width / 2),
(width / 2));
}
else {
XDrawRectangle(XtDisplay(hw),
XtWindow(hw->html.view),
hw->html.drawGC,
(x1 - width),
y1,
(width / 2),
(width / 2));
}
}
}
/*
* Redraw a formatted horizontal rule element
*/
void
HRuleRefresh(hw, eptr)
HTMLWidget hw;
struct ele_rec *eptr;
{
int width, height;
int x1, y1;
width = (int)hw->html.view_width - (int)(2 * hw->html.margin_width);
if (width < 0)
{
width = 0;
}
x1 = eptr->x;
y1 = eptr->y;
x1 = x1 - hw->html.scroll_x;
y1 = y1 - hw->html.scroll_y;
height = eptr->line_height;
/* blank out area */
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
if(!hw->html.bg_image)
XFillRectangle(XtDisplay(hw), XtWindow(hw->html.view),
hw->html.drawGC, x1, y1, width, height);
y1 = y1 + (height / 2) - 1;
XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
LineSolid, CapButt, JoinBevel);
#ifdef MOTIF
XDrawLine(XtDisplay(hw), XtWindow(hw->html.view),
hw->manager.bottom_shadow_GC,
x1, y1, (int)(x1 + width), y1);
XDrawLine(XtDisplay(hw), XtWindow(hw->html.view),
hw->manager.top_shadow_GC,
x1, y1 + 1, (int)(x1 + width), y1 + 1);
#else
/* changing the GC back and forth is not the most efficient way.... */
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
XDrawLine(XtDisplay(hw), XtWindow(hw->html.view),
hw->html.drawGC,
x1, y1, (int)(x1 + width), y1);
XDrawLine(XtDisplay(hw), XtWindow(hw->html.view),
hw->html.drawGC,
x1, y1 + 1, (int)(x1 + width), y1 + 1);
#endif
}
/*
* Redraw a formatted image element.
* The color of the image border reflects whether it is an active anchor
* or not.
* Actual Pixmap creation was put off until now to make sure we
* had a window. If it hasn't been already created, make the Pixmap
* now.
*/
void
ImageRefresh(hw, eptr)
HTMLWidget hw;
struct ele_rec *eptr;
{
unsigned long valuemask;
XGCValues values;
if (eptr->pic_data != NULL)
{
int x, y, extra;
x = eptr->x;
y = eptr->y + eptr->y_offset;
if ((hw->html.border_images == True)||
((eptr->anchorHRef != NULL)&&
(!eptr->pic_data->internal)))
{
if (eptr->pic_data->delayed) {
extra=2;
}
else {
extra = eptr->bwidth;
}
}
else
{
extra = 0;
}
x = x - hw->html.scroll_x;
y = y - hw->html.scroll_y;
XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
XSetBackground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
if (extra) {
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view), hw->html.drawGC,
x, y,
(eptr->pic_data->width + (2 * extra)),
extra);
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view), hw->html.drawGC,
x,
(y + eptr->pic_data->height + extra),
(eptr->pic_data->width + (2 * extra)),
extra);
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view), hw->html.drawGC,
x, y,
extra,
(eptr->pic_data->height + (2 * extra)));
XFillRectangle(XtDisplay(hw),
XtWindow(hw->html.view), hw->html.drawGC,
(x + eptr->pic_data->width + extra),
y,
extra,
(eptr->pic_data->height + (2 * extra)));
}
if (eptr->pic_data->image == None)
{
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->image = InfoToImage(hw,
eptr->pic_data, 0);
if (eptr->pic_data->transparent &&
eptr->pic_data->clip==None) {
eptr->pic_data->clip =
XCreatePixmapFromBitmapData
(XtDisplay(hw),
XtWindow(hw->html.view),
eptr->pic_data->clip_data,
eptr->pic_data->width,
eptr->pic_data->height,
1,
0,
1);
}
else if (!eptr->pic_data->transparent) {
eptr->pic_data->clip = None;
}
}
else
{
if (eptr->pic_data->delayed)
{
if ((eptr->anchorHRef != NULL)&&
(!IsDelayedHRef(hw, eptr->anchorHRef))&&
(!IsIsMapForm(hw, eptr->anchorHRef)))
{
eptr->pic_data->image = DelayedImage(
hw, True);
}
else
{
eptr->pic_data->image = DelayedImage(
hw, False);
}
}
else
{
/*
* Could be that the user opened another
* window, and the Pixmap was freed, and
* then they overflowed the cache,
* and the XImage data was freed.
* If this image was ever successfully
* fetched, try again before giving up.
*/
if ((eptr->pic_data->fetched)&&
(hw->html.resolveDelayedImage != NULL))
{
ImageInfo *pdata;
pdata = eptr->pic_data;
eptr->pic_data = (*(resolveImageProc)
(hw->html.resolveDelayedImage))(hw,
eptr->edata);
if (eptr->pic_data != NULL)
{
eptr->pic_data->delayed = 0;
/*
* Mark images we have sucessfully
* loaded at least once
*/
if (eptr->pic_data->image_data != NULL)
{
eptr->pic_data->fetched = 1;
}
/*
* Copy over state information from
* the last time we had this image
*/
eptr->pic_data->ismap =
pdata->ismap;
eptr->pic_data->fptr =
pdata->fptr;
eptr->pic_data->internal =
pdata->internal;
eptr->pic_data->text =
pdata->text;
}
else
{
eptr->pic_data = NoImageData(hw);
eptr->pic_data->delayed = 0;
eptr->pic_data->internal = 0;
}
}
else
{
eptr->pic_data->image = NoImage(hw);
}
}
}
}
if (eptr->pic_data->image != None)
{
if (eptr->pic_data->transparent) {
unsigned long valuemask;
XGCValues values;
values.clip_mask=eptr->pic_data->clip;
values.clip_x_origin=x+extra;
values.clip_y_origin=y+extra;
valuemask=GCClipMask|GCClipXOrigin|GCClipYOrigin;
XChangeGC(XtDisplay(hw),
hw->html.drawGC,
valuemask, &values);
XCopyArea(XtDisplay(hw),
eptr->pic_data->image,
XtWindow(hw->html.view),
hw->html.drawGC,
0,
0,
eptr->pic_data->width,
eptr->pic_data->height,
(x + extra),
(y + extra));
values.clip_mask=None;
values.clip_x_origin=0;
values.clip_y_origin=0;
valuemask=GCClipMask|GCClipXOrigin|GCClipYOrigin;
XChangeGC(XtDisplay(hw),
hw->html.drawGC,
valuemask, &values);
}
else {
values.clip_mask=None;
values.clip_x_origin=0;
values.clip_y_origin=0;
valuemask=GCClipMask|GCClipXOrigin|GCClipYOrigin;
XChangeGC(XtDisplay(hw),
hw->html.drawGC,
valuemask, &values);
XCopyArea(XtDisplay(hw),
eptr->pic_data->image,
XtWindow(hw->html.view),
hw->html.drawGC,
0,
0,
eptr->pic_data->width,
eptr->pic_data->height,
(x + extra),
(y + extra));
}
}
if ((eptr->pic_data->delayed)&&(eptr->anchorHRef != NULL)&&
(!IsDelayedHRef(hw, eptr->anchorHRef))&&
(!IsIsMapForm(hw, eptr->anchorHRef))) {
XSetForeground(XtDisplay(hw),
hw->html.drawGC,
eptr->fg);
XFillRectangle(XtDisplay(hw->html.view),
XtWindow(hw->html.view),
hw->html.drawGC,
x,
(y + AnchoredHeight(hw)),
(eptr->pic_data->width + (2 * extra)),
extra);
}
}
}
void
RefreshTextRange(hw, start, end)
HTMLWidget hw;
struct ele_rec *start;
struct ele_rec *end;
{
struct ele_rec *eptr;
eptr = start;
while ((eptr != NULL)&&(eptr != end))
{
if (eptr->type == E_TEXT)
{
TextRefresh(hw, eptr,
0, (eptr->edata_len - 2));
}
eptr = eptr->next;
}
if (eptr != NULL)
{
if (eptr->type == E_TEXT)
{
TextRefresh(hw, eptr,
0, (eptr->edata_len - 2));
}
}
}
/*
* Refresh all elements on a single line into the widget's window
*/
void
PlaceLine(hw, line)
HTMLWidget hw;
int line;
{
struct ele_rec *eptr;
XGCValues values;
/*
* Item list for this line
*/
eptr = hw->html.line_array[line];
while ((eptr != NULL)&&(eptr->line_number == (line + 1)))
{
switch(eptr->type)
{
case E_TEXT:
TextRefresh(hw, eptr,
0, (eptr->edata_len - 2));
break;
case E_BULLET:
BulletRefresh(hw, eptr);
break;
case E_HRULE:
HRuleRefresh(hw, eptr);
break;
case E_LINEFEED:
if(!hw->html.bg_image)
LinefeedRefresh(hw, eptr);
break;
case E_IMAGE:
ImageRefresh(hw, eptr);
break;
case E_WIDGET:
WidgetRefresh(hw, eptr);
break;
case E_TABLE:
TableRefresh(hw, eptr);
break;
}
eptr = eptr->next;
}
}
/*
* Locate the element (if any) that is at the passed location
* in the widget. If there is no corresponding element, return
* NULL. If an element is found return the position of the character
* you are at in the pos pointer passed.
*/
struct ele_rec *
LocateElement(hw, x, y, pos)
HTMLWidget hw;
int x, y;
int *pos;
{
struct ele_rec *eptr;
struct ele_rec *rptr;
int i, start, end, line, guess;
int tx1, tx2, ty1, ty2;
x = x + hw->html.scroll_x;
y = y + hw->html.scroll_y;
/*
* Narrow the search down to a 2 line range
* before beginning to search element by element
*/
start = -1;
end = -1;
/*
* Heuristic to speed up redraws by guessing at the starting line.
*/
guess = y / (hw->html.font->max_bounds.ascent +
hw->html.font->max_bounds.descent);
if (guess > (hw->html.line_count - 1))
{
guess = hw->html.line_count - 1;
}
while (guess > 0)
{
if ((hw->html.line_array[guess] != NULL)&&
(hw->html.line_array[guess]->y <= y))
{
break;
}
guess--;
}
if (guess < 0)
{
guess = 0;
}
for (i=guess; i<hw->html.line_count; i++)
{
if (hw->html.line_array[i] == NULL)
{
continue;
}
else if (hw->html.line_array[i]->y <= y)
{
start = i;
continue;
}
else
{
end = i;
break;
}
}
/*
* Search may have already failed, or it may be a one line
* range.
*/
if ((start == -1)&&(end == -1))
{
return(NULL);
}
else if (start == -1)
{
start = end;
}
else if (end == -1)
{
end = start;
}
/*
* Search element by element, for now we only search
* text elements, images, and linefeeds.
*/
eptr = hw->html.line_array[start];
ty1 = eptr->y;
/*
* Deal with bad Lucidia descents.
*/
if (eptr->font->descent > eptr->font->max_bounds.descent)
{
ty2 = eptr->y + eptr->font->max_bounds.ascent +
eptr->font->descent;
}
else
{
ty2 = eptr->y + eptr->font->max_bounds.ascent +
eptr->font->max_bounds.descent;
}
line = eptr->line_number;
/*
* Searches on this line should extend to the top of the
* next line, if possible. Which might be far away if there
* is an image on this line.
*/
if (((line + 1) < hw->html.line_count)&&
(hw->html.line_array[line + 1] != NULL))
{
ty2 = hw->html.line_array[line + 1]->y - 1;
}
/*
* Else we are at the last line, and need to find its height.
* The linefeed at the end should know the max height of the line.
*/
else
{
struct ele_rec *teptr;
teptr = eptr;
while (teptr != NULL)
{
if (teptr->type == E_LINEFEED)
{
break;
}
teptr = teptr->next;
}
if (teptr != NULL)
{
ty2 = teptr->y + teptr->line_height - 1;
}
}
rptr = NULL;
while ((eptr != NULL)&&(eptr->line_number <= (end + 1)))
{
if (eptr->line_number != line)
{
ty1 = ty2;
/*
* Deal with bad Lucidia descents.
*/
if(eptr->font->descent > eptr->font->max_bounds.descent)
{
ty2 = eptr->y + eptr->font->max_bounds.ascent +
eptr->font->descent;
}
else
{
ty2 = eptr->y + eptr->font->max_bounds.ascent +
eptr->font->max_bounds.descent;
}
line = eptr->line_number;
/*
* Searches on this line should extend to the top of
* the next line, if possible. Which might be far
* away if there is an image on this line.
*/
if (((line + 1) < hw->html.line_count)&&
(hw->html.line_array[line + 1] != NULL))
{
ty2 = hw->html.line_array[line + 1]->y - 1;
}
/*
* Else we are at the last line, and need to find its
* height. The linefeed at the end should know the
* max height of the line.
*/
else
{
struct ele_rec *teptr;
teptr = eptr;
while (teptr != NULL)
{
if (teptr->type == E_LINEFEED)
{
break;
}
teptr = teptr->next;
}
if (teptr != NULL)
{
ty2 = teptr->y + teptr->line_height - 1;
}
}
}
if (eptr->type == E_TEXT)
{
int dir, ascent, descent;
XCharStruct all;
tx1 = eptr->x;
XTextExtents(eptr->font, (char *)eptr->edata,
eptr->edata_len - 1, &dir,
&ascent, &descent, &all);
tx2 = eptr->x + all.width;
if ((x >= tx1)&&(x <= tx2)&&(y >= ty1)&&(y <= ty2))
{
rptr = eptr;
break;
}
}
else if ((eptr->type == E_IMAGE)&&(eptr->pic_data != NULL))
{
tx1 = eptr->x;
tx2 = eptr->x + eptr->pic_data->width;
if ((x >= tx1)&&(x <= tx2)&&(y >= ty1)&&(y <= ty2))
{
rptr = eptr;
break;
}
}
else if (eptr->type == E_LINEFEED)
{
tx1 = eptr->x;
if ((x >= tx1)&&(y >= ty1)&&(y <= ty2))
{
rptr = eptr;
break;
}
else if (eptr->next == NULL)
{
rptr = eptr;
break;
}
else if (eptr->next != NULL)
{
int tmpy;
tmpy = eptr->next->y + eptr->next->line_height;
tx2 = eptr->next->x;
if ((x < tx2)&&(y >= ty2)&&(y <= tmpy))
{
rptr = eptr;
break;
}
}
}
eptr = eptr->next;
}
/*
* If we found an element, locate the exact character position within
* that element.
*/
if (rptr != NULL)
{
int dir, ascent, descent;
XCharStruct all;
int epos;
/*
* Start assuming fixed width font. The real position should
* always be <= to this, but just in case, start at the end
* of the string if it is not.
*/
epos = ((x - rptr->x) / rptr->font->max_bounds.width) + 1;
if (epos >= rptr->edata_len - 1)
{
epos = rptr->edata_len - 2;
}
XTextExtents(rptr->font, (char *)rptr->edata,
(epos + 1), &dir, &ascent, &descent, &all);
if (x > (int)(rptr->x + all.width))
{
epos = rptr->edata_len - 3;
}
else
{
epos--;
}
while (epos >= 0)
{
XTextExtents(rptr->font, (char *)rptr->edata,
(epos + 1), &dir, &ascent, &descent, &all);
if ((int)(rptr->x + all.width) <= x)
{
break;
}
epos--;
}
epos++;
*pos = epos;
}
return(rptr);
}
/*
* Used by ParseTextToPrettyString to let it be sloppy about its
* string creation, and never overflow the buffer.
* It concatonates the passed string to the current string, managing
* both the current string length, and the total buffer length.
*/
void
strcpy_or_grow(str, slen, blen, add)
char **str;
int *slen;
int *blen;
char *add;
{
int newlen;
int addlen;
char *buf;
/*
* If necessary, initialize this string buffer
*/
if (*str == NULL)
{
*str = (char *)malloc(1024 * sizeof(char));
if (*str == NULL)
{
return;
}
*blen = 1024;
strcpy(*str, "");
*slen = 0;
}
buf = *str;
if ((buf == NULL)||(add == NULL))
{
return;
}
addlen = strlen(add);
newlen = *slen + addlen;
if (newlen >= *blen)
{
newlen = ((newlen / 1024) + 1) * 1024;
buf = (char *)malloc(newlen * sizeof(char));
if (buf == NULL)
{
return;
}
/*
bcopy(*str, buf, *blen);
*/
memcpy(buf, *str, *blen);
free((char *)*str);
*str = buf;
*blen = newlen;
}
/*
bcopy(add, (char *)(buf + *slen), addlen + 1);
*/
memcpy((char *)(buf + *slen), add, addlen + 1);
*slen = *slen + addlen;
}
/*
* Parse all the formatted text elements from start to end
* into an ascii text string, and return it.
* space_width and lmargin tell us how many spaces
* to indent lines.
*/
char *
ParseTextToString(elist, startp, endp, start_pos, end_pos, space_width, lmargin)
struct ele_rec *elist;
struct ele_rec *startp;
struct ele_rec *endp;
int start_pos, end_pos;
int space_width;
int lmargin;
{
int newline;
int epos;
char *text;
int t_slen, t_blen;
struct ele_rec *eptr;
struct ele_rec *start;
struct ele_rec *end;
if (startp == NULL)
{
return(NULL);
}
if (SwapElements(startp, endp, start_pos, end_pos))
{
start = endp;
end = startp;
epos = start_pos;
start_pos = end_pos;
end_pos = epos;
}
else
{
start = startp;
end = endp;
}
text = NULL;
newline = 0;
eptr = start;
while ((eptr != NULL)&&(eptr != end))
{
/*
* Skip the special internal text
*/
if (eptr->internal == True)
{
eptr = eptr->next;
continue;
}
if (eptr->type == E_TEXT)
{
int i, spaces;
char *tptr;
if (eptr == start)
{
tptr = (char *)(eptr->edata + start_pos);
}
else
{
tptr = (char *)eptr->edata;
}
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
if (spaces < 0)
{
spaces = 0;
}
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&text, &t_slen, &t_blen,
" ");
}
}
strcpy_or_grow(&text, &t_slen, &t_blen, tptr);
newline = 0;
}
else if (eptr->type == E_LINEFEED)
{
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
newline = 1;
}
eptr = eptr->next;
}
if ((eptr != NULL)&&(eptr->internal == False))
{
if (eptr->type == E_TEXT)
{
int i, spaces;
char *tptr;
char *tend, tchar;
if (eptr == start)
{
tptr = (char *)(eptr->edata + start_pos);
}
else
{
tptr = (char *)eptr->edata;
}
if (eptr == end)
{
tend = (char *)(eptr->edata + end_pos + 1);
tchar = *tend;
*tend = '\0';
}
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
if (spaces < 0)
{
spaces = 0;
}
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&text, &t_slen, &t_blen,
" ");
}
}
strcpy_or_grow(&text, &t_slen, &t_blen, tptr);
newline = 0;
if (eptr == end)
{
*tend = tchar;
}
}
else if (eptr->type == E_LINEFEED)
{
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
newline = 1;
}
}
return(text);
}
/*
* Parse all the formatted text elements from start to end
* into an ascii text string, and return it.
* Very like ParseTextToString() except the text is prettied up
* to show headers and the like.
* space_width and lmargin tell us how many spaces
* to indent lines.
*/
char *
ParseTextToPrettyString(hw, elist, startp, endp, start_pos, end_pos,
space_width, lmargin)
HTMLWidget hw;
struct ele_rec *elist;
struct ele_rec *startp;
struct ele_rec *endp;
int start_pos, end_pos;
int space_width;
int lmargin;
{
int line;
int newline;
int lead_spaces;
int epos;
char *text;
int t_slen, t_blen;
char *line_buf;
int l_slen, l_blen;
char lchar;
struct ele_rec *eptr;
struct ele_rec *start;
struct ele_rec *end;
struct ele_rec *last;
if (startp == NULL)
{
return(NULL);
}
if (SwapElements(startp, endp, start_pos, end_pos))
{
start = endp;
end = startp;
epos = start_pos;
start_pos = end_pos;
end_pos = epos;
}
else
{
start = startp;
end = endp;
}
text = NULL;
line_buf = NULL;
/*
* We need to know if we should consider the indentation or bullet
* that might be just before the first selected element to also be
* selected. This current hack looks to see if they selected the
* Whole line, and assumes if they did, they also wanted the beginning.
*
* If we are at the beginning of the list, or the beginning of
* a line, or just behind a bullett, assume this is the start of
* a line that we may want to include the indent for.
*/
if ((start_pos == 0)&&
((start->prev == NULL)||(start->prev->type == E_BULLET)||
(start->prev->line_number != start->line_number)))
{
eptr = start;
while ((eptr != NULL)&&(eptr != end)&&
(eptr->type != E_LINEFEED))
{
eptr = eptr->next;
}
if ((eptr != NULL)&&(eptr->type == E_LINEFEED))
{
newline = 1;
if ((start->prev != NULL)&&
(start->prev->type == E_BULLET))
{
start = start->prev;
}
}
else
{
newline = 0;
}
}
else
{
newline = 0;
}
lead_spaces = 0;
last = start;
eptr = start;
line = eptr->line_number;
while ((eptr != NULL)&&(eptr != end))
{
/*
* Skip the special internal text
*/
if (eptr->internal == True)
{
eptr = eptr->next;
continue;
}
if (eptr->type == E_BULLET)
{
int i, spaces;
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
spaces -= 2;
if (spaces < 0)
{
spaces = 0;
}
lead_spaces = spaces;
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&line_buf,
&l_slen, &l_blen, " ");
}
}
newline = 0;
strcpy_or_grow(&line_buf, &l_slen, &l_blen, "o ");
lead_spaces += 2;
}
else if (eptr->type == E_TEXT)
{
int i, spaces;
char *tptr;
if (eptr == start)
{
tptr = (char *)(eptr->edata + start_pos);
}
else
{
tptr = (char *)eptr->edata;
}
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
if (spaces < 0)
{
spaces = 0;
}
lead_spaces = spaces;
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&line_buf,
&l_slen, &l_blen, " ");
}
}
strcpy_or_grow(&line_buf, &l_slen, &l_blen, tptr);
newline = 0;
}
else if (eptr->type == E_LINEFEED)
{
strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
newline = 1;
lchar = '\0';
if (eptr->font == hw->html.header1_font)
{
lchar = '*';
}
else if (eptr->font == hw->html.header2_font)
{
lchar = '=';
}
else if (eptr->font == hw->html.header3_font)
{
lchar = '+';
}
else if (eptr->font == hw->html.header4_font)
{
lchar = '-';
}
else if (eptr->font == hw->html.header5_font)
{
lchar = '~';
}
else if (eptr->font == hw->html.header6_font)
{
lchar = '.';
}
if (lchar != '\0')
{
char *ptr;
int cnt;
cnt = 0;
ptr = line_buf;
while ((ptr != NULL)&&(*ptr != '\0'))
{
cnt++;
if (cnt > lead_spaces)
{
*ptr = lchar;
}
ptr++;
}
strcpy_or_grow(&text,&t_slen,&t_blen, line_buf);
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
}
if (line_buf != NULL)
{
free(line_buf);
line_buf = NULL;
}
}
last = eptr;
eptr = eptr->next;
}
if ((eptr != NULL)&&(eptr->internal == False))
{
if (eptr->type == E_BULLET)
{
int i, spaces;
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
spaces -= 2;
if (spaces < 0)
{
spaces = 0;
}
lead_spaces = spaces;
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&line_buf,
&l_slen, &l_blen, " ");
}
}
newline = 0;
strcpy_or_grow(&line_buf, &l_slen, &l_blen, "o ");
lead_spaces += 2;
}
else if (eptr->type == E_TEXT)
{
int i, spaces;
char *tptr;
char *tend, tchar;
if (eptr == start)
{
tptr = (char *)(eptr->edata + start_pos);
}
else
{
tptr = (char *)eptr->edata;
}
if (eptr == end)
{
tend = (char *)(eptr->edata + end_pos + 1);
tchar = *tend;
*tend = '\0';
}
if (newline)
{
spaces = (eptr->x - lmargin) / space_width;
if (spaces < 0)
{
spaces = 0;
}
lead_spaces = spaces;
for (i=0; i<spaces; i++)
{
strcpy_or_grow(&line_buf,
&l_slen, &l_blen, " ");
}
}
strcpy_or_grow(&line_buf, &l_slen, &l_blen, tptr);
newline = 0;
if (eptr == end)
{
*tend = tchar;
}
}
else if (eptr->type == E_LINEFEED)
{
strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
newline = 1;
lchar = '\0';
if (eptr->font == hw->html.header1_font)
{
lchar = '*';
}
else if (eptr->font == hw->html.header2_font)
{
lchar = '=';
}
else if (eptr->font == hw->html.header3_font)
{
lchar = '+';
}
else if (eptr->font == hw->html.header4_font)
{
lchar = '-';
}
else if (eptr->font == hw->html.header5_font)
{
lchar = '~';
}
else if (eptr->font == hw->html.header6_font)
{
lchar = '.';
}
if (lchar != '\0')
{
char *ptr;
int cnt;
cnt = 0;
ptr = line_buf;
while ((ptr != NULL)&&(*ptr != '\0'))
{
cnt++;
if (cnt > lead_spaces)
{
*ptr = lchar;
}
ptr++;
}
strcpy_or_grow(&text,&t_slen,&t_blen, line_buf);
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
}
if (line_buf != NULL)
{
free(line_buf);
line_buf = NULL;
}
}
last = eptr;
}
if (line_buf != NULL)
{
strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
lchar = '\0';
if (last->font == hw->html.header1_font)
{
lchar = '*';
}
else if (last->font == hw->html.header2_font)
{
lchar = '=';
}
else if (last->font == hw->html.header3_font)
{
lchar = '+';
}
else if (last->font == hw->html.header4_font)
{
lchar = '-';
}
else if (last->font == hw->html.header5_font)
{
lchar = '~';
}
else if (last->font == hw->html.header6_font)
{
lchar = '.';
}
if (lchar != '\0')
{
char *ptr;
int cnt;
cnt = 0;
ptr = line_buf;
while ((ptr != NULL)&&(*ptr != '\0'))
{
cnt++;
if (cnt > lead_spaces)
{
*ptr = lchar;
}
ptr++;
}
strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
}
}
if (line_buf != NULL)
{
free(line_buf);
line_buf = NULL;
}
return(text);
}
/*
* Find the preferred width of a parsed HTML document
* Currently unformatted plain text, unformatted listing text, plain files
* and preformatted text require special width.
* Preferred width = (width of longest plain text line in document) *
* (width of that text's font)
*/
int
DocumentWidth(hw, list)
HTMLWidget hw;
struct mark_up *list;
{
struct mark_up *mptr;
int plain_text;
int listing_text;
int pcnt, lcnt, pwidth, lwidth;
int width;
char *ptr;
/*
* Loop through object list looking at the plain, preformatted,
* and listing text
*/
width = 0;
pwidth = 0;
lwidth = 0;
plain_text = 0;
listing_text = 0;
mptr = list;
while (mptr != NULL)
{
/*
* All text blocks between the starting and ending
* plain and pre text markers are plain text blocks.
* Manipulate flags so we recognize these blocks.
*/
if ((mptr->type == M_PLAIN_TEXT)||
(mptr->type == M_PLAIN_FILE)||
(mptr->type == M_PREFORMAT))
{
if (mptr->is_end)
{
plain_text--;
if (plain_text < 0)
{
plain_text = 0;
}
}
else
{
plain_text++;
}
pcnt = 0;
lcnt = 0;
}
/*
* All text blocks between the starting and ending
* listing markers are listing text blocks.
*/
else if (mptr->type == M_LISTING_TEXT)
{
if (mptr->is_end)
{
listing_text--;
if (listing_text < 0)
{
listing_text = 0;
}
}
else
{
listing_text++;
}
lcnt = 0;
pcnt = 0;
}
/*
* If this is a plain text block, add to line length.
* Find the Max of all line lengths.
*/
else if ((plain_text)&&(mptr->type == M_NONE))
{
ptr = mptr->text;
while ((ptr != NULL)&&(*ptr != '\0'))
{
ptr = MaxTextWidth(ptr, &pcnt);
if (pcnt > pwidth)
{
pwidth = pcnt;
}
}
}
/*
* If this is a listing text block, add to line length.
* Find the Max of all line lengths.
*/
else if ((listing_text)&&(mptr->type == M_NONE))
{
ptr = mptr->text;
while ((ptr != NULL)&&(*ptr != '\0'))
{
ptr = MaxTextWidth(ptr, &lcnt);
if (lcnt > lwidth)
{
lwidth = lcnt;
}
}
}
mptr = mptr->next;
}
width = pwidth * hw->html.plain_font->max_bounds.width;
lwidth = lwidth * hw->html.listing_font->max_bounds.width;
if (lwidth > width)
{
width = lwidth;
}
return(width);
}