/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* This file is part of the GtkHTML library. Copyright (C) 1997 Martin Jones (mjones@kde.org) Copyright (C) 1997 Torben Weis (weis@kde.org) Copyright (C) 1999 Anders Carlsson (andersca@gnu.org) Copyright (C) 1999, 2000, Helix Code, Inc. Copyright (C) 2001, Ximian Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* RULE: You should never create a new flow without inserting anything in it. If `e->flow' is not NULL, it must contain something. */ #include #include "gtkhtml-compat.h" #include #include #include #include #include #include #include #include #include "gtkhtml-embedded.h" #include "gtkhtml-private.h" #include "gtkhtml-stream.h" #include "gtkhtmldebug.h" #include "htmlengine.h" #include "htmlengine-search.h" #include "htmlengine-edit.h" #include "htmlengine-edit-cursor.h" #include "htmlengine-edit-movement.h" #include "htmlengine-edit-cut-and-paste.h" #include "htmlengine-edit-selection-updater.h" #include "htmlengine-print.h" #include "htmlselection.h" #include "htmlcolor.h" #include "htmlinterval.h" #include "htmlobject.h" #include "htmlsettings.h" #include "htmltext.h" #include "htmltokenizer.h" #include "htmltype.h" #include "htmlundo.h" #include "htmldrawqueue.h" #include "htmlgdkpainter.h" #include "htmlreplace.h" #include "htmlentity.h" #include "htmlanchor.h" #include "htmlrule.h" #include "htmlobject.h" #include "htmlclueh.h" #include "htmlcluev.h" #include "htmlcluealigned.h" #include "htmlvspace.h" #include "htmlimage.h" #include "htmllinktext.h" #include "htmllist.h" #include "htmltable.h" #include "htmltablecell.h" #include "htmltext.h" #include "htmltextslave.h" #include "htmlclueflow.h" #include "htmlstack.h" #include "htmlstringtokenizer.h" #include "htmlform.h" #include "htmlbutton.h" #include "htmltextinput.h" #include "htmlradio.h" #include "htmlcheckbox.h" #include "htmlhidden.h" #include "htmlselect.h" #include "htmltextarea.h" #include "htmlimageinput.h" #include "htmlstack.h" #include "htmlsearch.h" #include "htmlframeset.h" #include "htmlframe.h" #include "htmliframe.h" #include "htmlshape.h" #include "htmlmap.h" /* #define CHECK_CURSOR */ #ifdef CHECK_CURSOR #include #endif static void html_engine_class_init (HTMLEngineClass *klass); static void html_engine_init (HTMLEngine *engine); static gboolean html_engine_timer_event (HTMLEngine *e); static gboolean html_engine_update_event (HTMLEngine *e); static char ** html_engine_stream_types (GtkHTMLStream *stream, gpointer data); static void html_engine_stream_write (GtkHTMLStream *stream, const gchar *buffer, size_t size, gpointer data); static void html_engine_stream_end (GtkHTMLStream *stream, GtkHTMLStreamStatus status, gpointer data); static void html_engine_set_object_data (HTMLEngine *e, HTMLObject *o); static void parse_one_token (HTMLEngine *p, HTMLObject *clue, const gchar *str); static void parse_input (HTMLEngine *e, const gchar *s, HTMLObject *_clue); static void parse_iframe (HTMLEngine *e, const gchar *s, HTMLObject *_clue); static void parse_f (HTMLEngine *p, HTMLObject *clue, const gchar *str); static void update_embedded (GtkWidget *widget, gpointer ); static void html_engine_map_table_clear (HTMLEngine *e); static void html_engine_add_map (HTMLEngine *e, HTMLMap *map); static void crop_iframe_to_parent (HTMLEngine *e, gint x, gint y, gint *width, gint *height); static GtkLayoutClass *parent_class = NULL; enum { SET_BASE_TARGET, SET_BASE, LOAD_DONE, TITLE_CHANGED, URL_REQUESTED, DRAW_PENDING, REDIRECT, SUBMIT, OBJECT_REQUESTED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; #define TIMER_INTERVAL 300 enum ID { ID_ADDRESS, ID_B, ID_BIG, ID_BLOCKQUOTE, ID_BODY, ID_CAPTION, ID_CENTER, ID_CITE, ID_CODE, ID_DIR, ID_DIV, ID_DL, ID_EM, ID_FONT, ID_HEADER, ID_I, ID_KBD, ID_OL, ID_PRE, ID_SMALL, ID_STRONG, ID_U, ID_UL, ID_TEXTAREA, ID_TD, ID_TH, ID_TT, ID_VAR, ID_SUB, ID_SUP, ID_STRIKEOUT }; /* * Font handling. */ /* Font faces */ static HTMLFontFace * current_font_face (HTMLEngine *e) { return (HTMLFontFace *) (html_stack_is_empty (e->font_face_stack) ? NULL : html_stack_top (e->font_face_stack)); } static void push_font_face (HTMLEngine *e, const HTMLFontFace *face) { html_stack_push (e->font_face_stack, g_strdup (face)); } static void pop_font_face (HTMLEngine *e) { g_free (html_stack_pop (e->font_face_stack)); } /* Font styles */ static inline GtkHTMLFontStyle current_font_style (HTMLEngine *e) { return e->font_style; } static gint style_to_attr (GtkHTMLFontStyle style) { switch (style) { case GTK_HTML_FONT_STYLE_BOLD: return GTK_HTML_FONT_STYLE_SHIFT_BOLD - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_ITALIC: return GTK_HTML_FONT_STYLE_SHIFT_ITALIC - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_UNDERLINE: return GTK_HTML_FONT_STYLE_SHIFT_UNDERLINE - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_STRIKEOUT: return GTK_HTML_FONT_STYLE_SHIFT_STRIKEOUT - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_FIXED: return GTK_HTML_FONT_STYLE_SHIFT_FIXED - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_SUBSCRIPT: return GTK_HTML_FONT_STYLE_SHIFT_SUBSCRIPT - GTK_HTML_FONT_STYLE_SHIFT_FIRST; case GTK_HTML_FONT_STYLE_SUPERSCRIPT: return GTK_HTML_FONT_STYLE_SHIFT_SUPERSCRIPT - GTK_HTML_FONT_STYLE_SHIFT_FIRST; default: return -1; } } static GtkHTMLFontStyle add_font_style (HTMLEngine *e, GtkHTMLFontStyle new_attrs) { if (new_attrs & GTK_HTML_FONT_STYLE_SIZE_MASK) { html_stack_push (e->font_size_stack, GINT_TO_POINTER (current_font_style (e) & GTK_HTML_FONT_STYLE_SIZE_MASK)); e->font_style = (current_font_style (e) & ~GTK_HTML_FONT_STYLE_SIZE_MASK) | new_attrs; } else { gint idx = style_to_attr (new_attrs); if (idx >= 0) e->font_style_attrs [idx] ++; else g_warning ("unknown style"); e->font_style = current_font_style (e) | new_attrs; } if (!(e->font_style & GTK_HTML_FONT_STYLE_SIZE_MASK)) e->font_style |= GTK_HTML_FONT_STYLE_SIZE_3; return current_font_style (e); } static GtkHTMLFontStyle remove_font_style (HTMLEngine *e, GtkHTMLFontStyle old_attrs) { if (old_attrs & GTK_HTML_FONT_STYLE_SIZE_MASK || old_attrs == GTK_HTML_FONT_STYLE_DEFAULT) { e->font_style = (current_font_style (e) & ~GTK_HTML_FONT_STYLE_SIZE_MASK) | (html_stack_is_empty (e->font_size_stack) ? GTK_HTML_FONT_STYLE_SIZE_3 : GPOINTER_TO_INT (html_stack_pop (e->font_size_stack))); } else { gint idx = style_to_attr (old_attrs); if (idx >= 0) { if (e->font_style_attrs [idx]) e->font_style_attrs [idx] --; if (!e->font_style_attrs [idx]) e->font_style = current_font_style (e) & ~old_attrs; } else g_warning ("unknown style"); } if (!(e->font_style & GTK_HTML_FONT_STYLE_SIZE_MASK)) e->font_style |= GTK_HTML_FONT_STYLE_SIZE_3; if (e->font_style == GTK_HTML_FONT_STYLE_SIZE_3) e->font_style = GTK_HTML_FONT_STYLE_DEFAULT; return current_font_style (e); } static void font_style_attr_reset (gint *attrs) { gint i; for (i = 0; i <= GTK_HTML_FONT_STYLE_SHIFT_LAST - GTK_HTML_FONT_STYLE_SHIFT_FIRST; i ++) attrs [i] = 0; } static void font_style_attr_copy (gint *dest, gint *src) { gint i; for (i = 0; i <= GTK_HTML_FONT_STYLE_SHIFT_LAST - GTK_HTML_FONT_STYLE_SHIFT_FIRST; i ++) dest [i] = src [i]; } /* Color handling. */ static HTMLColor * current_color (HTMLEngine *e) { HTMLColor *color; if (html_stack_is_empty (e->color_stack)) color = html_colorset_get_color (e->settings->color_set, HTMLTextColor); else color = html_stack_top (e->color_stack); return color; } static void push_color (HTMLEngine *e, HTMLColor *color) { html_stack_push (e->color_stack, color); html_color_ref (color); } static void pop_color (HTMLEngine *e) { HTMLColor *color = (HTMLColor *)html_stack_pop (e->color_stack); g_return_if_fail (color != NULL); html_color_unref (color); } static gboolean parse_color (const gchar *text, GdkColor *color) { gchar c [8]; gint len = strlen (text); if (gdk_color_parse (text, color)) return TRUE; c [7] = 0; if (*text != '#') { c[0] = '#'; strncpy (c + 1, text, 6); len++; } else { strncpy (c, text, 7); } if (len < 7) memset (c + len, '0', 7-len); return gdk_color_parse (c, color); } static GtkPolicyType parse_scroll (const char *token) { GtkPolicyType scroll; if (strncasecmp (token, "yes", 3) == 0) { scroll = GTK_POLICY_ALWAYS; } else if (strncasecmp (token, "no", 2) == 0) { scroll = GTK_POLICY_NEVER; } else /* auto */ { scroll = GTK_POLICY_AUTOMATIC; } return scroll; } static HTMLHAlignType parse_halign (const char *token, HTMLHAlignType default_val) { if (strcasecmp (token, "right") == 0) return HTML_HALIGN_RIGHT; else if (strcasecmp (token, "left") == 0) return HTML_HALIGN_LEFT; else if (strcasecmp (token, "center") == 0 || strcasecmp (token, "middle") == 0) return HTML_HALIGN_CENTER; else return default_val; } /* ClueFlow style handling. */ static HTMLClueFlowStyle current_clueflow_style (HTMLEngine *e) { HTMLClueFlowStyle style; if (html_stack_is_empty (e->clueflow_style_stack)) return HTML_CLUEFLOW_STYLE_NORMAL; style = (HTMLClueFlowStyle) GPOINTER_TO_INT (html_stack_top (e->clueflow_style_stack)); return style; } static void push_clueflow_style (HTMLEngine *e, HTMLClueFlowStyle style) { html_stack_push (e->clueflow_style_stack, GINT_TO_POINTER (style)); } static void pop_clueflow_style (HTMLEngine *e) { html_stack_pop (e->clueflow_style_stack); } /* Utility functions. */ static void new_flow (HTMLEngine *e, HTMLObject *clue, HTMLObject *first_object, HTMLClearType clear); static void close_flow (HTMLEngine *e, HTMLObject *clue); static void finish_flow (HTMLEngine *e, HTMLObject *clue); static HTMLObject * text_new (HTMLEngine *e, const gchar *text, GtkHTMLFontStyle style, HTMLColor *color) { HTMLObject *o; o = html_text_new (text, style, color); html_engine_set_object_data (e, o); return o; } static HTMLObject * flow_new (HTMLEngine *e, HTMLClueFlowStyle style, HTMLListType item_type, gint item_number, HTMLClearType clear) { HTMLObject *o; GByteArray *levels; GList *l; levels = g_byte_array_new (); if (e->listStack && e->listStack->list) { l = e->listStack->list; while (l) { guint8 val = ((HTMLList *)l->data)->type; g_byte_array_prepend (levels, &val, 1); l = l->next; } } o = html_clueflow_new (style, levels, item_type, item_number, clear); html_engine_set_object_data (e, o); return o; } static HTMLObject * create_empty_text (HTMLEngine *e) { HTMLObject *o; o = text_new (e, "", current_font_style (e), current_color (e)); html_text_set_font_face (HTML_TEXT (o), current_font_face (e)); return o; } static void insert_paragraph_break (HTMLEngine *e, HTMLObject *clue) { close_flow (e, clue); new_flow (e, clue, create_empty_text (e), HTML_CLEAR_NONE); close_flow (e, clue); } static void add_pending_paragraph_break (HTMLEngine *e, HTMLObject *clue) { if (e->pending_para) { insert_paragraph_break (e, clue); e->pending_para = FALSE; } } static void add_line_break (HTMLEngine *e, HTMLObject *clue, HTMLClearType clear) { if (!e->flow && !HTML_CLUE (clue)->head) new_flow (e, clue, create_empty_text (e), HTML_CLEAR_NONE); new_flow (e, clue, NULL, clear); } static void close_anchor (HTMLEngine *e) { if (e->url == NULL && e->target == NULL) return; g_free (e->url); e->url = NULL; g_free (e->target); e->target = NULL; } static void finish_flow (HTMLEngine *e, HTMLObject *clue) { if (e->flow && HTML_CLUE (e->flow)->tail == NULL) { html_clue_remove (HTML_CLUE (clue), e->flow); html_object_destroy (e->flow); e->flow = NULL; e->pending_para = FALSE; } close_flow (e, clue); } static void close_flow (HTMLEngine *e, HTMLObject *clue) { HTMLObject *last; if (e->flow == NULL) return; last = HTML_CLUE (e->flow)->tail; if (last == NULL) { html_clue_append (HTML_CLUE (e->flow), create_empty_text (e)); } else if (HTML_OBJECT_TYPE (last) == HTML_TYPE_VSPACE) { html_clue_remove (HTML_CLUE (e->flow), last); html_object_destroy (last); } else if (HTML_CLUE (e->flow)->tail != HTML_CLUE (e->flow)->head && html_object_is_text (last) && HTML_TEXT (last)->text_len == 1 && HTML_TEXT (last)->text [0] == ' ') { html_clue_remove (HTML_CLUE (e->flow), last); html_object_destroy (last); } e->flow = NULL; } static void update_flow_align (HTMLEngine *e, HTMLObject *clue) { if (e->flow != NULL) { if (HTML_CLUE (e->flow)->head != NULL) close_flow (e, clue); else HTML_CLUE (e->flow)->halign = e->pAlign; } } static void new_flow (HTMLEngine *e, HTMLObject *clue, HTMLObject *first_object, HTMLClearType clear) { close_flow (e, clue); e->flow = flow_new (e, current_clueflow_style (e), HTML_LIST_TYPE_BLOCKQUOTE, 0, clear); HTML_CLUE (e->flow)->halign = e->pAlign; if (first_object) html_clue_append (HTML_CLUE (e->flow), first_object); html_clue_append (HTML_CLUE (clue), e->flow); } static void append_element (HTMLEngine *e, HTMLObject *clue, HTMLObject *obj) { add_pending_paragraph_break (e, clue); e->avoid_para = FALSE; if (e->flow == NULL) new_flow (e, clue, obj, HTML_CLEAR_NONE); else html_clue_append (HTML_CLUE (e->flow), obj); } static gboolean check_prev (const HTMLObject *p, HTMLType type, GtkHTMLFontStyle font_style, HTMLColor *color, gchar *face) { if (p == NULL) return FALSE; if (HTML_OBJECT_TYPE (p) != type) return FALSE; if (HTML_TEXT (p)->font_style != font_style) return FALSE; if (! html_color_equal (HTML_TEXT (p)->color, color)) return FALSE; if ((face && !HTML_TEXT (p)->face) || (!face && HTML_TEXT (p)->face) || (face && HTML_TEXT (p)->face && strcasecmp (face, HTML_TEXT (p)->face))) return FALSE; return TRUE; } static void insert_text (HTMLEngine *e, HTMLObject *clue, const gchar *text) { GtkHTMLFontStyle font_style; HTMLObject *prev; HTMLType type; HTMLColor *color; gchar *face; gboolean create_link; if (text [0] == ' ' && text [1] == 0) { if (e->eat_space) return; else e->eat_space = TRUE; } else e->eat_space = FALSE; if (e->url != NULL || e->target != NULL) create_link = TRUE; else create_link = FALSE; font_style = current_font_style (e); color = current_color (e); face = current_font_face (e); if ((create_link || e->pending_para || e->flow == NULL || HTML_CLUE (e->flow)->head == NULL) && !e->inPre) { while (*text == ' ') text++; if (*text == 0) return; } if (e->flow == NULL) prev = NULL; else prev = HTML_CLUE (e->flow)->tail; if (e->url != NULL || e->target != NULL) type = HTML_TYPE_LINKTEXT; else type = HTML_TYPE_TEXT; if (! check_prev (prev, type, font_style, color, face) || e->pending_para) { HTMLObject *obj; if (create_link) obj = html_link_text_new (text, font_style, color, e->url, e->target); else obj = text_new (e, text, font_style, color); html_text_set_font_face (HTML_TEXT (obj), current_font_face (e)); append_element (e, clue, obj); } else html_text_append (HTML_TEXT (prev), text, -1); } /* Block stack. */ typedef void (*BlockFunc)(HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *el); struct _HTMLBlockStackElement { BlockFunc exitFunc; gint id; gint level; gint miscData1; gint miscData2; HTMLBlockStackElement *next; }; static HTMLBlockStackElement * block_stack_element_new (gint id, gint level, BlockFunc exitFunc, gint miscData1, gint miscData2, HTMLBlockStackElement *next) { HTMLBlockStackElement *se; se = g_new0 (HTMLBlockStackElement, 1); se->id = id; se->level = level; se->miscData1 = miscData1; se->miscData2 = miscData2; se->next = next; se->exitFunc = exitFunc; return se; } static void block_stack_element_free (HTMLBlockStackElement *elem) { g_free (elem); } static void push_block (HTMLEngine *e, gint id, gint level, BlockFunc exitFunc, gint miscData1, gint miscData2) { HTMLBlockStackElement *elem; elem = block_stack_element_new (id, level, exitFunc, miscData1, miscData2, e->blockStack); e->blockStack = elem; } static void free_block (HTMLEngine *e) { HTMLBlockStackElement *elem = e->blockStack; while (elem != 0) { HTMLBlockStackElement *tmp = elem; elem = elem->next; block_stack_element_free (tmp); } e->blockStack = 0; } static void pop_block (HTMLEngine *e, gint id, HTMLObject *clue) { HTMLBlockStackElement *elem, *tmp; gint maxLevel; elem = e->blockStack; maxLevel = 0; while ((elem != NULL) && (elem->id != id)) { if (maxLevel < elem->level) { maxLevel = elem->level; } elem = elem->next; } if (elem == NULL) return; if (maxLevel > elem->level) return; elem = e->blockStack; while (elem) { tmp = elem; if (elem->exitFunc != NULL) (*(elem->exitFunc))(e, clue, elem); if (elem->id == id) { e->blockStack = elem->next; elem = NULL; } else { elem = elem->next; } block_stack_element_free (tmp); } } /* The following are callbacks that are called at the end of a block. */ static void block_end_clueflow_style (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { close_flow (e, clue); pop_clueflow_style (e); e->pAlign = elem->miscData1; } static void block_end_pre ( HTMLEngine *e, HTMLObject *_clue, HTMLBlockStackElement *elem) { block_end_clueflow_style (e, _clue, elem); e->inPre = FALSE; } static void block_end_color_font (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { if (elem->miscData1) remove_font_style (e, current_font_style (e) & GTK_HTML_FONT_STYLE_SIZE_MASK); if (elem->miscData2) pop_color (e); pop_font_face (e); } static void block_end_list (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { html_list_destroy (html_stack_pop (e->listStack)); close_flow (e, clue); if (html_stack_is_empty (e->listStack)) { e->pending_para = FALSE; e->avoid_para = TRUE; } } static void block_end_glossary (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { html_list_destroy (html_stack_pop (e->listStack)); } static void block_end_quote (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { close_flow (e, clue); html_list_destroy (html_stack_pop (e->listStack)); e->pending_para = FALSE; e->avoid_para = TRUE; } static void block_end_div (HTMLEngine *e, HTMLObject *clue, HTMLBlockStackElement *elem) { close_flow (e, clue); e->divAlign = e->pAlign = (HTMLHAlignType) elem->miscData1; } static gchar * parse_body (HTMLEngine *e, HTMLObject *clue, const gchar *end[], gboolean toplevel, gboolean begin) { gchar *str; gchar *rv = NULL; gboolean final = FALSE; if (begin && !toplevel) { gint *old_font_style_attrs; html_stack_push (e->body_stack, e->font_size_stack); html_stack_push (e->body_stack, e->font_face_stack); html_stack_push (e->body_stack, e->color_stack); html_stack_push (e->body_stack, e->clueflow_style_stack); e->font_size_stack = html_stack_new (NULL); e->font_face_stack = html_stack_new (g_free); e->color_stack = html_stack_new ((HTMLStackFreeFunc) html_color_unref); e->clueflow_style_stack = html_stack_new (NULL); html_stack_push (e->body_stack, GINT_TO_POINTER (e->font_style)); e->font_style = GTK_HTML_FONT_STYLE_DEFAULT; old_font_style_attrs = g_new (gint, GTK_HTML_FONT_STYLE_SHIFT_LAST - GTK_HTML_FONT_STYLE_SHIFT_FIRST + 1); font_style_attr_copy (old_font_style_attrs, e->font_style_attrs); font_style_attr_reset (e->font_style_attrs); html_stack_push (e->body_stack, old_font_style_attrs); html_stack_push (e->body_stack, GINT_TO_POINTER (e->pending_para)); html_stack_push (e->body_stack, GINT_TO_POINTER (e->avoid_para)); push_block (e, ID_BODY, 4, NULL, 0, 0); } e->eat_space = FALSE; while (html_tokenizer_has_more_tokens (e->ht) && e->parsing) { str = html_tokenizer_next_token (e->ht); if (*str == '\0') continue; if ( *str == ' ' && *(str+1) == '\0' ) { /* if in* is set this text belongs in a form element */ if (e->inTextArea || e->inOption) e->formText = g_string_append (e->formText, " "); else if (e->inTitle) g_string_append (e->title, " "); else insert_text (e, clue, str); } else if (*str != TAG_ESCAPE) { if (e->inOption || e->inTextArea) g_string_append (e->formText, str); else if (e->inTitle) { g_string_append (e->title, str); } else { insert_text (e, clue, str); } } else { gint i = 0; str++; while (end [i] != 0) { if (strncasecmp (str, end[i], strlen(end[i])) == 0) { rv = str; final = TRUE; goto end_body; } i++; } /* The tag used for line break when we are in
...
*/ if (*str == '\n') add_line_break (e, clue, HTML_CLEAR_NONE); else parse_one_token (e, clue, str); } } if (!html_tokenizer_has_more_tokens (e->ht) && toplevel && !e->writing) html_engine_stop_parser (e); end_body: if (final) { if (e->flow && HTML_CLUE (e->flow)->tail == NULL) { html_clue_remove (HTML_CLUE (clue), e->flow); html_object_destroy (e->flow); e->flow = NULL; } if (!toplevel) { gint *old_font_style_attrs; pop_block (e, ID_BODY, clue); e->avoid_para = GPOINTER_TO_INT (html_stack_pop (e->body_stack)); e->pending_para = GPOINTER_TO_INT (html_stack_pop (e->body_stack)); old_font_style_attrs = html_stack_pop (e->body_stack); font_style_attr_copy (e->font_style_attrs, old_font_style_attrs); g_free (old_font_style_attrs); e->font_style = GPOINTER_TO_INT (html_stack_pop (e->body_stack)); html_stack_destroy (e->clueflow_style_stack); html_stack_destroy (e->color_stack); html_stack_destroy (e->font_face_stack); html_stack_destroy (e->font_size_stack); e->font_size_stack = html_stack_pop (e->body_stack); e->color_stack = html_stack_pop (e->body_stack); e->font_face_stack = html_stack_pop (e->body_stack); e->clueflow_style_stack = html_stack_pop (e->body_stack); } } return rv; } static gchar * discard_body (HTMLEngine *p, const gchar *end[]) { gchar *str = NULL; while (html_tokenizer_has_more_tokens (p->ht) && p->parsing) { str = html_tokenizer_next_token (p->ht); if (*str == '\0') continue; if ((*str == ' ' && *(str+1) == '\0') || (*str != TAG_ESCAPE)) { /* do nothing */ } else { gint i = 0; str++; while (end [i] != 0) { if (strncasecmp (str, end[i], strlen(end[i])) == 0) { return str; } i++; } } } return 0; } /* EP CHECK: finished except for the settings stuff (see `FIXME'). */ static const gchar * parse_table (HTMLEngine *e, HTMLObject *clue, gint max_width, const gchar *attr) { static const gchar *endthtd[] = { "", "", "", "divAlign; HTMLHAlignType oldpalign = e->pAlign; HTMLClue *oldflow = HTML_CLUE (e->flow); HTMLStack *old_list_stack = e->listStack; GdkColor tableColor, rowColor, bgColor; gboolean have_tableColor, have_rowColor, have_bgColor; gboolean have_tablePixmap, have_rowPixmap, have_bgPixmap; gint rowSpan; gint colSpan; gint cellwidth; gint cellheight; gboolean cellwidth_percent; gboolean cellheight_percent; gboolean no_wrap; gboolean fixedWidth; gboolean fixedHeight; HTMLVAlignType valign; HTMLHAlignType halign; HTMLTableCell *cell; gpointer tablePixmapPtr = NULL; gpointer rowPixmapPtr = NULL; gpointer bgPixmapPtr = NULL; have_tablePixmap = FALSE; have_rowPixmap = FALSE; have_bgPixmap = FALSE; have_tableColor = FALSE; have_rowColor = FALSE; have_bgColor = FALSE; gtk_html_debug_log (e->widget, "start parse\n"); html_string_tokenizer_tokenize (e->st, attr, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "cellpadding=", 12) == 0) { padding = atoi (token + 12); } else if (strncasecmp (token, "cellspacing=", 12) == 0) { spacing = atoi (token + 12); } else if (strncasecmp (token, "border", 6) == 0) { if (*(token + 6) == '=') border = atoi (token + 7); else border = 1; } else if (strncasecmp (token, "width=", 6) == 0) { if (strchr (token + 6, '%')) { percent = atoi (token + 6); } else if (strchr (token + 6, '*')) { /* Ignore */ } else if (isdigit (*(token + 6))) { width = atoi (token + 6); } } else if (strncasecmp (token, "align=", 6) == 0) { align = parse_halign (token + 6, align); } else if (strncasecmp (token, "bgcolor=", 8) == 0 && !e->defaultSettings->forceDefault) { if (parse_color (token + 8, &tableColor)) { rowColor = tableColor; have_rowColor = have_tableColor = TRUE; } } else if (strncasecmp (token, "background=", 11) == 0 && token [12] && !e->defaultSettings->forceDefault) { tablePixmapPtr = html_image_factory_register(e->image_factory, NULL, token + 11, FALSE); if(tablePixmapPtr) { rowPixmapPtr = tablePixmapPtr; have_tablePixmap = have_rowPixmap = TRUE; } } } table = HTML_TABLE (html_table_new (width, percent, padding, spacing, border)); if (have_tableColor) table->bgColor = gdk_color_copy (&tableColor); if (have_tablePixmap) table->bgPixmap = HTML_IMAGE_POINTER (tablePixmapPtr); e->listStack = html_stack_new ((HTMLStackFreeFunc)html_list_destroy); while (!done && html_tokenizer_has_more_tokens (e->ht)) { str = html_tokenizer_next_token (e->ht); /* Every tag starts with an escape character */ if (str[0] == TAG_ESCAPE) { str++; tableTag = TRUE; for (;;) { if (strncmp (str, "st, str + 9, " >" ); while ( html_string_tokenizer_has_more_tokens (e->st) ) { const char* token = html_string_tokenizer_next_token(e->st); if ( strncasecmp( token, "align=", 6 ) == 0) { if ( strncasecmp( token+6, "top", 3 ) == 0) capAlign = HTML_VALIGN_TOP; } } caption = HTML_CLUEV (html_cluev_new (0, 0, 100)); e->pAlign = HTML_HALIGN_CENTER; e->flow = 0; push_block (e, ID_CAPTION, 3, NULL, 0, 0); str = parse_body ( e, HTML_OBJECT (caption), endcap, FALSE, TRUE); pop_block (e, ID_CAPTION, HTML_OBJECT (caption) ); table->caption = caption; table->capAlign = capAlign; close_flow (e, HTML_OBJECT (caption)); e->flow = 0; if (!str) break; else if (strncmp( str, " or */ continue; /* parse the returned tag */ } } if (strncmp (str, "st, str + 4, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "valign=", 7) == 0) { if (strncasecmp (token + 7, "top", 3) == 0) rowvalign = HTML_VALIGN_TOP; else if (strncasecmp (token + 7, "bottom", 6) == 0) rowvalign = HTML_VALIGN_BOTTOM; else rowvalign = HTML_VALIGN_MIDDLE; } else if (strncasecmp (token, "align=", 6) == 0) { rowhalign = parse_halign (token + 6, rowhalign); } else if (strncasecmp (token, "bgcolor=", 8) == 0) { have_rowColor |= parse_color (token + 8, &rowColor); } else if (strncasecmp (token, "background=", 11) == 0 && token [12] && !e->defaultSettings->forceDefault) { rowPixmapPtr = html_image_factory_register(e->image_factory, NULL, token + 11, FALSE); if(rowPixmapPtr) have_rowPixmap = TRUE; } } break; } /* Hack to fix broken html in bonsai */ else if (strncmp (str, " and */ tableEntry = *str == '<' && *(str + 1) == 't' && (*(str + 2) == 'd' || *(str + 2) == 'h'); if (tableEntry || noCell) { gboolean heading = FALSE; noCell = FALSE; close_anchor (e); if (tableEntry && *(str + 2) == 'h') { gtk_html_debug_log (e->widget, "\n"); heading = TRUE; } /* * man not be present for first row * or after but start one anyway */ if (newRow) { /* Bad HTML: No tag present */ html_table_start_row (table); newRow = FALSE; } no_wrap = FALSE; rowSpan = 1; colSpan = 1; cellwidth = clue->max_width; cellheight = -1; cellwidth_percent = FALSE; cellheight_percent = FALSE; fixedWidth = FALSE; fixedHeight = FALSE; if (have_rowColor) { bgColor = rowColor; have_bgColor = TRUE; } else { have_bgColor = FALSE; } if (have_rowPixmap) { bgPixmapPtr = rowPixmapPtr; have_bgPixmap = TRUE; } else { have_bgPixmap = FALSE; } e->divAlign = HTML_HALIGN_NONE; e->pAlign = HTML_HALIGN_NONE; valign = rowvalign == HTML_VALIGN_NONE ? HTML_VALIGN_MIDDLE : rowvalign; halign = rowhalign == HTML_HALIGN_NONE ? HTML_HALIGN_NONE : rowhalign; if (tableEntry) { html_string_tokenizer_tokenize (e->st, str + 4, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "rowspan=", 8) == 0) { rowSpan = atoi (token + 8); if (rowSpan < 1) rowSpan = 1; } else if (strncasecmp (token, "colspan=", 8) == 0) { colSpan = atoi (token + 8); if (colSpan < 1) colSpan = 1; } else if (strncasecmp (token, "valign=", 7) == 0) { if (strncasecmp (token + 7, "top", 3) == 0) valign = HTML_VALIGN_TOP; else if (strncasecmp (token + 7, "bottom", 6) == 0) valign = HTML_VALIGN_BOTTOM; else valign = HTML_VALIGN_MIDDLE; } else if (strncasecmp (token, "align=", 6) == 0) { halign = parse_halign (token + 6, halign); } else if (strncasecmp (token, "height=", 7) == 0) { if (strchr (token + 7, '%')) { /* gtk_html_debug_log (e->widget, "percent!\n"); cellheight = atoi (token + 7); cellheight_percent = TRUE; fixedHeight = TRUE; */ } else if (strchr (token + 7, '*')) { /* ignore */ } else if (isdigit (*(token + 7))) { cellheight = atoi (token + 7); cellheight_percent = FALSE; fixedHeight = TRUE; } } else if (strncasecmp (token, "width=", 6) == 0) { if (strchr (token + 6, '%')) { gtk_html_debug_log (e->widget, "percent!\n"); cellwidth = atoi (token + 6); cellwidth_percent = TRUE; fixedWidth = TRUE; } else if (strchr (token + 6, '*')) { /* ignore */ } else if (isdigit (*(token + 6))) { cellwidth = atoi (token + 6); cellwidth_percent = FALSE; fixedWidth = TRUE; } } else if (strncasecmp (token, "bgcolor=", 8) == 0 && !e->defaultSettings->forceDefault) { have_bgColor |= parse_color (token + 8, &bgColor); } else if (strncasecmp (token, "nowrap", 6) == 0) { no_wrap = TRUE; } else if (strncasecmp (token, "background=", 11) == 0 && token [12] && !e->defaultSettings->forceDefault) { bgPixmapPtr = html_image_factory_register(e->image_factory, NULL, token + 11, FALSE); if(bgPixmapPtr) have_bgPixmap = TRUE; } } } add_pending_paragraph_break (e, clue); cell = HTML_TABLE_CELL (html_table_cell_new (rowSpan, colSpan, padding)); cell->no_wrap = no_wrap; cell->heading = heading; html_object_set_bg_color (HTML_OBJECT (cell), have_bgColor ? &bgColor : NULL); if(have_bgPixmap) html_table_cell_set_bg_pixmap(cell, bgPixmapPtr); HTML_CLUE (cell)->valign = valign; HTML_CLUE (cell)->halign = halign; if (fixedWidth) html_table_cell_set_fixed_width (cell, cellwidth, cellwidth_percent); if (fixedHeight) html_table_cell_set_fixed_height (cell, cellheight, cellheight_percent); html_table_add_cell (table, cell); has_cell = 1; e->flow = NULL; e->avoid_para = TRUE; if (!tableEntry) { /* Put all the junk between and the first table tag into one row */ push_block (e, ID_TD, 3, NULL, 0, 0); str = parse_body (e, HTML_OBJECT (cell), endall, FALSE, TRUE); pop_block (e, ID_TD, HTML_OBJECT (cell)); add_pending_paragraph_break (e, HTML_OBJECT (cell)); close_flow (e, HTML_OBJECT (cell)); html_table_end_row (table); html_table_start_row (table); } else { push_block (e, heading ? ID_TH : ID_TD, 3, NULL, 0, 0); str = parse_body (e, HTML_OBJECT (cell), endthtd, FALSE, TRUE); if (HTML_CLUE (cell)->head == NULL) insert_paragraph_break (e, HTML_OBJECT (cell)); pop_block (e, heading ? ID_TH : ID_TD, HTML_OBJECT (cell)); close_flow (e, HTML_OBJECT (cell)); } if (!str) break; else if ((strncmp (str, "listStack); e->listStack = old_list_stack; e->pAlign = oldpalign; e->divAlign = olddivalign; e->flow = HTML_OBJECT (oldflow); if (has_cell) { /* The ending "
" might be missing, so we close the table here... */ if (!newRow) html_table_end_row (table); has_cell = html_table_end_table (table); } if (has_cell) { if (align != HTML_HALIGN_LEFT && align != HTML_HALIGN_RIGHT) { if (e->flow && !html_clueflow_is_empty (HTML_CLUEFLOW (e->flow))) close_flow (e, clue); if (align != HTML_HALIGN_NONE) { oldpalign = e->pAlign; e->pAlign = align; } append_element (e, clue, HTML_OBJECT (table)); close_flow (e, clue); if (align != HTML_HALIGN_NONE) e->pAlign = oldpalign; } else { HTMLClueAligned *aligned = HTML_CLUEALIGNED (html_cluealigned_new (NULL, 0, 0, clue->max_width, 100)); HTML_CLUE (aligned)->halign = align; html_clue_append (HTML_CLUE (aligned), HTML_OBJECT (table)); append_element (e, clue, HTML_OBJECT (aligned)); } } else { /* Last resort: remove tables that do not contain any cells */ html_object_destroy (HTML_OBJECT (table)); } gtk_html_debug_log (e->widget, "Returning: %s\n", str); return str; } static gboolean is_leading_space (guchar *str) { while (*str != '\0') { if (!(isspace (*str) || IS_UTF8_NBSP (str))) return FALSE; str = g_utf8_next_char (str); } return TRUE; } static gchar * parse_object_params(HTMLEngine *p, HTMLObject *clue) { gchar *str; /* we peek at tokens looking for elements and * as soon as we find something that is not whitespace or a param * element we bail and the caller deal with the rest */ while (html_tokenizer_has_more_tokens (p->ht) && p->parsing) { str = html_tokenizer_peek_token (p->ht); if (*str == '\0' || *str == '\n' || is_leading_space (str)) { str = html_tokenizer_next_token (p->ht); /* printf ("\"%s\": was the string\n", str); */ continue; } else if (*str == TAG_ESCAPE) { str++; if (strncasecmp ("ht); parse_one_token (p, clue, str); continue; } } return str; } return NULL; } static void parse_object (HTMLEngine *e, HTMLObject *clue, gint max_width, const gchar *attr) { char *classid=NULL; char *name=NULL; char *type = NULL; char *str = NULL; char *data = NULL; int width=-1,height=-1; static const gchar *end[] = { "st, attr, " >" ); /* this might have to do something different for form object elements - check the spec MPZ */ while (html_string_tokenizer_has_more_tokens (e->st) ) { const char* token; token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "classid=", 8) == 0) { classid = g_strdup (token + 8); } else if (strncasecmp (token, "name=", 5) == 0 ) { name = g_strdup (token + 5); } else if ( strncasecmp (token, "width=", 6) == 0) { width = atoi (token + 6); } else if (strncasecmp (token, "height=", 7) == 0) { height = atoi (token + 7); } else if (strncasecmp (token, "type=", 5) == 0) { type = g_strdup (token + 5); } else if (strncasecmp (token, "data=", 5) == 0) { data = g_strdup (token + 5); } } eb = (GtkHTMLEmbedded *) gtk_html_embedded_new (classid, name, type, data, width, height); html_stack_push (e->embeddedStack, eb); el = html_embedded_new_widget (GTK_WIDGET (e->widget), eb, e); /* evaluate params */ parse_object_params (e, clue); /* create the object */ object_found = FALSE; gtk_signal_emit (GTK_OBJECT (e), signals [OBJECT_REQUESTED], eb, &object_found); /* show alt text on TRUE */ if (object_found) { append_element(e, clue, HTML_OBJECT(el)); /* automatically add this to a form if it is part of one */ if (e->form) html_form_add_element (e->form, HTML_EMBEDDED (el)); /* throw away the contents we can deal with the object */ str = discard_body (e, end); } else { /* parse the body of the tag to display the alternative */ str = parse_body (e, clue, end, FALSE, TRUE); close_flow (e, clue); html_object_destroy (HTML_OBJECT (el)); } if ((!str || (strncasecmp (str, "embeddedStack))) { html_stack_pop (e->embeddedStack); } g_free (type); g_free (data); g_free (classid); g_free (name); } static void parse_input (HTMLEngine *e, const gchar *str, HTMLObject *_clue) { enum InputType { CheckBox, Hidden, Radio, Reset, Submit, Text, Image, Button, Password, Undefined }; HTMLObject *element = NULL; const char *p; enum InputType type = Text; gchar *name = NULL; gchar *value = NULL; gchar *imgSrc = NULL; gboolean checked = FALSE; int size = 20; int maxLen = -1; int imgHSpace = 0; int imgVSpace = 0; html_string_tokenizer_tokenize (e->st, str, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if ( strncasecmp( token, "type=", 5 ) == 0 ) { p = token + 5; if ( strncasecmp( p, "checkbox", 8 ) == 0 ) type = CheckBox; else if ( strncasecmp( p, "password", 8 ) == 0 ) type = Password; else if ( strncasecmp( p, "hidden", 6 ) == 0 ) type = Hidden; else if ( strncasecmp( p, "radio", 5 ) == 0 ) type = Radio; else if ( strncasecmp( p, "reset", 5 ) == 0 ) type = Reset; else if ( strncasecmp( p, "submit", 5 ) == 0 ) type = Submit; else if ( strncasecmp( p, "button", 6 ) == 0 ) type = Button; else if ( strncasecmp( p, "text", 5 ) == 0 ) type = Text; else if ( strncasecmp( p, "image", 5 ) == 0 ) type = Image; } else if ( strncasecmp( token, "name=", 5 ) == 0 ) { name = g_strdup(token + 5); } else if ( strncasecmp( token, "value=", 6 ) == 0 ) { value = g_strdup(token + 6); } else if ( strncasecmp( token, "size=", 5 ) == 0 ) { size = atoi( token + 5 ); } else if ( strncasecmp( token, "maxlength=", 10 ) == 0 ) { maxLen = atoi( token + 10 ); } else if ( strncasecmp( token, "checked", 7 ) == 0 ) { checked = TRUE; } else if ( strncasecmp( token, "src=", 4 ) == 0 ) { imgSrc = g_strdup (token + 4); } else if ( strncasecmp( token, "onClick=", 8 ) == 0 ) { /* TODO: Implement Javascript */ } else if ( strncasecmp( token, "hspace=", 7 ) == 0 ) { imgHSpace = atoi (token + 7); } else if ( strncasecmp( token, "vspace=", 7 ) == 0 ) { imgVSpace = atoi (token + 7); } } switch ( type ) { case CheckBox: element = html_checkbox_new(GTK_WIDGET(e->widget), name, value, checked); break; case Hidden: { HTMLObject *hidden = html_hidden_new(name, value); html_form_add_hidden (e->form, HTML_HIDDEN (hidden)); break; } case Radio: element = html_radio_new(GTK_WIDGET(e->widget), name, value, checked, e->form); break; case Reset: element = html_button_new(GTK_WIDGET(e->widget), name, value, BUTTON_RESET); break; case Submit: element = html_button_new(GTK_WIDGET(e->widget), name, value, BUTTON_SUBMIT); break; case Button: element = html_button_new(GTK_WIDGET(e->widget), name, value, BUTTON_NORMAL); break; case Text: case Password: element = html_text_input_new(GTK_WIDGET(e->widget), name, value, size, maxLen, (type == Password)); break; case Image: element = html_imageinput_new (e->image_factory, name, imgSrc); html_image_set_spacing (HTML_IMAGE (HTML_IMAGEINPUT (element)->image), imgHSpace, imgVSpace); break; case Undefined: g_warning ("Unknown \n"); break; } if (element) { append_element (e, _clue, element); html_form_add_element (e->form, HTML_EMBEDDED (element)); } if (name) g_free (name); if (value) g_free (value); if (imgSrc) g_free (imgSrc); } static void parse_frameset (HTMLEngine *e, HTMLObject *clue, gint max_width, const gchar *attr) { HTMLObject *set; char *rows = NULL; char *cols = NULL; html_string_tokenizer_tokenize (e->st, attr, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "rows=", 5) == 0) { rows = g_strdup (token + 5); } else if (strncasecmp (token, "cols=", 5) == 0) { cols = g_strdup (token + 5); } else if (strncasecmp (token, "onload=", 7) == 0) { /* all frames in set loaded */ /* unimplemented */ } else if (strncasecmp (token, "onunload=", 9) == 0) { /* all frames unloaded */ /* unimplemented */ } } /* clear the borders */ e->bottomBorder = 0; e->topBorder = 0; e->leftBorder = 0; e->rightBorder = 0; set = html_frameset_new (e->widget, rows, cols); if (html_stack_is_empty (e->frame_stack)) { append_element (e, clue, set); } else { html_frameset_append (html_stack_top (e->frame_stack), set); } html_stack_push (e->frame_stack, set); g_free (rows); g_free (cols); } static void parse_iframe (HTMLEngine *e, const gchar *str, HTMLObject *_clue) { char *src = NULL; char *align = NULL; HTMLObject *iframe; static const gchar *end[] = { "st, str, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "src=", 4) == 0) { src = g_strdup (token + 4); } else if (strncasecmp (token, "width=", 6) == 0) { width = atoi (token + 6); } else if (strncasecmp (token, "height=", 7) == 0) { height = atoi (token + 7); } else if (strncasecmp (token, "align=", 6) == 0) { align = g_strdup (token + 6); } else if (strncasecmp (token, "longdesc=", 9) == 0) { /* TODO: Ignored */ } else if (strncasecmp (token, "name=", 5) == 0) { /* TODO: Ignored */ } else if (strncasecmp (token, "scrolling=", 10) == 0) { scroll = parse_scroll (token + 10); } else if (strncasecmp (token, "marginwidth=", 12) == 0) { margin_width = atoi (token + 12); } else if (strncasecmp (token, "marginheight=", 13) == 0) { margin_height = atoi (token + 13); } else if (strncasecmp (token, "frameborder=", 12) == 0) { border = atoi (token + 12); } } if (src) { iframe = html_iframe_new (GTK_WIDGET (e->widget), src, width, height, border); if (margin_height > 0) html_iframe_set_margin_height (HTML_IFRAME (iframe), margin_height); if (margin_width > 0) html_iframe_set_margin_width (HTML_IFRAME (iframe), margin_width); if (scroll != GTK_POLICY_AUTOMATIC) html_iframe_set_scrolling (HTML_IFRAME (iframe), scroll); g_free (src); append_element (e, _clue, iframe); discard_body (e, end); } else { parse_body (e, _clue, end, FALSE, TRUE); close_flow (e, _clue); } g_free (align); } /*
*/ static void parse_a (HTMLEngine *e, HTMLObject *_clue, const gchar *str) { if (strncmp (str, "area", 4) == 0) { HTMLShape *shape; char *type = NULL; char *href = NULL; char *coords = NULL; char *target = NULL; if (e->map == NULL) return; html_string_tokenizer_tokenize (e->st, str + 5, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "shape=", 6) == 0) { type = g_strdup (token + 6); } else if (strncasecmp (token, "href=", 5) == 0) { href = g_strdup (token +5); } else if ( strncasecmp (token, "target=", 7) == 0) { target = g_strdup (token + 7); } else if ( strncasecmp (token, "coords=", 7) == 0) { coords = g_strdup (token + 7); } } if (type || coords) { shape = html_shape_new (type, coords, href, target); if (shape != NULL) { html_map_add_shape (e->map, shape); } } g_free (type); g_free (href); g_free (coords); g_free (target); } else if ( strncmp( str, "address", 7) == 0 ) { push_clueflow_style (e, HTML_CLUEFLOW_STYLE_ADDRESS); close_flow (e, _clue); push_block (e, ID_ADDRESS, 2, block_end_clueflow_style, e->pAlign, 0); } else if ( strncmp( str, "/address", 8) == 0 ) { pop_block (e, ID_ADDRESS, _clue); } else if ( strncmp( str, "a ", 2 ) == 0 ) { gchar *url = NULL; gchar *id = NULL; const gchar *p; close_anchor (e); html_string_tokenizer_tokenize( e->st, str + 2, " >" ); while ((p = html_string_tokenizer_next_token (e->st)) != 0) { if (strncasecmp (p, "href=", 5) == 0) { url = g_strdup (p + 5); /* FIXME visited? */ } else if (strncasecmp (p, "id=", 3) == 0) { /* * FIXME this doesn't handle the * case where id and name are both set * properly but it will do for now */ if (id == NULL) id = g_strdup (p + 3); } else if (strncasecmp (p, "name=", 5) == 0) { if (id == NULL) id = g_strdup (p + 5); } else if (strncasecmp (p, "shape=", 6) == 0) { /* FIXME todo */ } else if (strncasecmp (p, "target=", 7) == 0) { #if 0 /* FIXME TODO */ target = g_strdup (p + 7); parsedTargets.append( target ); #endif } } if (id != NULL) { if (e->flow == 0) html_clue_append (HTML_CLUE (_clue), html_anchor_new (id)); else html_clue_append (HTML_CLUE (e->flow), html_anchor_new (id)); g_free (id); } #if 0 if ( !target && e->baseTarget != NULL && e->baseTarget[0] != '\0' ) { target = g_strdup (e->baseTarget); /* parsedTargets.append( target ); FIXME TODO */ } #endif if (url != NULL) { g_free (e->url); e->url = url; } if (e->url || e->target) push_color (e, html_colorset_get_color (e->settings->color_set, HTMLLinkColor)); } else if ( strncmp( str, "/a", 2 ) == 0 ) { if (e->url || e->target) pop_color (e); close_anchor (e); e->eat_space = FALSE; } } /*
' tag. */ static void parse_b (HTMLEngine *e, HTMLObject *clue, const gchar *str) { GdkColor color; if (strncmp (str, "basefont", 8) == 0) { } else if ( strncmp(str, "base", 4 ) == 0 ) { html_string_tokenizer_tokenize( e->st, str + 5, " >" ); while ( html_string_tokenizer_has_more_tokens (e->st) ) { const char* token = html_string_tokenizer_next_token(e->st); if ( strncasecmp( token, "target=", 7 ) == 0 ) { gtk_signal_emit (GTK_OBJECT (e), signals[SET_BASE_TARGET], token + 7); } else if ( strncasecmp( token, "href=", 5 ) == 0 ) { gtk_signal_emit (GTK_OBJECT (e), signals[SET_BASE], token + 5); } } } else if ( strncmp(str, "big", 3 ) == 0 ) { add_font_style (e, GTK_HTML_FONT_STYLE_SIZE_4); } else if ( strncmp(str, "/big", 4 ) == 0 ) { remove_font_style (e, GTK_HTML_FONT_STYLE_SIZE_4); } else if ( strncmp(str, "blockquote", 10 ) == 0 ) { gboolean type = HTML_LIST_TYPE_BLOCKQUOTE; html_string_tokenizer_tokenize (e->st, str + 11, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const char *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "type=", 5) == 0) { if (strncasecmp (token + 5, "cite", 5) == 0) { type = HTML_LIST_TYPE_BLOCKQUOTE_CITE; } } } html_stack_push (e->listStack, html_list_new (type)); push_block (e, ID_BLOCKQUOTE, 2, block_end_quote, FALSE, FALSE); e->avoid_para = TRUE; e->pending_para = FALSE; finish_flow (e, clue); } else if ( strncmp(str, "/blockquote", 11 ) == 0 ) { e->avoid_para = TRUE; finish_flow (e, clue); pop_block (e, ID_BLOCKQUOTE, clue); new_flow (e, clue, NULL, HTML_CLEAR_NONE); } else if (strncmp (str, "body", 4) == 0) { html_string_tokenizer_tokenize (e->st, str + 5, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { gchar *token; token = html_string_tokenizer_next_token (e->st); gtk_html_debug_log (e->widget, "token is: %s\n", token); if (strncasecmp (token, "bgcolor=", 8) == 0) { gtk_html_debug_log (e->widget, "setting color\n"); if (parse_color (token + 8, &color)) { gtk_html_debug_log (e->widget, "bgcolor is set\n"); html_colorset_set_color (e->settings->color_set, &color, HTMLBgColor); } else { gtk_html_debug_log (e->widget, "Color `%s' could not be parsed\n", token); } } else if (strncasecmp (token, "background=", 11) == 0 && token [12] && ! e->defaultSettings->forceDefault) { gchar *bgurl; bgurl = g_strdup (token + 11); if (e->bgPixmapPtr != NULL) html_image_factory_unregister(e->image_factory, e->bgPixmapPtr, NULL); e->bgPixmapPtr = html_image_factory_register(e->image_factory, NULL, bgurl, FALSE); g_free (bgurl); } else if ( strncasecmp( token, "text=", 5 ) == 0 && !e->defaultSettings->forceDefault ) { if (parse_color (token + 5, &color)) { if (! html_stack_is_empty (e->color_stack)) pop_color (e); html_colorset_set_color (e->settings->color_set, &color, HTMLTextColor); push_color (e, html_colorset_get_color (e->settings->color_set, HTMLTextColor)); } } else if ( strncasecmp( token, "link=", 5 ) == 0 && !e->defaultSettings->forceDefault ) { parse_color (token + 5, &color); html_colorset_set_color (e->settings->color_set, &color, HTMLLinkColor); } else if ( strncasecmp( token, "vlink=", 6 ) == 0 && !e->defaultSettings->forceDefault ) { parse_color (token + 6, &color); html_colorset_set_color (e->settings->color_set, &color, HTMLVLinkColor); } else if ( strncasecmp( token, "alink=", 6 ) == 0 && !e->defaultSettings->forceDefault ) { parse_color (token + 6, &color); html_colorset_set_color (e->settings->color_set, &color, HTMLALinkColor); } else if ( strncasecmp( token, "leftmargin=", 11 ) == 0) { e->leftBorder = atoi (token + 11); } else if ( strncasecmp( token, "rightmargin=", 12 ) == 0) { e->rightBorder = atoi (token + 12); } else if ( strncasecmp( token, "topmargin=", 10 ) == 0) { e->topBorder = atoi (token + 10); } else if ( strncasecmp( token, "bottommargin=", 13 ) == 0) { e->bottomBorder = atoi (token + 13); } else if ( strncasecmp( token, "marginwidth=", 12 ) == 0) { e->leftBorder = e->rightBorder = atoi (token + 12); } else if ( strncasecmp( token, "marginheight=", 13 ) == 0) { e->topBorder = e->bottomBorder = atoi (token + 13); } } gtk_html_debug_log (e->widget, "parsed \n"); } else if (strncmp (str, "br", 2) == 0 || strncmp (str, "/br", 3) == 0) { HTMLClearType clear; clear = HTML_CLEAR_NONE; html_string_tokenizer_tokenize (e->st, str + 3, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "clear=", 6) == 0) { gtk_html_debug_log (e->widget, "%s\n", token); if (strncasecmp (token + 6, "left", 4) == 0) clear = HTML_CLEAR_LEFT; else if (strncasecmp (token + 6, "right", 5) == 0) clear = HTML_CLEAR_RIGHT; else if (strncasecmp (token + 6, "all", 3) == 0) clear = HTML_CLEAR_ALL; } } add_line_break (e, clue, clear); } else if (strncmp (str, "b", 1) == 0) { if (str[1] == '>' || str[1] == ' ') { add_font_style (e, GTK_HTML_FONT_STYLE_BOLD); } } else if (strncmp (str, "/b", 2) == 0) { remove_font_style (e, GTK_HTML_FONT_STYLE_BOLD); } } /*
unimplemented */ /* EP CHECK OK except for the font in `'. */ static void parse_c (HTMLEngine *e, HTMLObject *clue, const gchar *str) { if (strncmp (str, "center", 6) == 0) { push_block (e, ID_CENTER, 1, block_end_div, e->pAlign, FALSE); e->pAlign = e->divAlign = HTML_HALIGN_CENTER; update_flow_align (e, clue); } else if (strncmp (str, "/center", 7) == 0) { pop_block (e, ID_CENTER, clue); } else if (strncmp( str, "cite", 4 ) == 0) { add_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); add_font_style (e, GTK_HTML_FONT_STYLE_BOLD); } else if (strncmp( str, "/cite", 5) == 0) { remove_font_style (e, GTK_HTML_FONT_STYLE_BOLD); remove_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); } else if (strncmp(str, "code", 4 ) == 0 ) { add_font_style (e, GTK_HTML_FONT_STYLE_FIXED); } else if (strncmp(str, "/code", 5 ) == 0 ) { remove_font_style (e, GTK_HTML_FONT_STYLE_FIXED); } } /* partial
*/ /* EP CHECK: dl/dt might be wrong. */ /* EP CHECK: dir might be wrong. */ static void parse_d ( HTMLEngine *e, HTMLObject *_clue, const char *str ) { if ( strncmp( str, "dir", 3 ) == 0 ) { close_anchor(e); push_block (e, ID_DIR, 2, block_end_list, FALSE, FALSE); html_stack_push (e->listStack, html_list_new (HTML_LIST_TYPE_DIR)); /* FIXME shouldn't it create a new flow? */ } else if ( strncmp( str, "/dir", 4 ) == 0 ) { pop_block (e, ID_DIR, _clue); } else if ( strncmp( str, "div", 3 ) == 0 ) { push_block (e, ID_DIV, 1, block_end_div, e->pAlign, FALSE); html_string_tokenizer_tokenize( e->st, str + 4, " >" ); while ( html_string_tokenizer_has_more_tokens (e->st) ) { const char* token = html_string_tokenizer_next_token (e->st); if ( strncasecmp( token, "align=", 6 ) == 0 ) { e->pAlign = e->divAlign = parse_halign (token + 6, e->pAlign); } } update_flow_align (e, _clue); } else if ( strncmp( str, "/div", 4 ) == 0 ) { pop_block (e, ID_DIV, _clue ); } else if ( strncmp( str, "dl", 2 ) == 0 ) { close_anchor (e); push_block (e, ID_DL, 2, block_end_glossary, FALSE, FALSE); if (!html_stack_is_empty (e->listStack)) { HTMLList *top = html_stack_top (e->listStack); if (top->type == HTML_LIST_TYPE_GLOSSARY_DL) top->type = HTML_LIST_TYPE_GLOSSARY_DD; } html_stack_push (e->listStack, html_list_new (HTML_LIST_TYPE_GLOSSARY_DL)); add_line_break (e, _clue, HTML_CLEAR_ALL); } else if ( strncmp( str, "/dl", 3 ) == 0 ) { pop_block (e, ID_DL, _clue); add_line_break (e, _clue, HTML_CLEAR_ALL); } else if (strncmp( str, "dt", 2 ) == 0) { HTMLList *top = html_stack_top (e->listStack); if (top && (top->type == HTML_LIST_TYPE_GLOSSARY_DD || top->type == HTML_LIST_TYPE_GLOSSARY_DL)) { top->type = HTML_LIST_TYPE_GLOSSARY_DL; close_flow (e, _clue); return; } close_anchor (e); push_block (e, ID_DL, 2, block_end_glossary, FALSE, FALSE); html_stack_push (e->listStack, html_list_new (HTML_LIST_TYPE_GLOSSARY_DL)); add_line_break (e, _clue, HTML_CLEAR_ALL); } else if (strncmp( str, "dd", 2 ) == 0) { HTMLList *top = html_stack_top (e->listStack); if (top && (top->type == HTML_LIST_TYPE_GLOSSARY_DD || top->type == HTML_LIST_TYPE_GLOSSARY_DL)) { top->type = HTML_LIST_TYPE_GLOSSARY_DD; close_flow (e, _clue); return; } close_anchor (e); push_block (e, ID_DL, 2, block_end_glossary, FALSE, FALSE); html_stack_push (e->listStack, html_list_new (HTML_LIST_TYPE_GLOSSARY_DD)); add_line_break (e, _clue, HTML_CLEAR_ALL); } else if (strncmp (str, "data ", 5) == 0) { gchar *key = NULL; gchar *class_name = NULL; html_string_tokenizer_tokenize (e->st, str + 5, " >" ); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "class=", 6 ) == 0) { g_free (class_name); class_name = g_strdup (token + 6); } else if (strncasecmp (token, "key=", 4 ) == 0) { g_free (key); key = g_strdup (token + 4); } else if (class_name && key && strncasecmp (token, "value=", 6) == 0) { if (class_name) { html_engine_set_class_data (e, class_name, key, token + 6); if (!strcmp (class_name, "ClueFlow") && e->flow) html_engine_set_object_data (e, e->flow); } } else if (strncasecmp (token, "clear=", 6) == 0) if (class_name) html_engine_clear_class_data (e, class_name, token + 6); /* TODO clear flow data */ } g_free (class_name); g_free (key); } } /* */ /* EP CHECK: OK. */ static void parse_e (HTMLEngine *e, HTMLObject *_clue, const gchar *str) { if ( strncmp( str, "em", 2 ) == 0 ) { add_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); } else if ( strncmp( str, "/em", 3 ) == 0 ) { remove_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); } } static void form_begin (HTMLEngine *e, HTMLObject *clue, gchar *action, gchar *method, gboolean close_paragraph) { e->form = html_form_new (e, action, method); e->formList = g_list_append (e->formList, e->form); if (! e->avoid_para && close_paragraph) { close_anchor (e); if (e->flow && HTML_CLUE (e->flow)->head) close_flow (e, clue); e->avoid_para = FALSE; e->pending_para = FALSE; } } static void form_end (HTMLEngine *e, gboolean close_paragraph) { e->form = NULL; if (! e->avoid_para && close_paragraph) { close_anchor (e); e->avoid_para = TRUE; e->pending_para = TRUE; } } /*
partial */ /* EP CHECK: Fonts are done wrong, the rest is missing. */ static void parse_f (HTMLEngine *e, HTMLObject *clue, const gchar *str) { if (strncmp (str, "font", 4) == 0) { GdkColor *color; HTMLColor *html_color = NULL; const HTMLFontFace *face = NULL; gint oldSize, newSize; oldSize = newSize = current_font_style (e) & GTK_HTML_FONT_STYLE_SIZE_MASK; /* The GdkColor API is not const safe! */ color = gdk_color_copy ((GdkColor *) current_color (e)); html_string_tokenizer_tokenize (e->st, str + 5, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "size=", 5) == 0) { gint num = atoi (token + 5); /* FIXME implement basefont */ if (*(token + 5) == '+' || *(token + 5) == '-') newSize = GTK_HTML_FONT_STYLE_SIZE_3 + num; else newSize = num; if (newSize > GTK_HTML_FONT_STYLE_SIZE_MAX) newSize = GTK_HTML_FONT_STYLE_SIZE_MAX; else if (newSize < GTK_HTML_FONT_STYLE_SIZE_1) newSize = GTK_HTML_FONT_STYLE_SIZE_1; } else if (strncasecmp (token, "face=", 5) == 0) { face = token + 5; } else if (strncasecmp (token, "color=", 6) == 0) { parse_color (token + 6, color); html_color = html_color_new_from_gdk_color (color); } } if (html_color) { push_color (e, html_color); html_color_unref (html_color); } push_font_face (e, face); if (oldSize != newSize) add_font_style (e, newSize); push_block (e, ID_FONT, 1, block_end_color_font, oldSize != newSize, html_color != NULL); } else if (strncmp (str, "/font", 5) == 0) { pop_block (e, ID_FONT, clue); } else if (strncmp (str, "form", 4) == 0) { gchar *action = NULL; gchar *method = "GET"; gchar *target = NULL; html_string_tokenizer_tokenize (e->st, str + 5, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if ( strncasecmp( token, "action=", 7 ) == 0 ) { action = g_strdup (token + 7); } else if ( strncasecmp( token, "method=", 7 ) == 0 ) { if ( strncasecmp( token + 7, "post", 4 ) == 0 ) method = "POST"; } else if ( strncasecmp( token, "target=", 7 ) == 0 ) { target = g_strdup(token + 7); } } form_begin (e, clue, action, method, TRUE); g_free(action); g_free(target); if (! e->avoid_para) { close_anchor (e); e->avoid_para = TRUE; e->pending_para = TRUE; } } else if (strncmp (str, "/form", 5) == 0) { form_end (e, TRUE); } else if (strncmp (str, "frameset", 8) == 0) { if (e->allow_frameset) parse_frameset (e, clue, clue->max_width, str + 8); } else if (strncasecmp (str, "/frameset", 9) == 0) { if (!html_stack_is_empty (e->frame_stack)) html_stack_pop (e->frame_stack); } else if (strncasecmp (str, "frame", 5) == 0) { char *src = NULL; HTMLObject *frame = NULL; gint margin_height = -1; gint margin_width = -1; GtkPolicyType scroll = GTK_POLICY_AUTOMATIC; if (!e->allow_frameset) return; src = NULL; html_string_tokenizer_tokenize (e->st, str + 5, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const gchar *token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "src=", 4) == 0) { src = g_strdup (token + 4); } else if (strncasecmp (token, "noresize", 8) == 0) { } else if (strncasecmp (token, "frameborder=", 12) == 0) { } else if (strncasecmp (token, "border=", 7) == 0) { /* * Netscape and Mozilla recognize this to turn of all the between * frame decoration. */ } else if (strncasecmp(token, "marginwidth=", 12) == 0) { margin_width = atoi (token + 12); } else if (strncasecmp(token, "marginheight=", 13) == 0) { margin_height = atoi (token + 13); } else if (strncasecmp(token, "scrolling=", 10) == 0) { scroll = parse_scroll (token + 10); } } frame = html_frame_new (GTK_WIDGET (e->widget), src, -1 , -1, FALSE); if (!html_frameset_append (html_stack_top (e->frame_stack), frame)) html_object_destroy (frame); if (margin_height > 0) html_frame_set_margin_height (HTML_FRAME (frame), margin_height); if (margin_width > 0) html_frame_set_margin_width (HTML_FRAME (frame), margin_width); if (scroll != GTK_POLICY_AUTOMATIC) html_frame_set_scrolling (HTML_FRAME (frame), scroll); g_free (src); } } /*
= '1' && str[1] <= '6')) { HTMLHAlignType align; align = p->pAlign; html_string_tokenizer_tokenize (p->st, str + 3, " >"); while (html_string_tokenizer_has_more_tokens (p->st)) { const gchar *token; token = html_string_tokenizer_next_token (p->st); if ( strncasecmp( token, "align=", 6 ) == 0 ) { align = parse_halign (token + 6, align); } } /* Start a new flow box */ push_clueflow_style (p, HTML_CLUEFLOW_STYLE_H1 + (str[1] - '1')); close_flow (p, clue); push_block (p, ID_HEADER, 2, block_end_clueflow_style, p->pAlign, 0); p->pAlign = align; p->pending_para = FALSE; p->avoid_para = TRUE; } else if (*(str) == '/' && *(str + 1) == 'h' && (*(str + 2) >= '1' && *(str + 2) <= '6')) { /* Close tag. */ pop_block (p, ID_HEADER, clue); p->avoid_para = TRUE; p->pending_para = FALSE; } else if (strncmp (str, "hr", 2) == 0) { gint size = 2; gint length = clue->max_width; gint percent = 100; HTMLHAlignType align = HTML_HALIGN_CENTER; gboolean shade = TRUE; html_string_tokenizer_tokenize (p->st, str + 3, " >"); while (html_string_tokenizer_has_more_tokens (p->st)) { gchar *token = html_string_tokenizer_next_token (p->st); if (strncasecmp (token, "align=", 6) == 0) { align = parse_halign (token + 6, align); } else if (strncasecmp (token, "size=", 5) == 0) { size = atoi (token + 5); } else if (strncasecmp (token, "width=", 6) == 0) { if (strchr (token + 6, '%')) percent = atoi (token + 6); else if (isdigit (*(token + 6))) { length = atoi (token + 6); percent = 0; } } else if (strncasecmp (token, "noshade", 7) == 0) { shade = FALSE; } } append_element (p, clue, html_rule_new (length, percent, size, shade, align)); } } /* ' missing. */ static void parse_i (HTMLEngine *e, HTMLObject *_clue, const gchar *str) { if (strncmp (str, "img", 3) == 0) { HTMLObject *image = 0; HTMLHAlignType align = HTML_HALIGN_NONE; HTMLVAlignType valign = HTML_VALIGN_NONE; HTMLColor *color = NULL; gchar *token = 0; gchar *tmpurl = NULL; gchar *mapname = NULL; gchar *id = NULL; gchar *alt = NULL; gint width = -1; gint height = -1; gint border = 0; gint hspace = 0; gint vspace = 0; gboolean percent_width = FALSE; gboolean percent_height = FALSE; gboolean ismap = FALSE; color = current_color (e); if (e->url != NULL || e->target != NULL) border = 2; if (e->url != NULL || e->target != NULL) border = 2; html_string_tokenizer_tokenize (e->st, str + 4, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "src=", 4) == 0) { tmpurl = g_strdup (token + 4); } else if (strncasecmp (token, "width=", 6) == 0) { if (isdigit (*(token + 6))) width = atoi (token + 6); percent_width = strchr (token + 6, '%') ? TRUE : FALSE; } else if (strncasecmp (token, "height=", 7) == 0) { if (isdigit (*(token + 7))) height = atoi (token + 7); percent_height = strchr (token + 7, '%') ? TRUE : FALSE; } else if (strncasecmp (token, "border=", 7) == 0) { border = atoi (token + 7); } else if (strncasecmp (token, "hspace=", 7) == 0) { hspace = atoi (token + 7); } else if (strncasecmp (token, "vspace=", 7) == 0) { vspace = atoi (token + 7); } else if (strncasecmp (token, "align=", 6) == 0) { if (strcasecmp (token + 6, "left") == 0) align = HTML_HALIGN_LEFT; else if (strcasecmp (token + 6, "right") == 0) align = HTML_HALIGN_RIGHT; else if (strcasecmp (token + 6, "top") == 0) valign = HTML_VALIGN_TOP; else if (strcasecmp (token + 6, "middle") == 0) valign = HTML_VALIGN_MIDDLE; else if (strcasecmp (token + 6, "bottom") ==0) valign = HTML_VALIGN_BOTTOM; } else if (strncasecmp (token, "id=", 3) == 0) { id = token + 3; } else if (strncasecmp (token, "alt=", 4) == 0) { alt = g_strdup (token + 4); } else if (strncasecmp (token, "usemap=", 7) == 0) { mapname = g_strdup (token + 7); } else if (strncasecmp (token, "ismap", 5) == 0) { ismap = TRUE; } } if (tmpurl != 0) { if (align != HTML_HALIGN_NONE) valign = HTML_VALIGN_BOTTOM; else if (valign == HTML_VALIGN_NONE) valign = HTML_VALIGN_BOTTOM; image = html_image_new (e->image_factory, tmpurl, e->url, e->target, width, height, percent_width, percent_height, border, color, valign, FALSE); if (id) { html_engine_add_object_with_id (e, id, (HTMLObject *) image); } if (hspace < 0) hspace = 0; if (vspace < 0) vspace = 0; html_image_set_spacing (HTML_IMAGE (image), hspace, vspace); if (alt) { html_image_set_alt (HTML_IMAGE (image), alt); g_free (alt); } html_image_set_map (HTML_IMAGE (image), mapname, ismap); g_free (tmpurl); g_free (mapname); if (align == HTML_HALIGN_NONE) { append_element (e, _clue, image); } else { /* We need to put the image in a HTMLClueAligned. */ /* Man, this is *so* gross. */ HTMLClueAligned *aligned = HTML_CLUEALIGNED (html_cluealigned_new (NULL, 0, 0, _clue->max_width, 100)); HTML_CLUE (aligned)->halign = align; html_clue_append (HTML_CLUE (aligned), HTML_OBJECT (image)); append_element (e, _clue, HTML_OBJECT (aligned)); } } } else if (strncmp( str, "input", 5 ) == 0) { gboolean fix_form = FALSE; if (e->form == NULL) { fix_form = TRUE; form_begin (e, _clue, NULL, "GET", FALSE); } parse_input (e, str + 6, _clue ); if (fix_form) { form_end (e, FALSE); } } else if (strncmp( str, "iframe", 6) == 0) { parse_iframe (e, str + 7, _clue); } else if ( strncmp (str, "i", 1 ) == 0 ) { if ( str[1] == '>' || str[1] == ' ' ) { add_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); } } else if ( strncmp( str, "/i", 2 ) == 0 ) { remove_font_style (e, GTK_HTML_FONT_STYLE_ITALIC); } } /* */ /* EP CHECK: OK but font is wrong. */ static void parse_k (HTMLEngine *e, HTMLObject *_clue, const gchar *str) { if ( strncmp(str, "kbd", 3 ) == 0 ) { add_font_style (e, GTK_HTML_FONT_STYLE_FIXED); } else if ( strncmp(str, "/kbd", 4 ) == 0 ) { remove_font_style (e, GTK_HTML_FONT_STYLE_FIXED); } } static HTMLListType get_list_type (gchar c) { switch (c) { case 'i': return HTML_LIST_TYPE_ORDERED_LOWER_ROMAN; case 'I': return HTML_LIST_TYPE_ORDERED_UPPER_ROMAN; case 'a': return HTML_LIST_TYPE_ORDERED_LOWER_ALPHA; case 'A': return HTML_LIST_TYPE_ORDERED_UPPER_ALPHA; case '1': default: return HTML_LIST_TYPE_ORDERED_ARABIC; } } /* */ /* EP CHECK: OK */ static void parse_l (HTMLEngine *p, HTMLObject *clue, const gchar *str) { if (strncmp (str, "link", 4) == 0) { } else if (strncmp (str, "li", 2) == 0) { HTMLListType listType; gint listLevel; gint itemNumber; listType = HTML_LIST_TYPE_UNORDERED; listLevel = 1; itemNumber = 1; close_anchor (p); if (!html_stack_is_empty (p->listStack)) { HTMLList *top; top = html_stack_top (p->listStack); listType = top->type; itemNumber = top->itemNumber; } html_string_tokenizer_tokenize (p->st, str + 3, " >"); while (html_string_tokenizer_has_more_tokens (p->st)) { const gchar *token = html_string_tokenizer_next_token (p->st); if (!strncasecmp (token, "value=", 6)) itemNumber = atoi (token + 6); else if (!strncasecmp (token, "type=", 5)) listType = get_list_type (token [5]); } add_pending_paragraph_break (p, clue); finish_flow (p, clue); if (!html_stack_is_empty (p->listStack)) { HTMLList *list; list = html_stack_top (p->listStack); list->itemNumber = itemNumber + 1; } p->flow = flow_new (p, HTML_CLUEFLOW_STYLE_LIST_ITEM, listType, itemNumber, HTML_CLEAR_NONE); html_clueflow_set_item_color (HTML_CLUEFLOW (p->flow), current_color (p)); html_clue_append (HTML_CLUE (clue), p->flow); p->avoid_para = TRUE; } else if (strncmp (str, "/li", 3) == 0) { finish_flow (p, clue); } } /* st, str + 5, " >" ); while ( html_string_tokenizer_has_more_tokens (e->st) ) { const gchar* token = html_string_tokenizer_next_token(e->st); if ( strncasecmp( token, "http-equiv=", 11 ) == 0 ) { if ( strncasecmp( token + 11, "refresh", 7 ) == 0 ) refresh = 1; } else if ( strncasecmp( token, "content=", 8 ) == 0 ) { if (refresh) { const gchar *content; content = token + 8; /* The time in seconds until the refresh */ refresh_delay = atoi(content); html_string_tokenizer_tokenize(e->st, content, ",;> "); while ( html_string_tokenizer_has_more_tokens (e->st) ) { const gchar* token = html_string_tokenizer_next_token(e->st); if ( strncasecmp( token, "url=", 4 ) == 0 ) refresh_url = g_strdup (token + 4); } gtk_signal_emit (GTK_OBJECT (e), signals[REDIRECT], refresh_url, refresh_delay); if(refresh_url) g_free(refresh_url); } } } } else if (strncmp (str, "map", 3) == 0) { html_string_tokenizer_tokenize (e->st, str + 3, " >"); while (html_string_tokenizer_has_more_tokens (e->st)) { const char* token = html_string_tokenizer_next_token (e->st); if (strncasecmp (token, "name=", 5) == 0) { const char *name = token + 5; e->map = HTML_MAP (html_map_new (name)); if (e->map == NULL) return; html_engine_add_map (e, e->map); } } } else if (strncmp (str, "/map", 4) == 0) { e->map = NULL; } } static void parse_n (HTMLEngine *e, HTMLObject *_clue, const gchar *str ) { if (strncasecmp (str, "noframe", 7) == 0) { static const char *end[] = {"allow_frameset) discard_body (e, end); } } /*
partial