mirror of https://github.com/lianthony/NT4.0
2112 lines
57 KiB
2112 lines
57 KiB
/*
|
|
This file was derived from the libwww code, version 2.15, from CERN.
|
|
A number of modifications have been made by Spyglass.
|
|
|
|
eric@spyglass.com
|
|
*/
|
|
/* Structured stream to Rich hypertext converter
|
|
** ============================================
|
|
**
|
|
** This generates of a hypertext object. It converts from the
|
|
** structured stream interface from HTML events into the style-
|
|
** oriented iunterface of the HText.h interface. This module is
|
|
** only used in clients and shouldnot be linked into servers.
|
|
**
|
|
** Override this module if making a new GUI browser.
|
|
**
|
|
*/
|
|
|
|
#include "all.h"
|
|
#include "marquee.h"
|
|
#include "mci.h"
|
|
|
|
#ifdef FEATURE_INTL
|
|
#define IEXPLORE
|
|
#include <fechrcnv.h>
|
|
// isspace doesn't work with non-ascii characters
|
|
// REVIEW: I think it's better just redefine this way than checking codepage.
|
|
#undef isspace
|
|
#define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')||(c=='\v')|| \
|
|
(c=='\f'))
|
|
#endif
|
|
|
|
#define IS_SPACE(ch) ( isspace((unsigned char) ch) )
|
|
|
|
#define HTML_C /** Used to avoid redeclatation problems in html.h **/
|
|
|
|
/* #define CAREFUL Check nesting here not really necessary */
|
|
|
|
/* HTML Object
|
|
** -----------
|
|
*/
|
|
#define MAX_NESTING 128 /* Should be checked by parser */
|
|
|
|
typedef struct _stack_element
|
|
{
|
|
int style;
|
|
int tag_number;
|
|
}
|
|
stack_element;
|
|
|
|
typedef struct _font_stack_element
|
|
{
|
|
int fontSize;
|
|
int fontFace;
|
|
int baseFontSize;
|
|
COLORREF fontColor;
|
|
}
|
|
font_stack_element;
|
|
|
|
typedef struct _center_stack_element
|
|
{
|
|
BOOL bCenter;
|
|
}
|
|
center_stack_element;
|
|
|
|
typedef struct _bold_stack_element
|
|
{
|
|
BOOL bBold;
|
|
}
|
|
bold_stack_element;
|
|
|
|
typedef struct _italic_stack_element
|
|
{
|
|
BOOL bItalic;
|
|
}
|
|
italic_stack_element;
|
|
|
|
typedef struct styleStateRec {
|
|
stack_element stack[MAX_NESTING];
|
|
stack_element *sp; // Style stack pointer
|
|
|
|
font_stack_element font_stack[MAX_NESTING];
|
|
font_stack_element *font_sp; // Font size stack pointer
|
|
|
|
center_stack_element center_stack[MAX_NESTING];
|
|
center_stack_element *center_sp; // Center stack pointer
|
|
|
|
bold_stack_element bold_stack[MAX_NESTING];
|
|
bold_stack_element *bold_sp; // Bold stack pointer
|
|
|
|
italic_stack_element italic_stack[MAX_NESTING];
|
|
italic_stack_element *italic_sp; // Italic stack pointer
|
|
|
|
BOOL bDefaultCenterValue;
|
|
|
|
BOOL bLastPoppedBold;
|
|
BOOL bLastPoppedItalic;
|
|
|
|
int new_style;
|
|
|
|
// from text
|
|
unsigned char iStyle;
|
|
unsigned char fontBits;
|
|
BOOL bCenter;
|
|
BOOL bBold;
|
|
BOOL bItalic;
|
|
BOOL bNoBreak;
|
|
BOOL bNeedListCRLF;
|
|
BOOL bNewPara;
|
|
BOOL bOnNewPara;
|
|
int baseFontSize;
|
|
int fontSize;
|
|
int fontFace;
|
|
COLORREF fontColor;
|
|
|
|
struct styleStateRec *next;
|
|
} STYLESTATE;
|
|
|
|
struct _HTStructured
|
|
{
|
|
CONST HTStructuredClass *isa;
|
|
char *szDocURL; /* Just points into request structure, so don't free! */
|
|
char base_url[MAX_URL_STRING + 1];
|
|
HText *text;
|
|
|
|
|
|
HTStream *target; /* Output stream */
|
|
HTStreamClass targetClass; /* Output routines */
|
|
|
|
HTChunk title; /* Grow by 128 */
|
|
HTChunk *martext; /* Marquee Text.. Where else can I put it? */
|
|
|
|
CONST SGML_dtd *dtd;
|
|
|
|
HTTag *current_tag;
|
|
BOOL style_change;
|
|
#define KEEP_A_SPACE
|
|
#ifdef KEEP_A_SPACE
|
|
BOOL do_space_pending;
|
|
BOOL space_pending;
|
|
#endif
|
|
STYLESTATE ss;
|
|
|
|
BOOL bFirstCellInRow;
|
|
BOOL bSeenBrInCell;
|
|
|
|
struct _MapContext *mc;
|
|
|
|
struct CharStream *csSource;
|
|
};
|
|
|
|
struct _HTStream
|
|
{
|
|
CONST HTStreamClass *isa;
|
|
/* .... */
|
|
};
|
|
|
|
/* Forward declarations of routines
|
|
*/
|
|
|
|
PRIVATE void actually_set_style(HTStructured * me);
|
|
PRIVATE void change_paragraph_style(HTStructured * me, int style);
|
|
|
|
static void PushFontInfo( HTStructured * me )
|
|
{
|
|
if (me->ss.font_sp == me->ss.font_stack)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Maximum nesting of %d exceded!\n",
|
|
MAX_NESTING));
|
|
} else {
|
|
--(me->ss.font_sp);
|
|
me->ss.font_sp[0].fontFace = me->text->fontFace;
|
|
me->ss.font_sp[0].fontSize = me->text->fontSize;
|
|
me->ss.font_sp[0].baseFontSize = me->text->baseFontSize;
|
|
me->ss.font_sp[0].fontColor = me->text->fontColor;
|
|
}
|
|
}
|
|
|
|
static void PopFontInfo( HTStructured * me )
|
|
{
|
|
if ( me->ss.font_sp != me->ss.font_stack + MAX_NESTING - 1 ) {
|
|
me->text->fontFace = me->ss.font_sp[0].fontFace;
|
|
me->text->fontSize = me->ss.font_sp[0].fontSize;
|
|
me->text->baseFontSize = me->ss.font_sp[0].baseFontSize;
|
|
me->text->fontColor = me->ss.font_sp[0].fontColor;
|
|
(me->ss.font_sp)++;
|
|
} else {
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Font stack underflow\n") );
|
|
}
|
|
}
|
|
|
|
#ifdef FEATURE_INTL
|
|
static void ForceFontChange( HTStructured * me, char *szFontFaceName, int CharSet )
|
|
{
|
|
if ( szFontFaceName ) // Change font
|
|
{
|
|
PushFontInfo ( me );
|
|
HText_beginSetFont(me->text, FALSE, NULL, NULL, szFontFaceName, CharSet);
|
|
}
|
|
else // Restore font
|
|
{
|
|
PopFontInfo( me );
|
|
HText_endSetFont(me->text, FALSE );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void PushCenterInfo( HTStructured * me, BOOL new_value )
|
|
{
|
|
if (me->ss.center_sp == me->ss.center_stack)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Maximum nesting of %d exceded!\n",
|
|
MAX_NESTING));
|
|
} else {
|
|
--(me->ss.center_sp);
|
|
me->ss.center_sp[0].bCenter = new_value;
|
|
}
|
|
}
|
|
|
|
static void PopCenterInfo( HTStructured * me )
|
|
{
|
|
if ( me->ss.center_sp != me->ss.center_stack + MAX_NESTING - 1 ) {
|
|
me->text->bCenter = me->ss.center_sp[0].bCenter;
|
|
(me->ss.center_sp)++;
|
|
} else {
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Center stack underflow\n") );
|
|
}
|
|
}
|
|
|
|
static void CenterSetValue( HTStructured * me, const char *align, BOOL setDefaultValue )
|
|
{
|
|
if ( align && !GTR_strcmpi((char *) align, "center") ) {
|
|
if ( setDefaultValue )
|
|
me->ss.bDefaultCenterValue = TRUE;
|
|
|
|
HText_beginCenter(me->text);
|
|
} else {
|
|
if ( setDefaultValue )
|
|
me->ss.bDefaultCenterValue = FALSE;
|
|
|
|
if ( (me->ss.center_sp != me->ss.center_stack + MAX_NESTING - 1) || me->ss.bDefaultCenterValue ) {
|
|
HText_beginCenter(me->text);
|
|
} else {
|
|
HText_endCenter(me->text);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void PushBoldInfo( HTStructured * me )
|
|
{
|
|
if (me->ss.bold_sp == me->ss.bold_stack)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Maximum nesting of %d exceded!\n",
|
|
MAX_NESTING));
|
|
} else {
|
|
--(me->ss.bold_sp);
|
|
me->ss.bLastPoppedBold =
|
|
me->ss.bold_sp[0].bBold = (me->text->fontBits & FONTBIT_BOLD) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
|
|
static void PopBoldInfo( HTStructured * me )
|
|
{
|
|
if ( me->ss.bold_sp != me->ss.bold_stack + MAX_NESTING - 1 ) {
|
|
if ( me->ss.bLastPoppedBold = me->ss.bold_sp[0].bBold )
|
|
HText_beginBold( me->text );
|
|
else
|
|
HText_endBold( me->text );
|
|
(me->ss.bold_sp)++;
|
|
} else {
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Bold stack underflow\n") );
|
|
}
|
|
}
|
|
|
|
static void PushItalicInfo( HTStructured * me )
|
|
{
|
|
if (me->ss.italic_sp == me->ss.italic_stack)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Maximum nesting of %d exceded!\n",
|
|
MAX_NESTING));
|
|
} else {
|
|
--(me->ss.italic_sp);
|
|
me->ss.bLastPoppedItalic =
|
|
me->ss.italic_sp[0].bItalic = (me->text->fontBits & FONTBIT_ITALIC) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
|
|
static void PopItalicInfo( HTStructured * me )
|
|
{
|
|
if ( me->ss.italic_sp != me->ss.italic_stack + MAX_NESTING - 1 ) {
|
|
if ( me->ss.bLastPoppedItalic = me->ss.italic_sp[0].bItalic )
|
|
HText_beginItalic( me->text );
|
|
else
|
|
HText_endItalic( me->text );
|
|
(me->ss.italic_sp)++;
|
|
} else {
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Italic stack underflow\n") );
|
|
}
|
|
}
|
|
|
|
static void PushAttributes( HTStructured * me, const char *align )
|
|
{
|
|
PushFontInfo( me );
|
|
PushBoldInfo( me );
|
|
PushItalicInfo( me );
|
|
CenterSetValue( me, align, TRUE );
|
|
}
|
|
|
|
static void PopAttributes( HTStructured * me )
|
|
{
|
|
PopFontInfo( me );
|
|
PopBoldInfo( me );
|
|
PopItalicInfo( me );
|
|
CenterSetValue( me, NULL, TRUE );
|
|
}
|
|
|
|
//
|
|
// Initialize the style state
|
|
//
|
|
// Note:
|
|
// There are two reasons this function will get called. The first is when the
|
|
// HTML stream is created, in which case it initializes the "current" style
|
|
// info as appropriate for the start of a document. The second is when a new
|
|
// table cell is being started. Essentially, each table cell behaves much like a
|
|
// miniature HTML doc, and therefore needs to start out with the same defaults
|
|
// as a document.
|
|
//
|
|
static void InitStyleState( HTStructured *me, BOOL new_doc )
|
|
{
|
|
me->ss.new_style = HTML_STYLE_NORMAL;
|
|
|
|
me->ss.sp = me->ss.stack + MAX_NESTING - 1;
|
|
me->ss.sp->tag_number = -1; /* INVALID */
|
|
me->ss.sp->style = HTML_STYLE_NORMAL; /* INVALID */
|
|
|
|
me->ss.font_sp = me->ss.font_stack + MAX_NESTING - 1;
|
|
|
|
me->ss.center_sp = me->ss.center_stack + MAX_NESTING - 1;
|
|
me->ss.center_sp->bCenter = FALSE;
|
|
|
|
me->ss.bDefaultCenterValue = FALSE;
|
|
|
|
me->ss.bold_sp = me->ss.bold_stack + MAX_NESTING - 1;
|
|
me->ss.bold_sp->bBold = FALSE;
|
|
|
|
me->ss.italic_sp = me->ss.italic_stack + MAX_NESTING - 1;
|
|
me->ss.italic_sp->bItalic = FALSE;
|
|
|
|
me->ss.bLastPoppedBold = FALSE;
|
|
me->ss.bLastPoppedItalic = FALSE;
|
|
|
|
if ( me->text ) {
|
|
me->text->iStyle = 0;
|
|
me->text->fontBits = 0;
|
|
me->text->bCenter = FALSE;
|
|
me->text->bBold = FALSE;
|
|
me->text->bItalic = FALSE;
|
|
me->text->bNoBreak = FALSE;
|
|
me->text->bNeedListCRLF = FALSE;
|
|
me->text->bNewPara = TRUE;
|
|
me->text->bOnNewPara = TRUE;
|
|
me->text->baseFontSize = DEFAULT_HTML_FONT_SIZE;
|
|
me->text->fontSize = DEFAULT_FONT_SIZE;
|
|
if ( new_doc ) {
|
|
me->text->fontFace = DEFAULT_FONT_FACE;
|
|
me->text->fontColor = (COLORREF)-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PushStyleState( HTStructured *me )
|
|
{
|
|
STYLESTATE *new_ss = GTR_MALLOC( sizeof(*new_ss) );
|
|
|
|
if ( new_ss ) {
|
|
// get current text fields
|
|
me->ss.iStyle = me->text->iStyle;
|
|
me->ss.fontBits = me->text->fontBits;
|
|
me->ss.bCenter = me->text->bCenter;
|
|
me->ss.bBold = me->text->bBold;
|
|
me->ss.bItalic = me->text->bItalic;
|
|
me->ss.bNoBreak = me->text->bNoBreak;
|
|
me->ss.bNeedListCRLF = me->text->bNeedListCRLF;
|
|
me->ss.bNewPara = me->text->bNewPara;
|
|
me->ss.bOnNewPara = me->text->bOnNewPara;
|
|
me->ss.baseFontSize = me->text->baseFontSize;
|
|
me->ss.fontSize = me->text->fontSize;
|
|
me->ss.fontFace = me->text->fontFace;
|
|
me->ss.fontColor = me->text->fontColor;
|
|
|
|
*new_ss = me->ss;
|
|
|
|
me->ss.next = new_ss;
|
|
}
|
|
}
|
|
|
|
BOOL PopStyleState( HTStructured *me )
|
|
{
|
|
if ( me->ss.next ) {
|
|
STYLESTATE *old_ss = me->ss.next;
|
|
|
|
// BUGBUG perf: only need to copy what's being used,
|
|
me->ss = *old_ss;
|
|
GTR_FREE( old_ss );
|
|
|
|
// restore text fields
|
|
me->text->iStyle = me->ss.iStyle;
|
|
me->text->fontBits = me->ss.fontBits ;
|
|
me->text->bCenter = me->ss.bCenter;
|
|
me->text->bBold = me->ss.bBold;
|
|
me->text->bItalic = me->ss.bItalic;
|
|
me->text->bNoBreak = me->ss.bNoBreak;
|
|
me->text->bNeedListCRLF = me->ss.bNeedListCRLF;
|
|
me->text->bNewPara = me->ss.bNewPara;
|
|
me->text->bOnNewPara = me->ss.bOnNewPara;
|
|
me->text->baseFontSize = me->ss.baseFontSize;
|
|
me->text->fontSize = me->ss.fontSize;
|
|
me->text->fontFace = me->ss.fontFace;
|
|
me->text->fontColor = me->ss.fontColor;
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* Style buffering avoids dummy paragraph begin/ends.
|
|
*/
|
|
#define UPDATE_STYLE if (me->style_change) { actually_set_style(me) ; }
|
|
|
|
|
|
/* Set character set
|
|
** ----------------
|
|
*/
|
|
|
|
char *x_ExpandRelativeAnchor(const char *rel, const char *base)
|
|
{
|
|
char *pTemp = 0;
|
|
char *stripped;
|
|
char *result = NULL;
|
|
|
|
if (!rel)
|
|
{
|
|
rel = "";
|
|
}
|
|
|
|
pTemp = GTR_strdup(rel);
|
|
stripped = HTStrip(pTemp);
|
|
result = HTParse(stripped, base, PARSE_PUNCTUATION | PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_ANCHOR);
|
|
GTR_FREE(pTemp);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determine if any enclosing block has a style with the given attribute
|
|
//
|
|
// On entry:
|
|
// me: self stack
|
|
// bit_to_check: either FONTBIT_BOLD, or FONTBIT_ITALIC, neither means freeFormat setting
|
|
//
|
|
// Returns:
|
|
// TRUE -> an enclosing block uses a style that has the given attribute set
|
|
// FALSE -> no enclosing block uses a style that has the given attribute set
|
|
//
|
|
// Note: This hack was made to emulate another popular Web browser.
|
|
//
|
|
PRIVATE BOOL StackedStyleHasAttr(HTStructured * me, int bit_to_check )
|
|
{
|
|
stack_element *sp = me->ss.sp;
|
|
extern int HTMLStyleBoldTable[COUNT_HTML_STYLES];
|
|
extern int HTMLStyleItalicsTable[COUNT_HTML_STYLES];
|
|
|
|
while ( sp != me->ss.stack + MAX_NESTING - 1 ) {
|
|
if ( bit_to_check == FONTBIT_BOLD ) {
|
|
if ( HTMLStyleBoldTable[sp->style] )
|
|
return TRUE;
|
|
} else if ( bit_to_check == FONTBIT_ITALIC ) {
|
|
if ( HTMLStyleItalicsTable[sp->style] )
|
|
return TRUE;
|
|
} else {
|
|
if ( !me->text->w3doc->pStyles->sty[sp->style]->freeFormat )
|
|
return TRUE;
|
|
}
|
|
sp++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* If style really needs to be set, call this
|
|
*/
|
|
PRIVATE void actually_set_style(HTStructured * me)
|
|
{
|
|
HText_setStyle(me->text, me->ss.new_style);
|
|
if ( me->ss.bLastPoppedBold || StackedStyleHasAttr( me, FONTBIT_BOLD ) )
|
|
me->text->fontBits |= FONTBIT_BOLD;
|
|
if ( me->ss.bLastPoppedItalic || StackedStyleHasAttr( me, FONTBIT_ITALIC ) )
|
|
me->text->fontBits |= FONTBIT_ITALIC;
|
|
me->text->freeFormat = !StackedStyleHasAttr( me, 0 );
|
|
|
|
me->style_change = NO;
|
|
#ifdef KEEP_A_SPACE
|
|
if (me->space_pending) HText_appendCharacter(me->text, ' ');
|
|
me->space_pending = NO;
|
|
me->do_space_pending = NO;
|
|
#endif
|
|
}
|
|
|
|
/* If you THINK you need to change style, call this
|
|
*/
|
|
|
|
PRIVATE void change_paragraph_style(HTStructured * me, int style)
|
|
{
|
|
if (me->ss.new_style != style)
|
|
{
|
|
me->style_change = YES;
|
|
#ifdef KEEP_A_SPACE
|
|
me->space_pending = NO;
|
|
me->do_space_pending = NO;
|
|
#endif
|
|
me->ss.new_style = style;
|
|
}
|
|
}
|
|
|
|
/*_________________________________________________________________________
|
|
**
|
|
** A C T I O N R O U T I N E S
|
|
*/
|
|
|
|
/* Character handling
|
|
** ------------------
|
|
*/
|
|
PRIVATE void HTML_put_character(HTStructured * me, char c)
|
|
{
|
|
|
|
|
|
switch (me->ss.sp[0].tag_number)
|
|
{
|
|
case HTML_COMMENT:
|
|
break; /* Do Nothing */
|
|
|
|
case HTML_TITLE:
|
|
if (IS_SPACE(c))
|
|
{
|
|
c = ' ';
|
|
}
|
|
HTChunkPutc(&me->title, c);
|
|
break;
|
|
|
|
case HTML_MARQUEE:
|
|
if (IS_SPACE(c))
|
|
{
|
|
c = ' ';
|
|
}
|
|
// don't party on if its NULL, since we could
|
|
// have poorly formated HTML, we shouldn't crash
|
|
if ( me->martext )
|
|
HTChunkPutc( me->martext, c);
|
|
|
|
break;
|
|
|
|
case HTML_LISTING: /* Litteral text */
|
|
case HTML_XMP:
|
|
case HTML_PLAINTEXT:
|
|
case HTML_PRE:
|
|
case HTML_TEXTAREA:
|
|
|
|
UPDATE_STYLE;
|
|
HText_appendCharacter(me->text, c);
|
|
break;
|
|
|
|
default: /* Free format text */
|
|
// check to see if we're really free format
|
|
if ( !me->text->freeFormat ) {
|
|
UPDATE_STYLE;
|
|
HText_appendCharacter(me->text, c);
|
|
return;
|
|
}
|
|
|
|
if ( (me->text->tableState == TS_IN_LIMBO) && IS_SPACE(c) )
|
|
return; // throw away spaces when we're in limbo
|
|
|
|
if (me->style_change || me->do_space_pending )
|
|
{
|
|
if (IS_SPACE(c))
|
|
{
|
|
#ifdef KEEP_A_SPACE
|
|
me->space_pending = YES;
|
|
#endif
|
|
return; /* Ignore it */
|
|
} else {
|
|
me->do_space_pending = NO;
|
|
}
|
|
UPDATE_STYLE;
|
|
}
|
|
if (c == '\n')
|
|
{
|
|
HText_appendCharacter(me->text, ' ');
|
|
}
|
|
else
|
|
{
|
|
HText_appendCharacter(me->text, c);
|
|
}
|
|
} /* end switch */
|
|
}
|
|
|
|
|
|
#ifdef FEATURE_INTL
|
|
/*********************************************************************/
|
|
/* Function: EncodeMBCSString */
|
|
/* */
|
|
/* Convert string to target PC character if it have DBCS character */
|
|
/* */
|
|
/* Return: points to string buffer including convered string */
|
|
/* */
|
|
/* Arguments: */
|
|
/* CONST char *s points to the original string */
|
|
/* */
|
|
/* int *l points to an integer to receive */
|
|
/* a count of the length of converted */
|
|
/* string. */
|
|
/* First, this integer value contain */
|
|
/* a count of the length of original */
|
|
/* string. */
|
|
/* If first value is NULL, we handle */
|
|
/* original string as NULL terminated */
|
|
/* string. */
|
|
/* */
|
|
/* MIMECSETTBL *pMime */
|
|
/* points to aMimeCharSet[iMimeCharSet]*/
|
|
/* */
|
|
/*********************************************************************/
|
|
CONST char *EncodeMBCSString(CONST char *s, int *l, MIMECSETTBL *pMime)
|
|
{
|
|
int len;
|
|
UCHAR *pPCChar;
|
|
int nEncodingMode = pMime->iChrCnv - 1;
|
|
|
|
/* get required size to call this function setting 0 to PCChar_len */
|
|
/* If set -1 to CodePage, FECHRCNV.DLL set it automatically */
|
|
len = UNIX_to_PC(pMime->CodePage, nEncodingMode, (UCHAR *)s, *l, NULL, 0);
|
|
|
|
/* alloc destination buffer */
|
|
/* this memory block will be freed at caller function */
|
|
pPCChar = (UCHAR *)GTR_MALLOC(len);
|
|
|
|
/* convert MBCS string actually */
|
|
*l = UNIX_to_PC(pMime->CodePage, nEncodingMode, (UCHAR *)s, *l, pPCChar, len);
|
|
|
|
return (CONST char *)pPCChar;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* Function: DecodeMBCSString */
|
|
/* */
|
|
/* Convert string to target UNIX character if it have DBCS character */
|
|
/* */
|
|
/* Return: length of string buffer including convered string */
|
|
/* */
|
|
/* Arguments: */
|
|
/* CONST char *s points to the convert string */
|
|
/* */
|
|
/* int *l points to an integer to receive */
|
|
/* a count of the length of converted */
|
|
/* string. */
|
|
/* First, this integer value contain */
|
|
/* a count of the length of original */
|
|
/* string. */
|
|
/* If first value is NULL, we handle */
|
|
/* original string as NULL terminated */
|
|
/* string. */
|
|
/* */
|
|
/* MIMECSETTBL *pMime */
|
|
/* points to aMimeCharSet[iMimeCharSet]*/
|
|
/* */
|
|
/*********************************************************************/
|
|
CONST char *DecodeMBCSString(CONST char *s, int *l, MIMECSETTBL *pMime)
|
|
{
|
|
int len;
|
|
UCHAR *pUNIXChar;
|
|
int nEncodingMode = pMime->iChrCnv - 1;
|
|
|
|
if(nEncodingMode == CODE_UNKNOWN)
|
|
nEncodingMode = FCC_GetCurrentEncodingMode();
|
|
|
|
if(nEncodingMode == CODE_UNKNOWN) // don't convert
|
|
return s;
|
|
|
|
/* get required size to call this function setting 0 to PCChar_len */
|
|
/* If set -1 to CodePage, FECHRCNV.DLL set it automatically */
|
|
len = PC_to_UNIX(pMime->CodePage, nEncodingMode, (UCHAR *)s, *l, NULL, 0);
|
|
|
|
/* alloc destination buffer */
|
|
/* this memory block will be freed at caller function */
|
|
pUNIXChar = (UCHAR *)GTR_MALLOC(len + 1);
|
|
|
|
/* convert MBCS string actually */
|
|
*l = PC_to_UNIX(pMime->CodePage, nEncodingMode, (UCHAR *)s, *l, pUNIXChar, len);
|
|
|
|
GTR_FREE((UCHAR *)s); // _BUGBUG: is this safe?
|
|
return (CONST char *)pUNIXChar;
|
|
}
|
|
#endif
|
|
|
|
/* String handling
|
|
** ---------------
|
|
**
|
|
** This is written separately from put_character becuase the loop can
|
|
** in some cases be promoted to a higher function call level for speed.
|
|
*/
|
|
PRIVATE void HTML_put_string(HTStructured * me, CONST char *s)
|
|
{
|
|
#ifdef FEATURE_INTL
|
|
CONST char *pPCChar = NULL;
|
|
int len = -1;
|
|
MIMECSETTBL *pMime = aMimeCharSet + me->text->w3doc->iMimeCharSet;
|
|
#endif
|
|
|
|
switch (me->ss.sp[0].tag_number)
|
|
{
|
|
case HTML_COMMENT:
|
|
break; /* Do Nothing */
|
|
|
|
case HTML_TITLE:
|
|
#ifdef FEATURE_INTL
|
|
if (pMime->iChrCnv)
|
|
{
|
|
pPCChar = EncodeMBCSString(s, &len, pMime);
|
|
s = pPCChar;
|
|
}
|
|
#endif
|
|
HTChunkPuts(&me->title, s);
|
|
break;
|
|
case HTML_MARQUEE:
|
|
// don't do this unless we know its NULL
|
|
// since we can party on a NULL pointer
|
|
if ( me->martext )
|
|
#ifdef FEATURE_INTL
|
|
if (pMime->iChrCnv)
|
|
{
|
|
pPCChar = EncodeMBCSString(s, &len, pMime);
|
|
s = pPCChar;
|
|
}
|
|
#endif
|
|
HTChunkPuts( me->martext, s);
|
|
break;
|
|
|
|
case HTML_LISTING: /* Literal text */
|
|
case HTML_XMP:
|
|
case HTML_PLAINTEXT:
|
|
case HTML_PRE:
|
|
case HTML_TEXTAREA:
|
|
|
|
UPDATE_STYLE;
|
|
#ifdef FEATURE_INTL
|
|
if (pMime->iChrCnv)
|
|
{
|
|
pPCChar = EncodeMBCSString(s, &len, pMime);
|
|
s = pPCChar;
|
|
}
|
|
#endif
|
|
HText_appendText(me->text, s);
|
|
break;
|
|
|
|
default: /* Free format text */
|
|
#ifdef FEATURE_INTL
|
|
if (pMime->iChrCnv)
|
|
{
|
|
pPCChar = EncodeMBCSString(s, &len, pMime);
|
|
s = pPCChar;
|
|
}
|
|
#endif
|
|
{
|
|
CONST char *p = s;
|
|
|
|
// check to see if we're really free format
|
|
if ( !me->text->freeFormat ) {
|
|
UPDATE_STYLE;
|
|
HText_appendText(me->text, s);
|
|
#ifdef FEATURE_INTL
|
|
goto done;
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
if (me->style_change)
|
|
{
|
|
for (; *p && IS_SPACE(*p); p++) ; /* Ignore leaders */
|
|
if (!*p)
|
|
{
|
|
#ifdef KEEP_A_SPACE
|
|
if (p != s) me->space_pending = YES;
|
|
#endif
|
|
#ifdef FEATURE_INTL
|
|
goto done;
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
UPDATE_STYLE;
|
|
}
|
|
for (; *p; p++)
|
|
{
|
|
if (me->style_change)
|
|
{
|
|
if (IS_SPACE(*p))
|
|
{
|
|
#ifdef KEEP_A_SPACE
|
|
me->space_pending = YES;
|
|
#endif
|
|
continue; /* Ignore it */
|
|
}
|
|
UPDATE_STYLE;
|
|
}
|
|
if (*p == '\n')
|
|
{
|
|
HText_appendCharacter(me->text, ' ');
|
|
}
|
|
else
|
|
{
|
|
HText_appendCharacter(me->text, *p);
|
|
}
|
|
} /* for */
|
|
}
|
|
} /* end switch */
|
|
#ifdef FEATURE_INTL
|
|
done:
|
|
if(pPCChar)
|
|
GTR_FREE((UCHAR *)pPCChar);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Buffer write
|
|
** ------------
|
|
*/
|
|
PRIVATE void HTML_write(HTStructured * me, CONST char *s, int l)
|
|
{
|
|
CONST char *p;
|
|
CONST char *e = s + l;
|
|
#ifdef FEATURE_INTL
|
|
CONST char *pPCChar = s;
|
|
int len = l;
|
|
MIMECSETTBL *pMime = aMimeCharSet + me->text->w3doc->iMimeCharSet;
|
|
|
|
if (pMime->iChrCnv)
|
|
{
|
|
pPCChar = EncodeMBCSString(s, &len, pMime);
|
|
e = pPCChar + len;
|
|
}
|
|
for (p = pPCChar; p < e; ++p)
|
|
HTML_put_character(me, *p);
|
|
if (pPCChar != s)
|
|
GTR_FREE((UCHAR *)pPCChar);
|
|
#else
|
|
for (p = s; s < e; p++)
|
|
HTML_put_character(me, *p);
|
|
#endif
|
|
}
|
|
|
|
/* Start Element
|
|
** -------------
|
|
*/
|
|
PRIVATE void HTML_start_element(HTStructured * me, int element_number, CONST BOOL * present, CONST char **value)
|
|
{
|
|
#ifdef FEATURE_INTL
|
|
CHARSETINFO csetinfo;
|
|
int default_cp;
|
|
MIMECSETTBL *pMime = aMimeCharSet + me->text->w3doc->iMimeCharSet;
|
|
#endif
|
|
XX_DMsg(DBG_SGML, ("HTML_start_element: %s\n", me->dtd->tags[element_number].name));
|
|
|
|
switch (element_number)
|
|
{
|
|
case HTML_DL:
|
|
case HTML_UL:
|
|
case HTML_OL:
|
|
case HTML_MENU:
|
|
case HTML_DIR:
|
|
#ifdef FEATURE_INTL
|
|
case HTML_ENTITY:
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
HText_addListCRLF(me->text);
|
|
}
|
|
|
|
switch (element_number)
|
|
{
|
|
#ifdef FEATURE_OCX
|
|
case HTML_EMBED:
|
|
|
|
// Do initialization stuff
|
|
if (present[HTML_EMBED_CLSID])
|
|
HText_beginEmbed(value[HTML_EMBED_CLSID]);
|
|
|
|
// Add to element list for layout purposes
|
|
HText_addEmbed(me->text,
|
|
(present[HTML_EMBED_CLSID] ? value[HTML_EMBED_CLSID] : NULL),
|
|
(present[HTML_EMBED_EVENTS] ? value[HTML_EMBED_EVENTS] : NULL),
|
|
(present[HTML_EMBED_HEIGHT] ? value[HTML_EMBED_HEIGHT] : NULL),
|
|
(present[HTML_EMBED_NAME] ? value[HTML_EMBED_NAME] : NULL),
|
|
(present[HTML_EMBED_PROGID] ? value[HTML_EMBED_PROGID] : NULL),
|
|
(present[HTML_EMBED_PROPERTIES] ? value[HTML_EMBED_PROPERTIES] : NULL),
|
|
(present[HTML_EMBED_PROPERTYSRC] ? value[HTML_EMBED_PROPERTYSRC] : NULL),
|
|
(present[HTML_EMBED_SINK] ? value[HTML_EMBED_SINK] : NULL),
|
|
(present[HTML_EMBED_SRC] ? value[HTML_EMBED_SRC] : NULL),
|
|
(present[HTML_EMBED_WIDTH] ? value[HTML_EMBED_WIDTH] : NULL)
|
|
);
|
|
break;
|
|
#endif
|
|
case HTML_BASE:
|
|
if (present[HTML_BASE_HREF] && value[HTML_BASE_HREF])
|
|
{
|
|
char *mycopy = 0;
|
|
char *stripped;
|
|
|
|
mycopy = GTR_strdup(value[HTML_BASE_HREF]);
|
|
stripped = HTStrip(mycopy);
|
|
GTR_strncpy(me->base_url, stripped, MAX_URL_STRING);
|
|
GTR_FREE(mycopy);
|
|
}
|
|
break;
|
|
|
|
case HTML_FORM:
|
|
{
|
|
char *addr = 0;
|
|
char *method;
|
|
|
|
method = NULL;
|
|
if (present[HTML_FORM_METHOD])
|
|
{
|
|
method = (char *) value[HTML_FORM_METHOD];
|
|
}
|
|
|
|
if (present[HTML_FORM_ACTION])
|
|
{
|
|
addr = x_ExpandRelativeAnchor(value[HTML_FORM_ACTION], me->base_url);
|
|
}
|
|
else
|
|
{
|
|
addr = me->base_url;
|
|
}
|
|
|
|
HText_beginForm(me->text, addr, method);
|
|
if (present[HTML_FORM_ACTION])
|
|
GTR_FREE(addr);
|
|
}
|
|
break;
|
|
case HTML_INPUT:
|
|
{
|
|
char *src = 0;
|
|
|
|
if (present[HTML_INPUT_SRC])
|
|
{
|
|
src = x_ExpandRelativeAnchor(value[HTML_INPUT_SRC], me->base_url);
|
|
}
|
|
UPDATE_STYLE;
|
|
HText_addInput(me->text,
|
|
present[HTML_INPUT_CHECKED],
|
|
present[HTML_INPUT_DISABLED],
|
|
(present[HTML_INPUT_MAX] ? value[HTML_INPUT_MAX] : NULL),
|
|
(present[HTML_INPUT_MIN] ? value[HTML_INPUT_MIN] : NULL),
|
|
(present[HTML_INPUT_NAME] ? value[HTML_INPUT_NAME] : NULL),
|
|
(present[HTML_INPUT_SIZE] ? value[HTML_INPUT_SIZE] : NULL),
|
|
(present[HTML_INPUT_TYPE] ? value[HTML_INPUT_TYPE] : NULL),
|
|
(present[HTML_INPUT_VALUE] ? value[HTML_INPUT_VALUE] : NULL),
|
|
(present[HTML_INPUT_MAXLENGTH] ? value[HTML_INPUT_MAXLENGTH] : NULL),
|
|
(present[HTML_INPUT_ALIGN] ? value[HTML_INPUT_ALIGN] : NULL),
|
|
src
|
|
);
|
|
|
|
if (src)
|
|
GTR_FREE(src);
|
|
}
|
|
break;
|
|
case HTML_SELECT:
|
|
{
|
|
UPDATE_STYLE;
|
|
HText_beginSelect(me->text,
|
|
(present[HTML_SELECT_NAME] ? value[HTML_SELECT_NAME] : NULL),
|
|
present[HTML_SELECT_MULTIPLE],
|
|
(present[HTML_SELECT_SIZE] ? value[HTML_SELECT_SIZE] : NULL)
|
|
);
|
|
}
|
|
break;
|
|
case HTML_OPTION:
|
|
{
|
|
HText_addOption(me->text,
|
|
present[HTML_OPTION_SELECTED],
|
|
(char *) (present[HTML_OPTION_VALUE] ? value[HTML_OPTION_VALUE] : NULL)
|
|
);
|
|
}
|
|
break;
|
|
case HTML_TEXTAREA:
|
|
{
|
|
UPDATE_STYLE;
|
|
HText_beginTextArea(me->text,
|
|
(present[HTML_TEXTAREA_COLS] ? value[HTML_TEXTAREA_COLS] : NULL),
|
|
(present[HTML_TEXTAREA_NAME] ? value[HTML_TEXTAREA_NAME] : NULL),
|
|
(present[HTML_TEXTAREA_ROWS] ? value[HTML_TEXTAREA_ROWS] : NULL)
|
|
);
|
|
}
|
|
break;
|
|
case HTML_A:
|
|
{
|
|
char *name = NULL;
|
|
char *href = NULL;
|
|
char *size = NULL;
|
|
BOOL bFreeIt = FALSE;
|
|
|
|
UPDATE_STYLE;
|
|
|
|
if (present[HTML_A_HREF] && value[HTML_A_HREF])
|
|
{
|
|
href = (char *) value[HTML_A_HREF];
|
|
if (href[0] != '#')
|
|
{
|
|
href = x_ExpandRelativeAnchor(href, me->base_url);
|
|
bFreeIt = TRUE;
|
|
}
|
|
}
|
|
if (present[HTML_A_NAME])
|
|
{
|
|
name = (char *) value[HTML_A_NAME];
|
|
}
|
|
if (present[HTML_A_X_SIZE])
|
|
{
|
|
size = (char *) value[HTML_A_X_SIZE];
|
|
}
|
|
HText_beginAnchor(me->text, href, name, size, present[HTML_A_NOCACHE]);
|
|
if (bFreeIt)
|
|
{
|
|
GTR_FREE(href);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HTML_TITLE:
|
|
HTChunkClear(&me->title);
|
|
break;
|
|
|
|
case HTML_NEXTID:
|
|
/* if (present[NEXTID_N] && value[NEXTID_N])
|
|
HText_setNextId(me->text, atoi(value[NEXTID_N])); */
|
|
break;
|
|
|
|
|
|
case HTML_ISINDEX:
|
|
{
|
|
/* BUGBUG: Note that we have a known bug here:
|
|
If a <BASE> tag appears after an <ISINDEX> tag, the action will be
|
|
based of the document's URL rather than the base HREF.
|
|
*/
|
|
UPDATE_STYLE;
|
|
|
|
/* We can wind up here from gopher processing, which just passes NULLs
|
|
for the present and value arrays, so make sure they're valid. */
|
|
#ifdef FEATURE_INTL
|
|
// This is needed because we'll load a localized string for
|
|
// the default prompt case. So this works only in case
|
|
// 1) we got localized, 2) we're on different locale
|
|
// (codepage) than the user's default.
|
|
|
|
if(!(present && present[HTML_ISINDEX_PROMPT]))
|
|
{
|
|
if((default_cp=MapLangToCP(GetUserDefaultLCID())) != pMime->CodePage)
|
|
{
|
|
ForceFontChange( me, STY_GetCPDefaultTypeFace(proportional, default_cp), DEFAULT_CHARSET);
|
|
}
|
|
}
|
|
#endif
|
|
if (present && present[HTML_ISINDEX_ACTION] && value[HTML_ISINDEX_ACTION])
|
|
{
|
|
char *action;
|
|
|
|
action = NULL;
|
|
action = x_ExpandRelativeAnchor(value[HTML_ISINDEX_ACTION], me->base_url);
|
|
HText_setIndex(me->text, action,
|
|
((present && present[HTML_ISINDEX_PROMPT]) ? value[HTML_ISINDEX_PROMPT] : NULL)
|
|
);
|
|
GTR_FREE(action);
|
|
}
|
|
else
|
|
{
|
|
HText_setIndex(me->text, me->base_url,
|
|
((present && present[HTML_ISINDEX_PROMPT]) ? value[HTML_ISINDEX_PROMPT] : NULL)
|
|
);
|
|
}
|
|
#ifdef FEATURE_INTL
|
|
if(!(present && present[HTML_ISINDEX_PROMPT]))
|
|
{
|
|
if (default_cp != pMime->CodePage)
|
|
ForceFontChange( me, NULL, 0 );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case HTML_BGSOUND:
|
|
{
|
|
char *src = NULL;
|
|
|
|
// expand if its a relative link
|
|
if ( present[HTML_BGSOUND_SRC] )
|
|
src = x_ExpandRelativeAnchor(value[HTML_BGSOUND_SRC], me->base_url);
|
|
|
|
HText_beginBGSound(me->text,
|
|
(present[HTML_BGSOUND_LOOP] ? value[HTML_BGSOUND_LOOP] : NULL),
|
|
src,
|
|
(present[HTML_BGSOUND_START] ? value[HTML_BGSOUND_START] : NULL)
|
|
);
|
|
if ( src )
|
|
GTR_FREE( src );
|
|
|
|
break;
|
|
}
|
|
case HTML_BR:
|
|
UPDATE_STYLE;
|
|
HText_appendCRLF(me->text);
|
|
HText_SetBRClearType( me->text,
|
|
((present && present[HTML_BR_CLEAR]) ? value[HTML_BR_CLEAR] : NULL) );
|
|
me->bSeenBrInCell = TRUE;
|
|
break;
|
|
|
|
case HTML_FETCH:
|
|
HText_beginFetch(me->text,
|
|
(present[HTML_FETCH_DESC] ? value[HTML_FETCH_DESC] : NULL),
|
|
(present[HTML_FETCH_GUID] ? value[HTML_FETCH_GUID] : NULL),
|
|
(present[HTML_FETCH_REQUIRED] ? value[HTML_FETCH_REQUIRED] : NULL),
|
|
(present[HTML_FETCH_SRC] ? value[HTML_FETCH_SRC] : NULL),
|
|
(present[HTML_FETCH_TS] ? value[HTML_FETCH_TS] : NULL)
|
|
);
|
|
break;
|
|
|
|
case HTML_FONT:
|
|
UPDATE_STYLE;
|
|
PushFontInfo( me );
|
|
#ifdef FEATURE_INTL
|
|
TranslateCharsetInfo((LPDWORD)GETMIMECP(me->text->w3doc), &csetinfo, TCI_SRCCODEPAGE);
|
|
#endif
|
|
HText_beginSetFont(me->text, FALSE,
|
|
(present[HTML_FONT_COLOR] ? value[HTML_FONT_COLOR] : NULL),
|
|
(present[HTML_FONT_SIZE] ? value[HTML_FONT_SIZE] : NULL),
|
|
(present[HTML_FONT_FACE] ? value[HTML_FONT_FACE] : NULL)
|
|
#ifdef FEATURE_INTL
|
|
, csetinfo.ciCharset
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
case HTML_BASEFONT:
|
|
UPDATE_STYLE;
|
|
PushFontInfo( me );
|
|
#ifdef FEATURE_INTL
|
|
TranslateCharsetInfo((LPDWORD)GETMIMECP(me->text->w3doc), &csetinfo, TCI_SRCCODEPAGE);
|
|
#endif
|
|
HText_beginSetFont(me->text, TRUE,
|
|
(present[HTML_FONT_COLOR] ? value[HTML_FONT_COLOR] : NULL),
|
|
(present[HTML_FONT_SIZE] ? value[HTML_FONT_SIZE] : NULL),
|
|
(present[HTML_FONT_FACE] ? value[HTML_FONT_FACE] : NULL)
|
|
#ifdef FEATURE_INTL
|
|
, csetinfo.ciCharset
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
case HTML_NOBR:
|
|
UPDATE_STYLE;
|
|
HText_beginNoBreak(me->text);
|
|
break;
|
|
|
|
case HTML_WBR:
|
|
UPDATE_STYLE;
|
|
HText_WordBreak(me->text);
|
|
break;
|
|
|
|
case HTML_CENTER:
|
|
UPDATE_STYLE;
|
|
PushCenterInfo( me, me->text->bCenter );
|
|
HText_beginCenter(me->text);
|
|
if ( !me->text->bOnNewPara )
|
|
HText_appendCRLF(me->text);
|
|
break;
|
|
|
|
case HTML_HR:
|
|
UPDATE_STYLE;
|
|
HText_appendHorizontalRule(me->text,
|
|
(present[HTML_HR_ALIGN] ? value[HTML_HR_ALIGN] : NULL),
|
|
(present[HTML_HR_SIZE] ? value[HTML_HR_SIZE] : NULL),
|
|
(present[HTML_HR_WIDTH] ? value[HTML_HR_WIDTH] : NULL),
|
|
present[HTML_HR_NOSHADE] );
|
|
break;
|
|
|
|
case HTML_P:
|
|
if ( me->text->tableState != TS_IN_LIMBO ) {
|
|
UPDATE_STYLE;
|
|
CenterSetValue( me, present[HTML_L_ALIGN] ? value[HTML_L_ALIGN] : NULL, FALSE );
|
|
HText_appendParagraph(me->text);
|
|
}
|
|
break;
|
|
|
|
case HTML_TABLE:
|
|
if ( !HText_IsFloating( present[HTML_TABLE_ALIGN] ? value[HTML_TABLE_ALIGN] : NULL ) )
|
|
if ( !me->text->bOnNewPara )
|
|
HText_appendCRLF(me->text);
|
|
UPDATE_STYLE;
|
|
if ( me->text->tableState == TS_IN_LIMBO ) {
|
|
HText_beginFrame(me->text, ELE_FRAME_IS_CELL,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
|
|
}
|
|
|
|
HText_beginFrame(me->text,
|
|
ELE_FRAME_IS_TABLE,
|
|
present[HTML_TABLE_ALIGN] ? value[HTML_TABLE_ALIGN] : NULL,
|
|
present[HTML_TABLE_BGCOLOR] ? value[HTML_TABLE_BGCOLOR] : NULL,
|
|
present[HTML_TABLE_BORDER] ?
|
|
(value[HTML_TABLE_BORDER] ? value[HTML_TABLE_BORDER] : "" ): NULL,
|
|
present[HTML_TABLE_BORDERCOLOR] ? value[HTML_TABLE_BORDERCOLOR] : NULL,
|
|
present[HTML_TABLE_BORDERCOLORDARK] ? value[HTML_TABLE_BORDERCOLORDARK] : NULL,
|
|
present[HTML_TABLE_BORDERCOLORLIGHT] ? value[HTML_TABLE_BORDERCOLORLIGHT] : NULL,
|
|
present[HTML_TABLE_CELLPADDING] ? value[HTML_TABLE_CELLPADDING] : NULL,
|
|
present[HTML_TABLE_CELLSPACING] ? value[HTML_TABLE_CELLSPACING] : NULL,
|
|
present[HTML_TABLE_NOWRAP] ?
|
|
(value[HTML_TABLE_NOWRAP] ? value[HTML_TABLE_NOWRAP] : "" ): NULL,
|
|
present[HTML_TABLE_WIDTH] ? value[HTML_TABLE_WIDTH] : NULL,
|
|
present[HTML_TABLE_VALIGN] ? value[HTML_TABLE_VALIGN] : NULL,
|
|
NULL,
|
|
NULL,
|
|
present[HTML_TABLE_HEIGHT] ? value[HTML_TABLE_HEIGHT] : NULL
|
|
);
|
|
change_paragraph_style(me, HTML_STYLE_NORMAL);
|
|
InitStyleState( me, FALSE );
|
|
me->do_space_pending = YES;
|
|
if ( present[HTML_TABLE_NOWRAP] )
|
|
HText_beginNoBreak( me->text );
|
|
break;
|
|
|
|
case HTML_TR:
|
|
if ( me->text->tableState != TS_NOT_IN_TABLE ) {
|
|
// If we see a <TR> while we're in a cell, this implies a missing </TD>
|
|
if ( me->text->tableState == TS_IN_CELL )
|
|
HText_endFrame(me->text, ELE_FRAME_IS_CELL, NULL);
|
|
|
|
me->text->bPendingTR = FALSE;
|
|
HText_beginRow(me->text,
|
|
present[HTML_TR_ALIGN] ? value[HTML_TR_ALIGN] : NULL,
|
|
present[HTML_TR_BGCOLOR] ? value[HTML_TR_BGCOLOR] : NULL,
|
|
present[HTML_TR_BORDERCOLOR] ? value[HTML_TR_BORDERCOLOR] : NULL,
|
|
present[HTML_TR_BORDERCOLORDARK] ? value[HTML_TR_BORDERCOLORDARK] : NULL,
|
|
present[HTML_TR_BORDERCOLORLIGHT] ? value[HTML_TR_BORDERCOLORLIGHT] : NULL,
|
|
present[HTML_TR_VALIGN] ? value[HTML_TR_VALIGN] : NULL,
|
|
present[HTML_TR_NOWRAP] ? value[HTML_TR_NOWRAP] : NULL
|
|
);
|
|
}
|
|
break;
|
|
|
|
case HTML_CAPTION:
|
|
if ( me->text->tableState != TS_NOT_IN_TABLE ) {
|
|
HText_beginFrame(me->text,
|
|
ELE_FRAME_IS_CELL | ELE_FRAME_IS_CAPTION_CELL,
|
|
present[HTML_CAPTION_ALIGN] ? value[HTML_CAPTION_ALIGN] : NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
present[HTML_CAPTION_VALIGN] ? value[HTML_CAPTION_VALIGN] : NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
change_paragraph_style(me, HTML_STYLE_NORMAL);
|
|
InitStyleState( me, FALSE );
|
|
me->do_space_pending = YES;
|
|
}
|
|
break;
|
|
|
|
case HTML_TH:
|
|
case HTML_TD:
|
|
if ( me->text->tableState != TS_NOT_IN_TABLE ) {
|
|
HText_beginFrame(me->text,
|
|
ELE_FRAME_IS_CELL | ((element_number == HTML_TH) ? ELE_FRAME_IS_HEADER_CELL : 0),
|
|
present[HTML_TD_ALIGN] ? value[HTML_TD_ALIGN] : NULL,
|
|
present[HTML_TD_BGCOLOR] ? value[HTML_TD_BGCOLOR] : NULL,
|
|
NULL,
|
|
present[HTML_TD_BORDERCOLOR] ? value[HTML_TD_BORDERCOLOR] : NULL,
|
|
present[HTML_TD_BORDERCOLORDARK] ? value[HTML_TD_BORDERCOLORDARK] : NULL,
|
|
present[HTML_TD_BORDERCOLORLIGHT] ? value[HTML_TD_BORDERCOLORLIGHT] : NULL,
|
|
NULL,
|
|
NULL,
|
|
present[HTML_TD_NOWRAP] ?
|
|
(value[HTML_TD_NOWRAP] ? value[HTML_TD_NOWRAP] : "" ): NULL,
|
|
present[HTML_TD_WIDTH] ? value[HTML_TD_WIDTH] : NULL,
|
|
present[HTML_TD_VALIGN] ? value[HTML_TD_VALIGN] : NULL,
|
|
present[HTML_TD_COLSPAN] ? value[HTML_TD_COLSPAN] : NULL,
|
|
present[HTML_TD_ROWSPAN] ? value[HTML_TD_ROWSPAN] : NULL,
|
|
present[HTML_TD_HEIGHT] ? value[HTML_TD_HEIGHT] : NULL
|
|
);
|
|
change_paragraph_style(me, HTML_STYLE_NORMAL);
|
|
InitStyleState( me, FALSE );
|
|
me->do_space_pending = YES;
|
|
if ( present[HTML_TD_NOWRAP] )
|
|
HText_beginNoBreak( me->text );
|
|
|
|
if ( element_number == HTML_TH ) {
|
|
// For header cells, default should be bold. Note that the corresponding
|
|
// PopBoldInfo will not be needed, because the cell frame will do a
|
|
// PopStyleInfo, which restored the bold stack to the state it was in
|
|
// prior to the cell being created.
|
|
PushBoldInfo( me );
|
|
HText_beginBold(me->text);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HTML_DL:
|
|
HText_beginGlossary(me->text);
|
|
break;
|
|
|
|
case HTML_DT:
|
|
HText_beginDT(me->text, element_number);
|
|
break;
|
|
|
|
case HTML_DD:
|
|
HText_beginDD(me->text, element_number);
|
|
break;
|
|
|
|
case HTML_UL:
|
|
HText_beginList(me->text, element_number,
|
|
(present[HTML_UL_TYPE] ? value[HTML_UL_TYPE] : NULL),
|
|
NULL );
|
|
break;
|
|
|
|
case HTML_OL:
|
|
HText_beginList(me->text, element_number,
|
|
(present[HTML_OL_TYPE] ? value[HTML_OL_TYPE] : NULL),
|
|
(present[HTML_OL_START] ? value[HTML_OL_START] : NULL)
|
|
);
|
|
break;
|
|
|
|
case HTML_MENU:
|
|
case HTML_DIR:
|
|
HText_beginList(me->text, element_number, NULL, NULL );
|
|
break;
|
|
|
|
case HTML_LI:
|
|
UPDATE_STYLE;
|
|
#ifdef FEATURE_INTL
|
|
if (me->text->list[me->text->next_list - 1].type == HTML_UL)
|
|
ForceFontChange( me, STY_GetCPDefaultTypeFace(proportional, 1252 ), ANSI_CHARSET);
|
|
#endif
|
|
HText_listItem(me->text, element_number,
|
|
((present && present[HTML_LI_TYPE]) ? value[HTML_LI_TYPE] : NULL),
|
|
((present && present[HTML_LI_VALUE]) ? value[HTML_LI_VALUE] : NULL)
|
|
);
|
|
#ifdef FEATURE_INTL
|
|
if(me->text->list[me->text->next_list - 1].type == HTML_UL)
|
|
ForceFontChange( me, NULL, 0 );
|
|
#endif
|
|
break;
|
|
|
|
case HTML_LISTING: /* Litteral text */
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_LISTING);
|
|
UPDATE_STYLE;
|
|
break;
|
|
case HTML_XMP: /* Litteral text */
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_XMP);
|
|
UPDATE_STYLE;
|
|
break;
|
|
case HTML_PLAINTEXT: /* Litteral text */
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_PLAINTEXT);
|
|
UPDATE_STYLE;
|
|
break;
|
|
case HTML_PRE: /* Litteral text */
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_PRE);
|
|
UPDATE_STYLE;
|
|
break;
|
|
|
|
case HTML_HTML: /* Ignore these altogether */
|
|
case HTML_HEAD:
|
|
break;
|
|
|
|
case HTML_BODY:
|
|
{
|
|
char *src = NULL;
|
|
|
|
if ( present[HTML_BODY_BACKGROUND] )
|
|
src = x_ExpandRelativeAnchor(value[HTML_BODY_BACKGROUND], me->base_url);
|
|
|
|
HText_beginBody(me->text,
|
|
(present[HTML_BODY_ALINK] ? value[HTML_BODY_ALINK] : NULL),
|
|
src,
|
|
(present[HTML_BODY_BGCOLOR] ? value[HTML_BODY_BGCOLOR] : NULL),
|
|
(present[HTML_BODY_BGPROPERTIES] ? value[HTML_BODY_BGPROPERTIES] : NULL),
|
|
(present[HTML_BODY_LEFTMARGIN] ? value[HTML_BODY_LEFTMARGIN] : NULL),
|
|
(present[HTML_BODY_LINK] ? value[HTML_BODY_LINK] : NULL),
|
|
(present[HTML_BODY_TEXT] ? value[HTML_BODY_TEXT] : NULL),
|
|
(present[HTML_BODY_TOPMARGIN] ? value[HTML_BODY_TOPMARGIN] : NULL),
|
|
(present[HTML_BODY_VLINK] ? value[HTML_BODY_VLINK] : NULL)
|
|
);
|
|
|
|
|
|
if ( src )
|
|
GTR_FREE(src);
|
|
}
|
|
break;
|
|
|
|
case HTML_IMG: /* Inline Images */
|
|
case HTML_IMAGE:
|
|
{
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
char *usemap = 0;
|
|
#endif
|
|
|
|
#ifdef FEATURE_VRML
|
|
char *vrml = NULL;
|
|
#endif
|
|
char *src = NULL;
|
|
char *mci = NULL;
|
|
|
|
#ifdef FEATURE_VRML
|
|
if ((!present[HTML_IMG_SRC]) &&
|
|
(!present[HTML_IMG_MCI]) &&
|
|
(!present[HTML_IMG_VRML])) break;
|
|
#else
|
|
if ((!present[HTML_IMG_SRC]) && (!present[HTML_IMG_MCI])) break;
|
|
#endif
|
|
|
|
if (present[HTML_IMG_SRC])
|
|
src = x_ExpandRelativeAnchor(value[HTML_IMG_SRC], me->base_url);
|
|
if (present[HTML_IMG_MCI])
|
|
mci = x_ExpandRelativeAnchor(value[HTML_IMG_MCI], me->base_url);
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
// it could be present but have no value, B#581
|
|
if (present[HTML_IMG_USEMAP] && value[HTML_IMG_USEMAP])
|
|
{
|
|
const char *first;
|
|
for (first = value[HTML_IMG_USEMAP]; *first && IS_SPACE(*first); *first++)
|
|
;
|
|
/* If the map is in this document, expand it ignoring any <BASE> tags */
|
|
if (*first == '#')
|
|
usemap = x_ExpandRelativeAnchor(value[HTML_IMG_USEMAP], me->szDocURL);
|
|
else
|
|
usemap = x_ExpandRelativeAnchor(value[HTML_IMG_USEMAP], me->base_url);
|
|
}
|
|
#endif
|
|
|
|
#ifdef FEATURE_VRML
|
|
if (present[HTML_IMG_VRML])
|
|
vrml = x_ExpandRelativeAnchor(value[HTML_IMG_VRML], me->base_url);
|
|
#endif
|
|
|
|
UPDATE_STYLE;
|
|
|
|
HText_appendInlineImage(me->text,
|
|
present[HTML_IMG_SRC] ? src : NULL,
|
|
present[HTML_IMG_WIDTH] ? value[HTML_IMG_WIDTH] : NULL,
|
|
present[HTML_IMG_HEIGHT] ? value[HTML_IMG_HEIGHT] : NULL,
|
|
present[HTML_IMG_ALIGN] ? value[HTML_IMG_ALIGN] : NULL,
|
|
present[HTML_IMG_ISMAP],
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
usemap,
|
|
#endif
|
|
present[HTML_IMG_ALT] ? value[HTML_IMG_ALT] : NULL,
|
|
present[HTML_IMG_BORDER] ? value[HTML_IMG_BORDER] : NULL,
|
|
present[HTML_IMG_HSPACE] ? value[HTML_IMG_HSPACE] : NULL,
|
|
present[HTML_IMG_VSPACE] ? value[HTML_IMG_VSPACE] : NULL,
|
|
present[HTML_IMG_MCI] ? mci : NULL,
|
|
present[HTML_IMG_LOOP] ? value[HTML_IMG_LOOP] : NULL,
|
|
present[HTML_IMG_START] ? value[HTML_IMG_START] : NULL,
|
|
present[HTML_IMG_CONTROLS] ? (value[HTML_IMG_CONTROLS] ? value[HTML_IMG_CONTROLS] : "ON") : NULL
|
|
#ifdef FEATURE_VRML
|
|
,present[HTML_IMG_VRML] ? vrml : NULL
|
|
#endif
|
|
);
|
|
|
|
if (src)
|
|
GTR_FREE(src);
|
|
if (mci)
|
|
GTR_FREE(mci);
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
if (usemap)
|
|
GTR_FREE(usemap);
|
|
#endif
|
|
|
|
#ifdef FEATURE_VRML
|
|
if (vrml)
|
|
GTR_FREE(vrml);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
case HTML_MAP:
|
|
if (me->mc)
|
|
{
|
|
/* Implicitly terminate previous map */
|
|
Map_EndMap(me->mc);
|
|
me->mc = NULL;
|
|
}
|
|
if (present[HTML_MAP_NAME])
|
|
me->mc = Map_StartMap(value[HTML_MAP_NAME], me->szDocURL, me->base_url);
|
|
break;
|
|
|
|
case HTML_AREA:
|
|
if (me->mc)
|
|
{
|
|
Map_AddToMap(
|
|
me->mc,
|
|
present[HTML_AREA_COORDS] ? value[HTML_AREA_COORDS] : NULL,
|
|
present[HTML_AREA_HREF] ? value[HTML_AREA_HREF] : NULL,
|
|
present[HTML_AREA_NOHREF],
|
|
present[HTML_AREA_SHAPE] ? value[HTML_AREA_SHAPE] : NULL);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case HTML_KBD:
|
|
HText_beginTT(me->text);
|
|
HText_beginBold(me->text);
|
|
break;
|
|
|
|
case HTML_SAMP:
|
|
case HTML_TT:
|
|
case HTML_VAR:
|
|
case HTML_CODE:
|
|
UPDATE_STYLE;
|
|
HText_beginTT(me->text);
|
|
break;
|
|
case HTML_B:
|
|
case HTML_STRONG:
|
|
UPDATE_STYLE;
|
|
PushBoldInfo( me );
|
|
HText_beginBold(me->text);
|
|
break;
|
|
|
|
case HTML_MARQUEE:
|
|
UPDATE_STYLE;
|
|
|
|
HText_beginInlineMarquee( me->text,
|
|
present[HTML_MARQUEE_WIDTH] ? value[HTML_MARQUEE_WIDTH] : NULL,
|
|
present[HTML_MARQUEE_HEIGHT] ? value[HTML_MARQUEE_HEIGHT] : NULL,
|
|
present[HTML_MARQUEE_ALIGN] ? value[HTML_MARQUEE_ALIGN] : NULL,
|
|
present[HTML_MARQUEE_DELTA] ? value[HTML_MARQUEE_DELTA] : NULL,
|
|
present[HTML_MARQUEE_DELAY] ? value[HTML_MARQUEE_DELAY] : NULL,
|
|
present[HTML_MARQUEE_DIRECTION] ? value[HTML_MARQUEE_DIRECTION] : NULL,
|
|
present[HTML_MARQUEE_BORDER] ? value[HTML_MARQUEE_BORDER] : NULL,
|
|
present[HTML_MARQUEE_HSPACE] ? value[HTML_MARQUEE_HSPACE] : NULL,
|
|
present[HTML_MARQUEE_VSPACE] ? value[HTML_MARQUEE_VSPACE] : NULL,
|
|
present[HTML_MARQUEE_BACKROUND] ? value[HTML_MARQUEE_BACKROUND] : NULL,
|
|
present[HTML_MARQUEE_BGCOLOR] ? value[HTML_MARQUEE_BGCOLOR] : NULL,
|
|
present[HTML_MARQUEE_BEHAVIOR] ? value[HTML_MARQUEE_BEHAVIOR] : NULL,
|
|
present[HTML_MARQUEE_LOOP] ? value[HTML_MARQUEE_LOOP] : NULL
|
|
);
|
|
|
|
// make it sure it allocs properly
|
|
me->martext = me->text->w3doc->aElements[me->text->iElement].pMarquee->szMarText;
|
|
|
|
|
|
// clear the text chunk, could be done simpler deeper in the call stack,
|
|
// but its done here for symetry with the other calls in this .c file
|
|
|
|
HTChunkClear(me->martext);
|
|
|
|
|
|
break;
|
|
case HTML_META:
|
|
|
|
ParseMeta( &me->text->w3doc->pMeta,
|
|
present[HTML_META_HTTPEQUIV] ? value[HTML_META_HTTPEQUIV] : NULL,
|
|
present[HTML_META_CONTENT] ? value[HTML_META_CONTENT] : NULL,
|
|
FALSE,
|
|
me->base_url
|
|
);
|
|
|
|
break;
|
|
|
|
case HTML_S:
|
|
case HTML_STRIKE:
|
|
UPDATE_STYLE;
|
|
HText_beginStrikeOut(me->text);
|
|
break;
|
|
case HTML_I:
|
|
case HTML_EM:
|
|
case HTML_CITE:
|
|
case HTML_DFN:
|
|
UPDATE_STYLE;
|
|
PushItalicInfo( me );
|
|
HText_beginItalic(me->text);
|
|
break;
|
|
case HTML_U:
|
|
UPDATE_STYLE;
|
|
HText_beginUnderline(me->text);
|
|
break;
|
|
|
|
case HTML_H1: /* paragraph styles */
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 6;
|
|
change_paragraph_style(me, HTML_STYLE_H1); /* May be postponed */
|
|
break;
|
|
case HTML_H2:
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 5;
|
|
change_paragraph_style(me, HTML_STYLE_H2); /* May be postponed */
|
|
break;
|
|
case HTML_H3:
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 4;
|
|
change_paragraph_style(me, HTML_STYLE_H3); /* May be postponed */
|
|
break;
|
|
case HTML_H4:
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 3;
|
|
change_paragraph_style(me, HTML_STYLE_H4); /* May be postponed */
|
|
break;
|
|
case HTML_H5:
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 2;
|
|
change_paragraph_style(me, HTML_STYLE_H5); /* May be postponed */
|
|
break;
|
|
case HTML_H6:
|
|
PushAttributes( me, (present && present[HTML_GEN_ALIGN]) ? value[HTML_GEN_ALIGN] : NULL );
|
|
me->text->fontSize = 1;
|
|
change_paragraph_style(me, HTML_STYLE_H6); /* May be postponed */
|
|
break;
|
|
case HTML_ADDRESS:
|
|
if ( !me->text->bOnNewPara )
|
|
HText_appendCRLF(me->text);
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_ADDRESS); /* May be postponed */
|
|
break;
|
|
case HTML_BLOCKQUOTE:
|
|
PushAttributes( me, NULL );
|
|
change_paragraph_style(me, HTML_STYLE_BLOCKQUOTE); /* May be postponed */
|
|
HText_beginBlockQuote(me->text);
|
|
break;
|
|
|
|
#ifdef FEATURE_INTL // ValueEntity character is ANSI graphics.
|
|
// So force changing font to ANSI font.
|
|
case HTML_ENTITY:
|
|
UPDATE_STYLE;
|
|
ForceFontChange( me, STY_GetCPDefaultTypeFace(proportional, 1252), ANSI_CHARSET );
|
|
break;
|
|
#endif
|
|
} /* end switch */
|
|
|
|
if (me->dtd->tags[element_number].contents != SGML_EMPTY)
|
|
{
|
|
if (me->ss.sp == me->ss.stack)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("HTML: ****** Maximum nesting of %d exceded!\n",
|
|
MAX_NESTING));
|
|
return;
|
|
}
|
|
switch (me->dtd->tags[element_number].contents)
|
|
{
|
|
case SGML_EMPTY:
|
|
case SGML_NEST:
|
|
break;
|
|
default:
|
|
--(me->ss.sp);
|
|
me->ss.sp[0].style = me->ss.new_style; /* Stack new style */
|
|
me->ss.sp[0].tag_number = element_number;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* End Element
|
|
** -----------
|
|
**
|
|
*/
|
|
/* When we end an element, the style must be returned to that
|
|
** in effect before that element. Note that anchors (etc?)
|
|
** don't have an associated style, so that we must scan down the
|
|
** stack for an element with a defined style. (In fact, the styles
|
|
** should be linked to the whole stack not just the top one.)
|
|
** TBL 921119
|
|
**
|
|
** We don't turn on "CAREFUL" check because the parser produces
|
|
** (internal code errors apart) good nesting. The parser checks
|
|
** incoming code errors, not this module.
|
|
*/
|
|
PRIVATE void HTML_end_element(HTStructured * me, int element_number)
|
|
{
|
|
#ifdef CAREFUL /* parser assumed to produce good nesting */
|
|
if (element_number != me->ss.sp[0].tag_number)
|
|
{
|
|
char buf[256];
|
|
|
|
sprintf(buf, "BUMMER: Received %s when expecting %s", me->dtd->tags[element_number].name, me->dtd->tags[me->ss.sp->tag_number].name);
|
|
HTAlert(buf);
|
|
}
|
|
#endif
|
|
|
|
XX_DMsg(DBG_SGML, ("HTML_end_element: %s\n", me->dtd->tags[element_number].name));
|
|
|
|
switch (me->dtd->tags[element_number].contents)
|
|
{
|
|
case SGML_EMPTY:
|
|
case SGML_NEST:
|
|
break;
|
|
default:
|
|
if ( me->ss.sp != me->ss.stack + MAX_NESTING - 1 )
|
|
me->ss.sp++; /* Pop state off stack */
|
|
break;
|
|
}
|
|
|
|
switch (element_number)
|
|
{
|
|
case HTML_DL:
|
|
case HTML_UL:
|
|
case HTML_OL:
|
|
case HTML_MENU:
|
|
case HTML_DIR:
|
|
#ifdef FEATURE_INTL
|
|
case HTML_ENTITY:
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
HText_addListCRLF(me->text);
|
|
}
|
|
|
|
switch (element_number)
|
|
{
|
|
case HTML_TR:
|
|
if (me->text->tableState == TS_NOT_IN_TABLE)
|
|
{
|
|
XX_DMsg(DBG_SGML, ("HTML_end_element: not in table!!!\n"));
|
|
break;
|
|
}
|
|
|
|
// If we see a </TR> while we're in a cell, this implies a missing </TD>
|
|
if ( me->text->tableState == TS_IN_CELL )
|
|
HText_endFrame(me->text, ELE_FRAME_IS_CELL, NULL);
|
|
|
|
// Track the fact that we're "between" rows
|
|
me->text->bPendingTR = TRUE;
|
|
break;
|
|
|
|
case HTML_TABLE:
|
|
{
|
|
BOOL bWasFloating = FALSE;
|
|
|
|
if (me->text->tableState == TS_NOT_IN_TABLE)
|
|
{
|
|
XX_DMsg(DBG_SGML, ("HTML_end_element: not in table!!!\n"));
|
|
break;
|
|
}
|
|
|
|
// If we see a </TABLE> tag while we're in a cell, this implies a missing </TD>
|
|
if ( me->text->tableState == TS_IN_CELL )
|
|
HText_endFrame(me->text, ELE_FRAME_IS_CELL, NULL);
|
|
|
|
HText_endFrame(me->text, ELE_FRAME_IS_TABLE, &bWasFloating );
|
|
|
|
if ( !bWasFloating )
|
|
HText_appendCRLF(me->text);
|
|
}
|
|
break;
|
|
|
|
case HTML_TD:
|
|
case HTML_TH:
|
|
case HTML_CAPTION:
|
|
if (me->text->tableState == TS_NOT_IN_TABLE)
|
|
{
|
|
XX_DMsg(DBG_SGML, ("HTML_end_element: not in table!!!\n"));
|
|
break;
|
|
}
|
|
|
|
HText_endFrame(me->text, ELE_FRAME_IS_CELL, NULL);
|
|
break;
|
|
|
|
case HTML_FORM:
|
|
{
|
|
HText_endForm(me->text);
|
|
}
|
|
break;
|
|
case HTML_TEXTAREA:
|
|
{
|
|
HText_endTextArea(me->text);
|
|
}
|
|
break;
|
|
case HTML_SELECT:
|
|
{
|
|
HText_endSelect(me->text);
|
|
}
|
|
break;
|
|
case HTML_DL:
|
|
HText_endGlossary(me->text);
|
|
break;
|
|
|
|
case HTML_UL:
|
|
case HTML_OL:
|
|
case HTML_MENU:
|
|
case HTML_DIR:
|
|
HText_endList(me->text, element_number);
|
|
break;
|
|
|
|
case HTML_P:
|
|
if ( me->text->tableState != TS_IN_LIMBO ) {
|
|
CenterSetValue( me, NULL, FALSE );
|
|
HText_appendParagraph(me->text);
|
|
}
|
|
break;
|
|
|
|
case HTML_B:
|
|
case HTML_STRONG:
|
|
PopBoldInfo( me );
|
|
break;
|
|
|
|
case HTML_S:
|
|
case HTML_STRIKE:
|
|
HText_endStrikeOut(me->text);
|
|
break;
|
|
|
|
case HTML_I:
|
|
case HTML_EM:
|
|
case HTML_CITE:
|
|
case HTML_DFN:
|
|
PopItalicInfo( me );
|
|
break;
|
|
|
|
case HTML_BASEFONT:
|
|
PopFontInfo( me );
|
|
HText_endSetFont(me->text, TRUE );
|
|
break;
|
|
|
|
case HTML_FONT:
|
|
PopFontInfo( me );
|
|
HText_endSetFont(me->text, FALSE );
|
|
break;
|
|
|
|
case HTML_NOBR:
|
|
HText_endNoBreak(me->text);
|
|
break;
|
|
|
|
case HTML_CENTER:
|
|
HText_endCenter(me->text);
|
|
PopCenterInfo( me );
|
|
if ( !me->text->bOnNewPara )
|
|
HText_appendCRLF(me->text);
|
|
break;
|
|
|
|
case HTML_KBD:
|
|
HText_endBold(me->text);
|
|
HText_endTT(me->text);
|
|
break;
|
|
|
|
case HTML_SAMP:
|
|
case HTML_TT:
|
|
case HTML_VAR:
|
|
case HTML_CODE:
|
|
HText_endTT(me->text);
|
|
break;
|
|
|
|
case HTML_U:
|
|
HText_endUnderline(me->text);
|
|
break;
|
|
|
|
case HTML_A:
|
|
UPDATE_STYLE;
|
|
HText_endAnchor(me->text);
|
|
break;
|
|
|
|
case HTML_TITLE:
|
|
HTChunkTerminate(&me->title);
|
|
HText_setTitle(me->text, me->title.data);
|
|
break;
|
|
case HTML_MARQUEE:
|
|
// don't party on if its NULL, since we could
|
|
// have poorly formated HTML, we shouldn't crash
|
|
if ( me->martext )
|
|
{
|
|
HTChunkTerminate(me->martext);
|
|
me->martext = NULL;
|
|
}
|
|
|
|
break;
|
|
case HTML_H1:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_H2:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_H3:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_H4:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_H5:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_H6:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
case HTML_ADDRESS:
|
|
PopAttributes( me );
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
if ( !me->text->bOnNewPara )
|
|
HText_appendCRLF(me->text);
|
|
break;
|
|
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
case HTML_MAP:
|
|
if (me->mc)
|
|
{
|
|
Map_EndMap(me->mc);
|
|
me->mc = NULL;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case HTML_LISTING: /* Litteral text */
|
|
case HTML_XMP:
|
|
case HTML_PLAINTEXT:
|
|
case HTML_PRE:
|
|
PopAttributes( me );
|
|
HText_appendCRLF(me->text);
|
|
goto DefaultCase;
|
|
|
|
case HTML_BLOCKQUOTE:
|
|
PopAttributes( me );
|
|
HText_endBlockQuote(me->text);
|
|
goto DefaultCase;
|
|
|
|
#if FEATURE_INTL // Restore font
|
|
case HTML_ENTITY:
|
|
ForceFontChange( me, NULL, 0 );
|
|
break;
|
|
#endif
|
|
default:
|
|
|
|
DefaultCase:
|
|
change_paragraph_style(me, me->ss.sp->style); /* Often won't really change */
|
|
break;
|
|
|
|
} /* switch */
|
|
|
|
}
|
|
|
|
|
|
/* Expanding entities
|
|
** ------------------
|
|
*/
|
|
/* (In fact, they all shrink!)
|
|
*/
|
|
|
|
PRIVATE void HTML_put_entity(HTStructured * me, int entity_number)
|
|
{
|
|
#ifdef FEATURE_INTL
|
|
// In DBCS version, we should call the put_character rather than
|
|
// the put_string. The put_string handle entity value
|
|
// as DBCS primary byte.
|
|
HTML_put_character(me, *(me->dtd->entity_values[entity_number]));
|
|
#else
|
|
HTML_put_string(me, me->dtd->entity_values[entity_number]);
|
|
#endif
|
|
}
|
|
|
|
|
|
PRIVATE void HTML_free(HTStructured * me)
|
|
{
|
|
HText_endAllFrames( me->text );
|
|
UPDATE_STYLE;
|
|
HText_endAppend(me->text);
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
if (me->mc)
|
|
{
|
|
/* Implicitly terminate previous map */
|
|
Map_EndMap(me->mc);
|
|
}
|
|
#endif
|
|
|
|
if (me->target)
|
|
{
|
|
DCACHETIME dct={0,0};
|
|
|
|
(*me->targetClass.free) (me->target, dct, dct);
|
|
}
|
|
HTChunkClear(&me->title);
|
|
|
|
GTR_FREE(me);
|
|
}
|
|
|
|
|
|
PRIVATE void HTML_abort(HTStructured * me, HTError e)
|
|
{
|
|
UPDATE_STYLE;
|
|
HText_abort(me->text);
|
|
#ifdef FEATURE_CLIENT_IMAGEMAP
|
|
if (me->mc)
|
|
{
|
|
Map_AbortMap(me->mc);
|
|
me->mc = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (me->target)
|
|
{
|
|
(*me->targetClass.abort) (me->target, e);
|
|
}
|
|
HTChunkClear(&me->title);
|
|
GTR_FREE(me);
|
|
}
|
|
|
|
PRIVATE LPVOID HTML_get_source(HTStructured *me)
|
|
{
|
|
return (LPVOID) (me->csSource);
|
|
}
|
|
|
|
PRIVATE void HTML_add_source(HTStructured *me, CONST char *str, int len)
|
|
{
|
|
CS_AddString(me->csSource, (char *) str, len);
|
|
}
|
|
|
|
|
|
PRIVATE void HTML_block_done(HTStructured *me)
|
|
{
|
|
HText_update(me->text);
|
|
}
|
|
|
|
/* P U B L I C
|
|
*/
|
|
|
|
/* Structured Object Class
|
|
** -----------------------
|
|
*/
|
|
PRIVATE CONST HTStructuredClass HTMLPresentation =
|
|
{
|
|
"text/html",
|
|
HTML_free,
|
|
HTML_abort,
|
|
HTML_put_character, HTML_put_string, HTML_write,
|
|
HTML_start_element, HTML_end_element,
|
|
HTML_put_entity, HTML_add_source, HTML_block_done, HTML_get_source
|
|
};
|
|
|
|
|
|
/* New Structured Text object
|
|
** --------------------------
|
|
**
|
|
** The structured stream can generate either presentation,
|
|
** or plain text, or HTML.
|
|
*/
|
|
PUBLIC HTStructured *HTML_new(struct Mwin *tw, HTRequest * request, void *param, HTFormat input_format, HTFormat output_format, HTStream * output_stream)
|
|
{
|
|
|
|
HTStructured *me;
|
|
|
|
me = (HTStructured *) GTR_MALLOC(sizeof(*me));
|
|
if (me)
|
|
{
|
|
memset(me, 0, sizeof(*me));
|
|
me->isa = &HTMLPresentation;
|
|
me->dtd = &DTD;
|
|
me->szDocURL = request->destination->szActualURL;
|
|
me->title.size = 0;
|
|
me->title.growby = 128;
|
|
me->title.allocated = 0;
|
|
me->title.data = 0;
|
|
me->text = 0;
|
|
me->style_change = NO;
|
|
#ifdef KEEP_A_SPACE
|
|
me->space_pending = NO;
|
|
me->do_space_pending = NO;
|
|
#endif
|
|
GTR_strncpy(me->base_url, request->destination->szActualURL, MAX_URL_STRING);
|
|
|
|
InitStyleState( me, TRUE );
|
|
me->ss.next = NULL;
|
|
|
|
me->target = output_stream;
|
|
if (output_stream)
|
|
me->targetClass = *output_stream->isa; /* Copy pointers */
|
|
|
|
me->bFirstCellInRow = TRUE;
|
|
me->bSeenBrInCell = FALSE;
|
|
|
|
me->csSource = CS_Create();
|
|
me->text = HText_new2(tw, request, me->target, me->csSource);
|
|
me->text->pHtmlStream = me;
|
|
HText_beginAppend(me->text);
|
|
HText_setStyle(me->text, HTML_STYLE_NORMAL);
|
|
|
|
}
|
|
|
|
return (HTStructured *) me;
|
|
}
|
|
|
|
|
|
PUBLIC HTStream *HTMLPresent(struct Mwin *tw, HTRequest * request, void *param, HTFormat input_format, HTFormat output_format, HTStream * output_stream)
|
|
{
|
|
return SGML_new(tw, &DTD, HTML_new(tw, request, NULL, input_format, output_format, output_stream), request);
|
|
}
|