📄 html.c
字号:
/* * File: html.c * * Copyright (C) 1997 Raph Levien <raph@acm.org> * Copyright (C) 1999 James McCollough <jamesm@gtwn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * Dillo HTML parsing routines */#define USE_TABLES#include <ctype.h> /* for isspace and tolower */#include <string.h> /* for memcpy and memmove */#include <stdlib.h>#include <stdio.h> /* for sprintf */#include <math.h> /* for rint */#include <gtk/gtk.h>#include "list.h"#include "colors.h"#include "dillo.h"#include "history.h"#include "nav.h"#include "menu.h"#include "commands.h"#include "dw.h" /* for Dw_cursor_hand */#include "dw_widget.h"#include "dw_page.h"#include "dw_bullet.h"#include "dw_button.h"#include "dw_hruler.h"#include "dw_embed_gtk.h"#include "dw_table.h"#include "dw_list_item.h"#include "IO/IO.h"#include "IO/Url.h"#include "interface.h"#include "progressbar.h"#include "prefs.h"#include "misc.h"//#define DEBUG_LEVEL 3#include "debug.h"typedef void (*TagFunct) (DilloHtml *Html, char *Tag, gint Tagsize);#define TAB_SIZE 8/* * Forward declarations */static const char *Html_get_attr(DilloHtml *html, const char *tag, gint tagsize, const char *attrname);static const char *Html_get_attr2(DilloHtml *html, const char *tag, gint tagsize, const char *attrname, DilloHtmlTagParsingFlags flags);static void Html_add_widget(DilloHtml *html, DwWidget *widget, char *width_str, char *height_str, DwStyle *style_attrs);static void Html_write(DilloHtml *html, char *Buf, gint BufSize, gint Eof);static void Html_close(DilloHtml *html, gint ClientKey);static void Html_callback(int Op, CacheClient_t *Client);static DilloHtml *Html_new(BrowserWindow *bw, const DilloUrl *url);static void Html_tag_open_input(DilloHtml *html, char *tag, gint tagsize);/* * Local Data */static const char *roman_I0[] ={"I","II","III","IV","V","VI","VII","VIII","IX"}, *roman_I1[] ={"X","XX","XXX","XL","L","LX","LXX","LXXX","XC"}, *roman_I2[] ={"C","CC","CCC","CD","D","DC","DCC","DCCC","CM"}, *roman_I3[] ={"M","MM","MMM","MMMM"};/* The following array of font sizes has to be _strictly_ crescent */static const gint FontSizes[] = {8, 10, 12, 14, 18, 24};static const gint FontSizesNum = 6;static const gint FontSizesBase = 2;/* * Set callback function and callback data for "html/text" MIME type. */DwWidget *a_Html_text(const char *Type, void *P, CA_Callback_t *Call, void **Data){ DilloWeb *web = P; DilloHtml *html = Html_new(web->bw, web->url); *Data = (void *) html; *Call = (CA_Callback_t) Html_callback; return html->dw;}/* * We'll make the linkblock first to get it out of the way. */static DilloHtmlLB *Html_lb_new(BrowserWindow *bw, const DilloUrl *url){ DilloHtmlLB *html_lb = g_new(DilloHtmlLB, 1); html_lb->bw = bw; html_lb->base_url = a_Url_dup(url); html_lb->num_forms_max = 1; html_lb->num_forms = 0; html_lb->forms = NULL; html_lb->num_links_max = 1; html_lb->num_links = 0; html_lb->links = NULL; a_Dw_image_map_list_init(&html_lb->maps); html_lb->link_color = prefs.link_color; html_lb->visited_color = prefs.visited_color; return html_lb;}/* * Free the memory used by the linkblock */static void Html_lb_free(void *lb){ gint i, j, k; DilloHtmlForm *form; DilloHtmlLB *html_lb = lb; DEBUG_MSG(3, "Html_lb_free\n"); a_Url_free(html_lb->base_url); for (i = 0; i < html_lb->num_forms; i++) { form = &html_lb->forms[i]; a_Url_free(form->action); for (j = 0; j < form->num_inputs; j++) { g_free(form->inputs[j].name); g_free(form->inputs[j].init_str); if (form->inputs[j].type == DILLO_HTML_INPUT_SELECT || form->inputs[j].type == DILLO_HTML_INPUT_SEL_LIST) { for(k = 0; k < form->inputs[j].select->num_options; k++) { g_free(form->inputs[j].select->options[k].value); } g_free(form->inputs[j].select->options); g_free(form->inputs[j].select); } } g_free(form->inputs); } g_free(html_lb->forms); for (i = 0; i < html_lb->num_links; i++) if (html_lb->links[i]) a_Url_free(html_lb->links[i]); g_free(html_lb->links); a_Dw_image_map_list_free(&html_lb->maps); g_free(html_lb);}/* * Set the URL data for image maps. */static void Html_set_link_coordinates(DilloHtmlLB *lb, gint link, gint x, gint y){ gchar data[32]; if (x != -1) { sprintf(data, "?%d,%d", x, y); a_Url_set_ismap_coords(lb->links[link], data); }}/* * Handle the status function generated by the dw scroller, * and show the url in the browser status-bar. */static void Html_handle_status(DwWidget *widget, gint link, gint x, gint y, DilloHtmlLB *lb){ DilloUrl *url; url = (link == -1) ? NULL : lb->links[link]; if (url) { Html_set_link_coordinates(lb, link, x, y); a_Interface_msg(lb->bw, "%s", URL_ALT_(url) ? URL_ALT_(url) : URL_STR_(url)); a_Dw_widget_set_cursor (widget, Dw_cursor_hand); lb->bw->status_is_link = 1; } else { if (lb->bw->status_is_link) a_Interface_msg(lb->bw, ""); a_Dw_widget_set_cursor (widget, NULL); }}/* * Popup the link menu ("link_pressed" callback of the page) */static void Html_link_menu(DwWidget *widget, gint link, gint x, gint y, GdkEventButton *event, DilloHtmlLB *lb){ if (event->button == 3) { Html_set_link_coordinates(lb, link, x, y); a_Menu_popup_set_url(lb->bw, lb->links[link]); gtk_menu_popup(GTK_MENU(lb->bw->menu_popup.over_link), NULL, NULL, NULL, NULL, event->button, event->time); }}/* * Activate a link ("link_clicked" callback of the page) */static void Html_link_clicked(DwWidget *widget, gint link, gint x, gint y, GdkEventButton *event, DilloHtmlLB *lb){ DwPage *page; DwStyle *old_style, style_attrs; gint i, j, changed; Html_set_link_coordinates(lb, link, x, y); if (event->button == 1) a_Nav_push(lb->bw, lb->links[link]); else if (event->button == 2) { a_Menu_popup_set_url(lb->bw, lb->links[link]); a_Commands_open_link_nw_callback(NULL, lb->bw); } /* * This is only a workaround to visualize links opened in a new * window. It will definitely change. */ if (DW_IS_PAGE (widget)) { page = DW_PAGE (widget); for (i = 0; i < page->num_lines; i++) { changed = FALSE; for (j = page->lines[i].first_word; j < page->lines[i].last_word; j++) if (page->words[j].style->link == link) { old_style = page->words[j].style; style_attrs = *old_style; style_attrs.color = a_Dw_style_color_new (lb->visited_color, widget->viewport->window); page->words[j].style = a_Dw_style_new (&style_attrs, widget->viewport->window); /* unref'ing it before may crash dillo! */ a_Dw_style_unref (old_style); changed = TRUE; } if (changed) p_Dw_widget_queue_draw_area (widget, 0, page->lines[i].top, widget->allocation.width, page->lines[i].ascent + page->lines[i].descent); } } /* end workaround */}/* * Popup the page menu ("button_press_event" callback of the viewport) */static int Html_page_menu(GtkWidget *viewport, GdkEventButton *event, BrowserWindow *bw){ if (event->button == 3) { a_Menu_popup_set_url(bw, a_History_get_url(NAV_TOP(bw))); gtk_menu_popup(GTK_MENU(bw->menu_popup.over_page), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } else return FALSE;}/* * Connect all signals of a page or an image. */static void Html_connect_signals(DilloHtml *html, GtkObject *widget){ gtk_signal_connect (widget, "link_entered", GTK_SIGNAL_FUNC(Html_handle_status), (gpointer)html->linkblock); gtk_signal_connect (widget, "link_pressed", GTK_SIGNAL_FUNC(Html_link_menu), (gpointer)html->linkblock); gtk_signal_connect (widget, "link_clicked", GTK_SIGNAL_FUNC(Html_link_clicked), (gpointer)html->linkblock);}/* * Create a new link in the linkblock, set it as the url's parent * and return the index. */static gint Html_set_new_link(DilloHtml *html, DilloUrl **url){ gint nl; nl = html->linkblock->num_links; a_List_add(html->linkblock->links, nl, html->linkblock->num_links_max); html->linkblock->links[nl] = (*url) ? *url : NULL; return html->linkblock->num_links++;}/* * Allocate and insert form information into the Html linkblock */static gint Html_form_new(DilloHtmlLB *html_lb, DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc enc){ gint nf; a_List_add(html_lb->forms, html_lb->num_forms, html_lb->num_forms_max); nf = html_lb->num_forms; html_lb->forms[nf].method = method; html_lb->forms[nf].action = a_Url_dup(action); html_lb->forms[nf].enc = enc; html_lb->forms[nf].num_inputs = 0; html_lb->forms[nf].num_inputs_max = 4; html_lb->forms[nf].inputs = NULL; html_lb->forms[nf].num_entry_fields = 0; html_lb->forms[nf].num_submit_buttons = 0; html_lb->num_forms++; // g_print("Html_form_new: action=%s nform=%d\n", action, nf); return nf;}/* * Change one toplevel attribute. var should be an identifier. val is * only evaluated once, so you can safely use a function call for it. */#define HTML_SET_TOP_ATTR(html, var, val) \ do { \ DwStyle style_attrs, *old_style; \ \ old_style = (html)->stack[(html)->stack_top].style; \ style_attrs = *old_style; \ style_attrs.var = (val); \ (html)->stack[(html)->stack_top].style = \ a_Dw_style_new (&style_attrs, (html)->bw->main_window->window); \ a_Dw_style_unref (old_style); \ } while (FALSE)/* * Set the font at the top of the stack. BImask specifies which * attributes in BI should be changed. */static void Html_set_top_font(DilloHtml *html, gchar *name, gint size, gint BI, gint BImask){ DwStyleFont font_attrs; font_attrs = *html->stack[(html)->stack_top].style->font; if ( name ) font_attrs.name = name; if ( size ) font_attrs.size = size; if ( BImask & 1 ) font_attrs.bold = (BI & 1) ? TRUE : FALSE; if ( BImask & 2 ) font_attrs.italic = (BI & 2) ? TRUE : FALSE; HTML_SET_TOP_ATTR (html, font, a_Dw_style_font_new (&font_attrs));}/* * Evaluates the ALIGN attribute (reft|center|right|justify) and * sets the style at the top of the stack. */static void Html_tag_set_align_attr(DilloHtml *html, char *tag, gint tagsize){ const char *align; if ((align = Html_get_attr(html, tag, tagsize, "align"))) { if (strcasecmp (align, "left") == 0) HTML_SET_TOP_ATTR (html, text_align, DW_STYLE_TEXT_ALIGN_LEFT); else if (strcasecmp (align, "right") == 0) HTML_SET_TOP_ATTR (html, text_align, DW_STYLE_TEXT_ALIGN_RIGHT); else if (strcasecmp (align, "center") == 0) HTML_SET_TOP_ATTR (html, text_align, DW_STYLE_TEXT_ALIGN_CENTER); else if (strcasecmp (align, "justify") == 0) HTML_SET_TOP_ATTR (html, text_align, DW_STYLE_TEXT_ALIGN_JUSTIFY); }}/* * Add a new DwPage into the current DwPage, for indentation. * left and right are the horizontal indentation amounts, space is the * vertical space around the block. */static void Html_add_indented_widget(DilloHtml *html, DwWidget *page,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -