diff options
author | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
---|---|---|
committer | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
commit | f5c598b518d1f906148534d015f50075d3e8242d (patch) | |
tree | 21dd70add5b366c3dd80641b77f6b18e0baa009e /src/html.cc | |
parent | e98d02a01ffeb18ede86af025e51ae1ec011c75a (diff) | |
parent | 5f0fc0e48b8cbee7e1795935da0abff6627fd498 (diff) |
merge
Diffstat (limited to 'src/html.cc')
-rw-r--r-- | src/html.cc | 2068 |
1 files changed, 1033 insertions, 1035 deletions
diff --git a/src/html.cc b/src/html.cc index 70466979..49d06da3 100644 --- a/src/html.cc +++ b/src/html.cc @@ -20,20 +20,17 @@ #include <string.h> /* for memcpy and memmove */ #include <stdlib.h> #include <stdio.h> /* for sprintf */ -#include <math.h> /* for rint */ #include <errno.h> -#include <fltk/utf.h> /* for utf8encode */ - #include "bw.h" /* for BrowserWindow */ #include "msg.h" #include "binaryconst.h" #include "colors.h" +#include "utf8.hh" #include "misc.h" #include "uicmd.hh" #include "history.h" -#include "nav.h" #include "menu.hh" #include "prefs.h" #include "capi.h" @@ -49,7 +46,7 @@ #include "dw/ruler.hh" /*----------------------------------------------------------------------------- - * Defines + * Defines *---------------------------------------------------------------------------*/ /* Define to 1 to ignore white space immediately after an open tag, @@ -61,6 +58,7 @@ /*----------------------------------------------------------------------------- * Name spaces *---------------------------------------------------------------------------*/ +using namespace lout; using namespace dw; using namespace dw::core; using namespace dw::core::ui; @@ -106,24 +104,15 @@ static const char *Html_get_attr2(DilloHtml *html, int tagsize, const char *attrname, int tag_parsing_flags); -static void Html_add_widget(DilloHtml *html, Widget *widget, - char *width_str, char *height_str, - StyleAttrs *style_attrs); static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof); -static void Html_load_image(BrowserWindow *bw, DilloUrl *url, - DilloImage *image); +static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, + const DilloUrl *requester, DilloImage *image); static void Html_callback(int Op, CacheClient_t *Client); -static int Html_tag_index(const char *tag); static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx); /*----------------------------------------------------------------------------- * Local Data *---------------------------------------------------------------------------*/ -/* The following array of font sizes has to be _strictly_ increasing */ -static const int FontSizes[] = {10, 12, 14, 18, 22, 28}; -static const int FontSizesNum = 6; -static const int FontSizesBase = 2; - /* Parsing table structure */ typedef struct { const char *name; /* element name */ @@ -210,7 +199,7 @@ static void Html_free(void *data) /* * Used by the "Load images" page menuitem. - */ + */ void a_Html_load_images(void *v_html, DilloUrl *pattern) { DilloHtml *html = (DilloHtml*)v_html; @@ -219,6 +208,58 @@ void a_Html_load_images(void *v_html, DilloUrl *pattern) } /* + * Search for form + */ +static bool Html_contains_form(DilloHtml *html, void *v_form) +{ + for (int i = 0; i < html->forms->size(); i++) { + if (html->forms->get(i) == v_form) { + return true; + } + } + return false; +} + +/* + * Used by the "Submit form" form menuitem. + */ +void a_Html_form_submit(void *v_html, void *v_form) +{ + DilloHtml *html = (DilloHtml*)v_html; + + if (Html_contains_form(html, v_form)) { + /* it's still valid */ + a_Html_form_submit2(v_form); + } +} + +/* + * Used by the "Reset form" form menuitem. + */ +void a_Html_form_reset(void *v_html, void *v_form) +{ + DilloHtml *html = (DilloHtml*)v_html; + + if (Html_contains_form(html, v_form)) { + /* it's still valid */ + a_Html_form_reset2(v_form); + } +} + +/* + * Used by the "Show/Hide hiddens" form menuitem. + */ +void a_Html_form_display_hiddens(void *v_html, void *v_form, bool_t display) +{ + DilloHtml *html = (DilloHtml*)v_html; + + if (Html_contains_form(html, v_form)) { + /* it's still valid */ + a_Html_form_display_hiddens2(v_form, (display != 0)); + } +} + +/* * Set the URL data for image maps. */ static void Html_set_link_coordinates(DilloHtml *html, int link, int x, int y) @@ -244,42 +285,20 @@ static int Html_set_new_link(DilloHtml *html, DilloUrl **url) } /* - * Add a new image. + * Add a new image to our list. + * image is NULL if dillo will try to load the image immediately. */ -static int Html_add_new_linkimage(DilloHtml *html, - DilloUrl **url, DilloImage *image) +static void Html_add_new_htmlimage(DilloHtml *html, + DilloUrl **url, DilloImage *image) { - DilloLinkImage *li = dNew(DilloLinkImage, 1); - li->url = *url; - li->image = image; + DilloHtmlImage *hi = dNew(DilloHtmlImage, 1); + hi->url = *url; + hi->image = image; + a_Image_ref(image); - int ni = html->images->size(); + int n = html->images->size(); html->images->increase(); - html->images->set(ni, li); - return ni; -} - -/* - * Set the font at the top of the stack. BImask specifies which - * attributes in BI should be changed. - */ -void a_Html_set_top_font(DilloHtml *html, const char *name, int size, - int BI, int BImask) -{ - FontAttrs font_attrs; - - font_attrs = *S_TOP(html)->style->font; - if (name) - font_attrs.name = name; - if (size) - font_attrs.size = size; - if (BImask & 1) - font_attrs.weight = (BI & 1) ? 700 : 400; - if (BImask & 2) - font_attrs.style = (BI & 2) ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL; - - HTML_SET_TOP_ATTR (html, font, - Font::create (HT2LT(html), &font_attrs)); + html->images->set(n, hi); } /* @@ -287,25 +306,26 @@ void a_Html_set_top_font(DilloHtml *html, const char *name, int size, * sets the style at the top of the stack. */ void a_Html_tag_set_align_attr(DilloHtml *html, + CssPropertyList *props, const char *tag, int tagsize) { - const char *align, *charattr; + const char *align; if ((align = a_Html_get_attr(html, tag, tagsize, "align"))) { - Style *old_style = S_TOP(html)->style; - StyleAttrs style_attrs = *old_style; + TextAlignType textAlignType = TEXT_ALIGN_LEFT; if (dStrcasecmp (align, "left") == 0) - style_attrs.textAlign = TEXT_ALIGN_LEFT; + textAlignType = TEXT_ALIGN_LEFT; else if (dStrcasecmp (align, "right") == 0) - style_attrs.textAlign = TEXT_ALIGN_RIGHT; + textAlignType = TEXT_ALIGN_RIGHT; else if (dStrcasecmp (align, "center") == 0) - style_attrs.textAlign = TEXT_ALIGN_CENTER; + textAlignType = TEXT_ALIGN_CENTER; else if (dStrcasecmp (align, "justify") == 0) - style_attrs.textAlign = TEXT_ALIGN_JUSTIFY; + textAlignType = TEXT_ALIGN_JUSTIFY; +#if 0 else if (dStrcasecmp (align, "char") == 0) { /* TODO: Actually not supported for <p> etc. */ - style_attrs.textAlign = TEXT_ALIGN_STRING; + v.textAlign = TEXT_ALIGN_STRING; if ((charattr = a_Html_get_attr(html, tag, tagsize, "char"))) { if (charattr[0] == 0) /* TODO: ALIGN=" ", and even ALIGN="&32;" will reult in @@ -319,8 +339,8 @@ void a_Html_tag_set_align_attr(DilloHtml *html, /* TODO: Examine LANG attr of <html>. */ style_attrs.textAlignChar = '.'; } - S_TOP(html)->style = Style::create (HT2LT(html), &style_attrs); - old_style->unref (); +#endif + props->set (CSS_PROPERTY_TEXT_ALIGN, CSS_TYPE_ENUM, textAlignType); } } @@ -329,19 +349,22 @@ void a_Html_tag_set_align_attr(DilloHtml *html, * sets the style in style_attrs. Returns true when set. */ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, - int tagsize, StyleAttrs *style_attrs) + int tagsize, CssPropertyList *props) { const char *attr; + VAlignType valign; if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) { if (dStrcasecmp (attr, "top") == 0) - style_attrs->valign = VALIGN_TOP; + valign = VALIGN_TOP; else if (dStrcasecmp (attr, "bottom") == 0) - style_attrs->valign = VALIGN_BOTTOM; + valign = VALIGN_BOTTOM; else if (dStrcasecmp (attr, "baseline") == 0) - style_attrs->valign = VALIGN_BASELINE; + valign = VALIGN_BASELINE; else - style_attrs->valign = VALIGN_MIDDLE; + valign = VALIGN_MIDDLE; + + props->set (CSS_PROPERTY_VERTICAL_ALIGN, CSS_TYPE_ENUM, valign); return true; } else return false; @@ -349,84 +372,17 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, /* - * 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. + * Create and add a new Textblock to the current Textblock */ -static void Html_add_indented_widget(DilloHtml *html, Widget *textblock, - int left, int right, int space) +static void Html_add_textblock(DilloHtml *html, int space) { - StyleAttrs style_attrs; - Style *style; - - style_attrs = *S_TOP(html)->style; - - style_attrs.margin.setVal (0); - style_attrs.borderWidth.setVal (0); - style_attrs.padding.setVal(0); - - /* Activate this for debugging */ -#if 0 - style_attrs.borderWidth.setVal (1); - style_attrs.setBorderColor ( - Color::createShaded (HT2LT(html), style_attrs.color->getColor()); - style_attrs.setBorderStyle (BORDER_DASHED); -#endif - - style_attrs.margin.left = left; - style_attrs.margin.right = right; - style = Style::create (HT2LT(html), &style_attrs); + Textblock *textblock = new Textblock (prefs.limit_text_width); - DW2TB(html->dw)->addParbreak (space, style); - DW2TB(html->dw)->addWidget (textblock, style); - DW2TB(html->dw)->addParbreak (space, style); + HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ()); + HT2TB(html)->addWidget (textblock, html->styleEngine->style ()); + HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ()); S_TOP(html)->textblock = html->dw = textblock; S_TOP(html)->hand_over_break = true; - style->unref (); - - /* Handle it when the user clicks on a link */ - html->connectSignals(textblock); -} - -/* - * Create and add a new indented DwPage to the current DwPage - */ -static void Html_add_indented(DilloHtml *html, int left, int right, int space) -{ - Textblock *textblock = new Textblock (prefs.limit_text_width); - Html_add_indented_widget (html, textblock, left, right, space); -} - -/* - * Given a font_size, this will return the correct 'level'. - * (or the closest, if the exact level isn't found). - */ -static int Html_fontsize_to_level(int fontsize) -{ - int i, level; - double normalized_size = fontsize / prefs.font_factor, - approximation = FontSizes[FontSizesNum-1] + 1; - - for (i = level = 0; i < FontSizesNum; i++) - if (approximation >= fabs(normalized_size - FontSizes[i])) { - approximation = fabs(normalized_size - FontSizes[i]); - level = i; - } else { - break; - } - - return level; -} - -/* - * Given a level of a font, this will return the correct 'size'. - */ -static int Html_level_to_fontsize(int level) -{ - level = MAX(0, level); - level = MIN(FontSizesNum - 1, level); - - return (int)rint(FontSizes[level]*prefs.font_factor); } /* @@ -435,19 +391,19 @@ static int Html_level_to_fontsize(int level) DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, const char *content_type) { - /* Init event receiver */ - linkReceiver.html = this; - /* Init main variables */ bw = p_bw; page_url = a_Url_dup(url); base_url = a_Url_dup(url); dw = NULL; + /* Init event receiver */ + linkReceiver.html = this; + HT2LT(this)->connectLink (&linkReceiver); + a_Bw_add_doc(p_bw, this); /* Init for-parsing variables */ - Buf_Consumed = 0; Start_Buf = NULL; Start_Ofs = 0; @@ -466,10 +422,13 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, DocType = DT_NONE; /* assume Tag Soup 0.0! :-) */ DocTypeVersion = 0.0f; + styleEngine = new StyleEngine (HT2LT (this)); + + cssUrls = new misc::SimpleVector <DilloUrl*> (1); + stack = new misc::SimpleVector <DilloHtmlState> (16); stack->increase(); - stack->getRef(0)->style = NULL; - stack->getRef(0)->table_cell_style = NULL; + stack->getRef(0)->table_cell_props = NULL; stack->getRef(0)->parse_mode = DILLO_HTML_PARSE_MODE_INIT; stack->getRef(0)->table_mode = DILLO_HTML_TABLE_MODE_NONE; stack->getRef(0)->cell_text_align_set = false; @@ -479,7 +438,6 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, stack->getRef(0)->textblock = NULL; stack->getRef(0)->table = NULL; stack->getRef(0)->ref_list_item = NULL; - stack->getRef(0)->current_bg_color = prefs.bg_color; stack->getRef(0)->hand_over_break = false; InFlags = IN_NONE; @@ -490,29 +448,24 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, pre_column = 0; PreFirstChar = false; PrevWasCR = false; - PrevWasOpenTag = false; - PrevWasSPC = false; InVisitedLink = false; ReqTagClose = false; - CloseOneTag = false; TagSoup = true; - NameVal = NULL; + loadCssFromStash = false; Num_HTML = Num_HEAD = Num_BODY = Num_TITLE = 0; attr_data = dStr_sized_new(1024); - parse_finished = false; + non_css_link_color = -1; + non_css_visited_color = -1; + visited_color = -1; /* Init page-handling variables */ forms = new misc::SimpleVector <DilloHtmlForm*> (1); inputs_outside_form = new misc::SimpleVector <DilloHtmlInput*> (1); links = new misc::SimpleVector <DilloUrl*> (64); - images = new misc::SimpleVector <DilloLinkImage*> (16); - //a_Dw_image_map_list_init(&maps); - - link_color = prefs.link_color; - visited_color = prefs.visited_color; + images = new misc::SimpleVector <DilloHtmlImage*> (16); /* Initialize the main widget */ initDw(); @@ -521,34 +474,15 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, } /* - * Miscelaneous initializations for Dw + * Miscellaneous initializations for Dw */ void DilloHtml::initDw() { - StyleAttrs style_attrs; - FontAttrs font_attrs; - dReturn_if_fail (dw == NULL); /* Create the main widget */ dw = stack->getRef(0)->textblock = new Textblock (prefs.limit_text_width); - /* Create a dummy font, attribute, and tag for the bottom of the stack. */ - font_attrs.name = prefs.vw_fontname; - font_attrs.size = Html_level_to_fontsize(FontSizesBase); - font_attrs.weight = 400; - font_attrs.style = FONT_STYLE_NORMAL; - - style_attrs.initValues (); - style_attrs.font = Font::create (HT2LT(this), &font_attrs); - style_attrs.color = Color::createSimple (HT2LT(this), prefs.text_color); - stack->getRef(0)->style = Style::create (HT2LT(this), &style_attrs); - - stack->getRef(0)->table_cell_style = NULL; - - /* Handle it when the user clicks on a link */ - connectSignals(dw); - bw->num_page_bugs = 0; dStr_truncate(bw->page_bugs, 0); } @@ -560,14 +494,17 @@ DilloHtml::~DilloHtml() { _MSG("::~DilloHtml(this=%p)\n", this); - if (!parse_finished) - freeParseData(); + freeParseData(); a_Bw_remove_doc(bw, this); a_Url_free(page_url); a_Url_free(base_url); + for (int i = 0; i < cssUrls->size(); i++) + a_Url_free(cssUrls->get(i)); + delete (cssUrls); + for (int i = 0; i < forms->size(); i++) a_Html_form_delete (forms->get(i)); delete(forms); @@ -577,28 +514,18 @@ DilloHtml::~DilloHtml() delete(inputs_outside_form); for (int i = 0; i < links->size(); i++) - if (links->get(i)) - a_Url_free(links->get(i)); + a_Url_free(links->get(i)); delete (links); for (int i = 0; i < images->size(); i++) { - DilloLinkImage *li = images->get(i); - a_Url_free(li->url); - if (li->image) - a_Image_unref(li->image); - dFree(li); + DilloHtmlImage *img = images->get(i); + a_Url_free(img->url); + a_Image_unref(img->image); + dFree(img); } delete (images); - //a_Dw_image_map_list_free(&maps); -} - -/* - * Connect all signals of a textblock or an image. - */ -void DilloHtml::connectSignals(Widget *dw) -{ - dw->connectLink (&linkReceiver); + delete styleEngine; } /* @@ -611,9 +538,19 @@ void DilloHtml::write(char *Buf, int BufSize, int Eof) char *buf = Buf + Start_Ofs; int bufsize = BufSize - Start_Ofs; - dReturn_if_fail (dw != NULL); + _MSG("DilloHtml::write BufSize=%d Start_Ofs=%d\n", BufSize, Start_Ofs); +#if 0 + char *aux = dStrndup(Buf, BufSize); + MSG(" {%s}\n", aux); + dFree(aux); +#endif + /* Update Start_Buf. It may be used after the parser is stopped */ Start_Buf = Buf; + + dReturn_if (dw == NULL); + dReturn_if (stop_parser == true); + token_start = Html_write_raw(this, buf, bufsize, Eof); Start_Ofs += token_start; } @@ -644,7 +581,9 @@ int DilloHtml::getCurTagLineNumber() */ void DilloHtml::freeParseData() { - (stack->getRef(0)->style)->unref (); /* template style */ + for (int i = stack->size () - 1; i >= 0; i--) + if (stack->getRef (i)->table_cell_props) + stack->getRef (i)->table_cell_props->unref (); delete(stack); dStr_free(Stash, TRUE); @@ -661,6 +600,8 @@ void DilloHtml::finishParsing(int ClientKey) { int si; + dReturn_if (stop_parser == true); + /* force the close of elements left open (TODO: not for XHTML) */ while ((si = stack->size() - 1)) { if (stack->getRef(si)->tag_idx != -1) { @@ -669,9 +610,6 @@ void DilloHtml::finishParsing(int ClientKey) } /* Remove this client from our active list */ a_Bw_close_client(bw, ClientKey); - - freeParseData(); - parse_finished = true; } /* @@ -680,7 +618,10 @@ void DilloHtml::finishParsing(int ClientKey) int DilloHtml::formNew(DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc enc, const char *charset) { - DilloHtmlForm *form = a_Html_form_new (this,method,action,enc,charset); + // avoid data loss on repush after CSS stylesheets have been loaded + bool enabled = bw->NumPendingStyleSheets == 0; + DilloHtmlForm *form = a_Html_form_new (this, method, action, + enc, charset, enabled); int nf = forms->size (); forms->increase (); forms->set (nf, form); @@ -713,16 +654,36 @@ void DilloHtml::loadImages (const DilloUrl *pattern) { dReturn_if_fail (bw->nav_expecting == FALSE); + /* If the user asked for a specific URL, the user (NULL) is the requester, + * but if the user just asked for all URLs, use the page URL as the + * requester. If the possible patterns become more complex, it might be + * good to have the caller supply the requester instead. + */ + const DilloUrl *requester = pattern ? NULL : this->page_url; + for (int i = 0; i < images->size(); i++) { if (images->get(i)->image) { if ((!pattern) || (!a_Url_cmp(images->get(i)->url, pattern))) { - Html_load_image(bw, images->get(i)->url, images->get(i)->image); - images->get(i)->image = NULL; // web owns it now + if (Html_load_image(bw, images->get(i)->url, requester, + images->get(i)->image)) { + a_Image_unref (images->get(i)->image); + images->get(i)->image = NULL; // web owns it now + } } } } } +/* + * Save URL in a vector (may be loaded later). + */ +void DilloHtml::addCssUrl(const DilloUrl *url) +{ + int nu = cssUrls->size(); + cssUrls->increase(); + cssUrls->set(nu, a_Url_dup(url)); +} + bool DilloHtml::HtmlLinkReceiver::enter (Widget *widget, int link, int img, int x, int y) { @@ -732,10 +693,12 @@ bool DilloHtml::HtmlLinkReceiver::enter (Widget *widget, int link, int img, if (link == -1) { _MSG(" Link LEAVE notify...\n"); a_UIcmd_set_msg(bw, ""); + a_UIcmd_set_pointer_on_link(bw, FALSE); } else { _MSG(" Link ENTER notify...\n"); Html_set_link_coordinates(html, link, x, y); a_UIcmd_set_msg(bw, "%s", URL_STR(html->links->get(link))); + a_UIcmd_set_pointer_on_link(bw, TRUE); } return true; } @@ -758,14 +721,12 @@ bool DilloHtml::HtmlLinkReceiver::press (Widget *widget, int link, int img, if (link != -1) linkurl = html->links->get(link); const bool_t loaded_img = (html->images->get(img)->image == NULL); - a_UIcmd_image_popup( - bw, html->images->get(img)->url, loaded_img, linkurl); + a_UIcmd_image_popup(bw, html->images->get(img)->url, loaded_img, + html->page_url, linkurl); ret = true; } else { if (link == -1) { - a_UIcmd_page_popup(bw, a_History_get_url(NAV_TOP_UIDX(bw)), - bw->num_page_bugs != 0, - html->unloadedImages()); + a_UIcmd_page_popup(bw, bw->num_page_bugs != 0, html->cssUrls); ret = true; } else { a_UIcmd_link_popup(bw, html->links->get(link)); @@ -786,22 +747,12 @@ bool DilloHtml::HtmlLinkReceiver::click (Widget *widget, int link, int img, if ((img != -1) && (html->images->get(img)->image)) { // clicked an image that has not already been loaded - DilloUrl *pattern; - if (event->button == 1){ // load all instances of this image - pattern = html->images->get(img)->url; - } else { - if (event->button == 2){ - // load all images - pattern = NULL; - } else { - return false; - } + DilloUrl *pattern = html->images->get(img)->url; + html->loadImages(pattern); + return true; } - - html->loadImages(pattern); - return true; } if (link != -1) { @@ -892,7 +843,7 @@ static const Ent_t Entities[NumEnt] = { {"loz",022712}, {"lrm",020016}, {"lsaquo",020071},{"lsquo",020030}, {"lt",60}, {"macr",0257}, {"mdash",020024},{"micro",0265}, {"middot",0267},{"minus",021022},{"mu",01674}, {"nabla",021007}, - {"nbsp",32}, {"ndash",020023},{"ne",021140}, {"ni",021013}, + {"nbsp",0240}, {"ndash",020023},{"ne",021140}, {"ni",021013}, {"not",0254}, {"notin",021011},{"nsub",021204}, {"ntilde",0361}, {"nu",01675}, {"oacute",0363}, {"ocirc",0364}, {"oelig",0523}, {"ograve",0362},{"oline",020076},{"omega",01711}, {"omicron",01677}, @@ -952,14 +903,14 @@ static int Html_ms_stupid_quotes_2ucs(int isocode) { int ret; switch (isocode) { - case 145: - case 146: ret = '\''; break; - case 147: - case 148: ret = '"'; break; - case 149: ret = 176; break; - case 150: - case 151: ret = '-'; break; - default: ret = isocode; break; + case 145: + case 146: ret = '\''; break; + case 147: + case 148: ret = '"'; break; + case 149: ret = 176; break; + case 150: + case 151: ret = '-'; break; + default: ret = isocode; break; } return ret; } @@ -991,7 +942,7 @@ static int Html_parse_entity(DilloHtml *html, const char *token, /* strtol with base 16 accepts leading "0x" - we don't */ if (*s == '0' && s[1] == 'x') { s++; - isocode = 0; + isocode = 0; } else { isocode = strtol(s, &s, 16); } @@ -1015,7 +966,7 @@ static int Html_parse_entity(DilloHtml *html, const char *token, } else if (isalpha(*s)) { /* character entity reference */ - while (*++s && (isalnum(*s) || strchr(":_.-", *s))); + while (*++s && (isalnum(*s) || strchr(":_.-", *s))) ; c = *s; *s = 0; @@ -1066,7 +1017,7 @@ char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize) toksize-i, &entsize)) >= 0) { if (isocode >= 128) { /* multibyte encoding */ - n = utf8encode(isocode, buf); + n = a_Utf8_encode(isocode, buf); for (k = 0; k < n; ++k) new_str[j++] = buf[k]; } else { @@ -1082,9 +1033,32 @@ char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize) } /* + * For white-space: pre-line, we must break the line if encountering a newline. + * Otherwise, collapse whitespace as usual. + */ +static void Html_process_space_pre_line(DilloHtml *html, const char *space, + int spacesize) +{ + int i, breakCnt = 0; + + for (i = 0; i < spacesize; i++) { + /* Support for "\r", "\n" and "\r\n" line breaks */ + if (space[i] == '\r' || (space[i] == '\n' && !html->PrevWasCR)) { + breakCnt++; + html->PrevWasCR = (space[i] == '\r'); + + HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ()); + } + } + if (breakCnt == 0) { + HT2TB(html)->addSpace(html->styleEngine->wordStyle ()); + } +} + +/* * Parse spaces */ -static void Html_process_space(DilloHtml *html, const char *space, +static void Html_process_space(DilloHtml *html, const char *space, int spacesize) { char *spc; @@ -1108,11 +1082,12 @@ static void Html_process_space(DilloHtml *html, const char *space, if (spaceCnt) { spc = dStrnfill(spaceCnt, ' '); - DW2TB(html->dw)->addText (spc, S_TOP(html)->style); + HT2TB(html)->addText (spc, spaceCnt, + html->styleEngine->wordStyle ()); dFree(spc); spaceCnt = 0; } - DW2TB(html->dw)->addLinebreak (S_TOP(html)->style); + HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ()); html->pre_column = 0; } html->PreFirstChar = false; @@ -1140,16 +1115,18 @@ static void Html_process_space(DilloHtml *html, const char *space, if (spaceCnt) { spc = dStrnfill(spaceCnt, ' '); - DW2TB(html->dw)->addText (spc, S_TOP(html)->style); + HT2TB(html)->addText (spc, spaceCnt, html->styleEngine->wordStyle ()); dFree(spc); } } else { if (SGML_SPCDEL) { - /* SGML_SPCDEL ignores white space inmediately after an open tag */ - } else if (!html->PrevWasSPC) { - DW2TB(html->dw)->addSpace(S_TOP(html)->style); - html->PrevWasSPC = true; + /* SGML_SPCDEL ignores white space immediately after an open tag */ + } else if (html->styleEngine->wordStyle ()->whiteSpace == + WHITE_SPACE_PRE_LINE) { + Html_process_space_pre_line(html, space, spacesize); + } else { + HT2TB(html)->addSpace(html->styleEngine->wordStyle ()); } if (parse_mode == DILLO_HTML_PARSE_MODE_STASH_AND_BODY) @@ -1168,7 +1145,7 @@ static void Html_process_space(DilloHtml *html, const char *space, static void Html_process_word(DilloHtml *html, const char *word, int size) { int i, j, start; - char *Pword, ch; + char *Pword; DilloHtmlParseMode parse_mode = S_TOP(html)->parse_mode; if (parse_mode == DILLO_HTML_PARSE_MODE_STASH || @@ -1195,39 +1172,66 @@ static void Html_process_word(DilloHtml *html, const char *word, int size) Pword = a_Html_parse_entities(html, word, size); for (start = i = 0; Pword[i]; start = i) if (isspace(Pword[i])) { - while (Pword[++i] && isspace(Pword[i])); + while (Pword[++i] && isspace(Pword[i])) ; Html_process_space(html, Pword + start, i - start); } else { - while (Pword[++i] && !isspace(Pword[i])); - ch = Pword[i]; - Pword[i] = 0; - DW2TB(html->dw)->addText(Pword, S_TOP(html)->style); - Pword[i] = ch; + while (Pword[++i] && !isspace(Pword[i])) ; + HT2TB(html)->addText(Pword + start, i - start, + html->styleEngine->wordStyle ()); html->pre_column += i - start; html->PreFirstChar = false; } dFree(Pword); } else { + const char *word2, *word2_end; + + Pword = NULL; if (!memchr(word,'&', size)) { /* No entities */ - DW2TB(html->dw)->addText(word, S_TOP(html)->style); + word2 = word; + word2_end = word + size - 1; } else { /* Collapse white-space entities inside the word (except ) */ Pword = a_Html_parse_entities(html, word, size); - for (i = 0; Pword[i]; ++i) - if (strchr("\t\f\n\r", Pword[i])) - for (j = i; (Pword[j] = Pword[j+1]); ++j); - - DW2TB(html->dw)->addText(Pword, S_TOP(html)->style); - dFree(Pword); + /* Collapse adjacent " \t\f\n\r" characters into a single space */ + for (i = j = 0; (Pword[i] = Pword[j]); ++i, ++j) { + if (strchr(" \t\f\n\r", Pword[i])) { + if (i == 0 || (i > 0 && Pword[i-1] != ' ')) + Pword[i] = ' '; + else + for (--i; Pword[j+1] && strchr(" \t\f\n\r", Pword[j+1]); ++j) + ; + } + } + word2 = Pword; + word2_end = word2 + strlen(word2) - 1; + } + for (start = i = 0; word2[i]; start = i) { + int len; + + if (isspace(word2[i])) { + while (word2[++i] && isspace(word2[i])) ; + Html_process_space(html, word2 + start, i - start); + } else if (!strncmp(word2+i, utf8_zero_width_space, 3)) { + i += 3; + } else if (a_Utf8_ideographic(word2+i, word2_end, &len)) { + i += len; + HT2TB(html)->addText(word2 + start, i - start, + html->styleEngine->wordStyle ()); + } else { + do { + i += len; + } while (word2[i] && !isspace(word2[i]) && + strncmp(word2+i, utf8_zero_width_space, 3) && + (!a_Utf8_ideographic(word2+i, word2_end, &len))); + HT2TB(html)->addText(word2 + start, i - start, + html->styleEngine->wordStyle ()); + } } + if (Pword == word2) + dFree(Pword); } - - html->PrevWasOpenTag = false; - html->PrevWasSPC = false; - if (html->InFlags & IN_LI) - html->WordAfterLI = true; } /* @@ -1250,14 +1254,14 @@ static bool Html_match_tag(const char *tagstr, char *tag, int tagsize) /* * This function is called after popping the stack, to - * handle nested DwPage widgets. + * handle nested Textblock widgets. */ static void Html_eventually_pop_dw(DilloHtml *html, bool hand_over_break) { if (html->dw != S_TOP(html)->textblock) { if (hand_over_break) - DW2TB(html->dw)->handOverBreak (S_TOP(html)->style); - DW2TB(html->dw)->flush (); + HT2TB(html)->handOverBreak (html->styleEngine->style ()); + HT2TB(html)->flush (); html->dw = S_TOP(html)->textblock; } } @@ -1275,10 +1279,8 @@ static void Html_push_tag(DilloHtml *html, int tag_idx) * instead of copying all fields except for tag. --Jcid */ *html->stack->getRef(n_items) = *html->stack->getRef(n_items - 1); html->stack->getRef(n_items)->tag_idx = tag_idx; - /* proper memory management, may be unref'd later */ - (S_TOP(html)->style)->ref (); - if (S_TOP(html)->table_cell_style) - (S_TOP(html)->table_cell_style)->ref (); + if (S_TOP(html)->table_cell_props) + S_TOP(html)->table_cell_props->ref (); html->dw = S_TOP(html)->textblock; } @@ -1288,6 +1290,7 @@ static void Html_push_tag(DilloHtml *html, int tag_idx) */ static void Html_force_push_tag(DilloHtml *html, int tag_idx) { + html->styleEngine->startElement (tag_idx); Html_push_tag(html, tag_idx); } @@ -1298,15 +1301,32 @@ static void Html_real_pop_tag(DilloHtml *html) { bool hand_over_break; - (S_TOP(html)->style)->unref (); - if (S_TOP(html)->table_cell_style) - (S_TOP(html)->table_cell_style)->unref (); + html->styleEngine->endElement (S_TOP(html)->tag_idx); + if (S_TOP(html)->table_cell_props) + S_TOP(html)->table_cell_props->unref (); hand_over_break = S_TOP(html)->hand_over_break; html->stack->setSize (html->stack->size() - 1); Html_eventually_pop_dw(html, hand_over_break); } /* + * Cleanup the stack to a given index. + */ +static void Html_tag_cleanup_to_idx(DilloHtml *html, int idx) +{ + int s_sz; + while ((s_sz = html->stack->size()) > idx) { + int toptag_idx = S_TOP(html)->tag_idx; + TagInfo toptag = Tags[toptag_idx]; + if (s_sz > idx + 1 && toptag.EndTag != 'O') + BUG_MSG(" - forcing close of open tag: <%s>\n", toptag.name); + _MSG("Close: %*s%s\n", size," ", toptag.name); + toptag.close(html, toptag_idx); + Html_real_pop_tag(html); + } +} + +/* * Default close function for tags. * (conditional cleanup of the stack) * There are several ways of doing it. Considering the HTML 4.01 spec @@ -1321,77 +1341,51 @@ static void Html_real_pop_tag(DilloHtml *html) * 2.- If it exists, clean all the tags in between. * 3.- Cleanup the matching tag. (on error, give a warning message) */ -static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx) +static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) { int w3c_mode = !prefs.w3c_plus_heuristics; - int stack_idx, cmp = 1; - int new_idx = TagIdx; - - if (html->CloseOneTag) { - Html_real_pop_tag(html); - html->CloseOneTag = false; - return; - } + int stack_idx, tag_idx, matched = 0, expected = 0; + TagInfo new_tag = Tags[new_idx]; /* Look for the candidate tag to close */ - stack_idx = html->stack->size() - 1; - while (stack_idx && - (cmp = (new_idx != html->stack->getRef(stack_idx)->tag_idx)) && - ((w3c_mode && - Tags[html->stack->getRef(stack_idx)->tag_idx].EndTag == 'O') || - (!w3c_mode && - (Tags[html->stack->getRef(stack_idx)->tag_idx].EndTag == 'O') || - Tags[html->stack->getRef(stack_idx)->tag_idx].TagLevel < - Tags[new_idx].TagLevel))) { - --stack_idx; - } - - /* clean, up to the matching tag */ - if (cmp == 0 && stack_idx > 0) { - /* There's a valid matching tag in the stack */ - while (html->stack->size() > stack_idx) { - int toptag_idx = S_TOP(html)->tag_idx; - /* Warn when we decide to close an open tag (for !w3c_mode) */ - if (html->stack->size() > stack_idx + 1 && - Tags[toptag_idx].EndTag != 'O') - BUG_MSG(" - forcing close of open tag: <%s>\n", - Tags[toptag_idx].name); - - /* Close this and only this tag */ - html->CloseOneTag = true; - Tags[toptag_idx].close (html, toptag_idx); + stack_idx = html->stack->size(); + while (--stack_idx) { + tag_idx = html->stack->getRef(stack_idx)->tag_idx; + if (tag_idx == new_idx) { + /* matching tag found */ + matched = 1; + break; + } else if (Tags[tag_idx].EndTag == 'O') { + /* skip an optional tag */ + continue; + } else if (w3c_mode || Tags[tag_idx].TagLevel >= new_tag.TagLevel) { + /* this is the tag that should have been closed */ + expected = 1; + break; } + } + if (matched) { + Html_tag_cleanup_to_idx(html, stack_idx); + } else if (expected) { + BUG_MSG("unexpected closing tag: </%s> -- expected </%s>.\n", + new_tag.name, Tags[tag_idx].name); } else { - if (stack_idx == 0) { - BUG_MSG("unexpected closing tag: </%s>.\n", Tags[new_idx].name); - } else { - BUG_MSG("unexpected closing tag: </%s>. -- expected </%s>\n", - Tags[new_idx].name, - Tags[html->stack->getRef(stack_idx)->tag_idx].name); - } + BUG_MSG("unexpected closing tag: </%s>.\n", new_tag.name); } } /* - * Cleanup (conditional), and Pop the tag (if it matches) - */ -void a_Html_pop_tag(DilloHtml *html, int TagIdx) -{ - Html_tag_cleanup_at_close(html, TagIdx); -} - -/* * Some parsing routines. */ /* * Used by a_Html_parse_length */ -static Length Html_parse_length_or_multi_length (const char *attr, - char **endptr) +static CssLength Html_parse_length_or_multi_length (const char *attr, + char **endptr) { - Length l; + CssLength l; double v; char *end; @@ -1399,12 +1393,12 @@ static Length Html_parse_length_or_multi_length (const char *attr, switch (*end) { case '%': end++; - l = createPerLength (v / 100); + l = CSS_CREATE_LENGTH (v / 100, CSS_LENGTH_TYPE_PERCENTAGE); break; case '*': end++; - l = createRelLength (v); + l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_RELATIVE); break; /* The "px" suffix seems not allowed by HTML4.01 SPEC. @@ -1413,7 +1407,7 @@ static Length Html_parse_length_or_multi_length (const char *attr, end += 2; */ default: - l = createAbsLength ((int)v); + l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_PX); break; } @@ -1427,24 +1421,24 @@ static Length Html_parse_length_or_multi_length (const char *attr, * Returns a length or a percentage, or UNDEF_LENGTH in case * of an error, or if attr is NULL. */ -Length a_Html_parse_length (DilloHtml *html, const char *attr) +CssLength a_Html_parse_length (DilloHtml *html, const char *attr) { - Length l; + CssLength l; char *end; l = Html_parse_length_or_multi_length (attr, &end); - if (isRelLength (l)) + if (CSS_LENGTH_TYPE (l) == CSS_LENGTH_TYPE_RELATIVE) /* not allowed as &Length; */ - return LENGTH_AUTO; + l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); else { /* allow only whitespaces */ if (*end && !isspace (*end)) { BUG_MSG("Garbage after length: %s\n", attr); - return LENGTH_AUTO; + l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); } } - _MSG("a_Html_parse_length: \"%s\" %d\n", attr, absLengthVal(l)); + _MSG("a_Html_parse_length: \"%s\" %d\n", attr, CSS_LENGTH_VALUE(l)); return l; } @@ -1498,7 +1492,7 @@ static int * recognizes the "HTML Level" with or without the URL. The convention * comes from mozilla (see URLs below), but Dillo doesn't have the same * rendering modes, so it may be better to chose another behaviour. --Jcid - * + * * http://www.mozilla.org/docs/web-developer/quirks/doctypes.html * http://lists.auriga.wearlab.de/pipermail/dillo-dev/2004-October/002300.html * @@ -1507,7 +1501,7 @@ static int static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize) { static const char HTML_sig [] = "<!DOCTYPE HTML PUBLIC "; - static const char HTML20 [] = "-//IETF//DTD HTML//EN"; + static const char HTML20 [] = "-//IETF//DTD HTML 2.0"; static const char HTML32 [] = "-//W3C//DTD HTML 3.2"; static const char HTML40 [] = "-//W3C//DTD HTML 4.0"; static const char HTML401 [] = "-//W3C//DTD HTML 4.01"; @@ -1524,9 +1518,9 @@ static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize) * and replace '\n' and '\r' with ' ' inside quoted strings. */ for (i = 0, p = ntag; *p; ++p) { if (isspace(*p)) { - for (ntag[i++] = ' '; isspace(p[1]); ++p); + for (ntag[i++] = ' '; isspace(p[1]); ++p) ; } else if ((quote = *p) == '"' || *p == '\'') { - for (ntag[i++] = *p++; (ntag[i++] = *p) && *p != quote; ++p) { + for (ntag[i++] = *p++; (ntag[i] = *p) && ntag[i++] != quote; ++p) { if (*p == '\n' || *p == '\r') ntag[i - 1] = ' '; p += (p[0] == '\r' && p[1] == '\n') ? 1 : 0; @@ -1595,7 +1589,6 @@ static void Html_tag_close_html(DilloHtml *html, int TagIdx) /* beware of pages with multiple HTML close tags... :-P */ html->InFlags &= ~IN_HTML; } - a_Html_pop_tag(html, TagIdx); } /* @@ -1622,16 +1615,22 @@ static void Html_tag_open_head(DilloHtml *html, const char *tag, int tagsize) * Handle close HEAD element * Note: as a side effect of Html_test_section() this function is called * twice when the head element is closed implicitly. + * Note2: HEAD is parsed once completely got. */ static void Html_tag_close_head(DilloHtml *html, int TagIdx) { if (html->InFlags & IN_HEAD) { + _MSG("Closing HEAD section\n"); if (html->Num_TITLE == 0) BUG_MSG("HEAD section lacks the TITLE element\n"); - + html->InFlags &= ~IN_HEAD; + + /* charset is already set, load remote stylesheets now */ + for (int i = 0; i < html->cssUrls->size(); i++) { + a_Html_load_stylesheet(html, html->cssUrls->get(i)); + } } - a_Html_pop_tag(html, TagIdx); } /* @@ -1653,11 +1652,10 @@ static void Html_tag_close_title(DilloHtml *html, int TagIdx) if (html->InFlags & IN_HEAD) { /* title is only valid inside HEAD */ a_UIcmd_set_page_title(html->bw, html->Stash->str); - a_History_set_title(NAV_TOP_UIDX(html->bw),html->Stash->str); + a_History_set_title_by_url(html->page_url, html->Stash->str); } else { BUG_MSG("the TITLE element must be inside the HEAD section\n"); } - a_Html_pop_tag(html, TagIdx); } /* @@ -1677,16 +1675,33 @@ static void Html_tag_open_script(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_close_script(DilloHtml *html, int TagIdx) { /* eventually the stash will be sent to an interpreter for parsing */ - a_Html_pop_tag(html, TagIdx); } /* * Handle open STYLE - * store the contents to the stash where (in the future) the style - * sheet interpreter can get it. + * Store contents in the stash where the style sheet interpreter can get it. */ static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize) { + const char *attrbuf; + + html->loadCssFromStash = true; + + if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { + BUG_MSG("type attribute is required for <style>\n"); + } else if (dStrcasecmp(attrbuf, "text/css")) { + html->loadCssFromStash = false; + } + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) && + dStrcasecmp(attrbuf, "all") && !dStristr(attrbuf, "screen")) { + /* HTML 4.01 sec. 6.13 says that media descriptors are case-sensitive, + * but sec. 14.2.3 says that the attribute is case-insensitive. + * TODO can be a comma-separated list. + * TODO handheld. + */ + html->loadCssFromStash = false; + } + a_Html_stash_init(html); S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM; } @@ -1696,8 +1711,9 @@ static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_close_style(DilloHtml *html, int TagIdx) { - /* eventually the stash will be sent to an interpreter for parsing */ - a_Html_pop_tag(html, TagIdx); + if (prefs.parse_embedded_css && html->loadCssFromStash) + html->styleEngine->parse(html, NULL, html->Stash->str, html->Stash->len, + CSS_ORIGIN_AUTHOR); } /* @@ -1707,9 +1723,9 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) { const char *attrbuf; Textblock *textblock; - StyleAttrs style_attrs; - Style *style; + CssPropertyList props; int32_t color; + int tag_index_a = a_Html_tag_index ("a"); if (!(html->InFlags & IN_BODY)) html->InFlags |= IN_BODY; @@ -1724,43 +1740,53 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) BUG_MSG("unclosed HEAD element\n"); } - textblock = DW2TB(html->dw); + textblock = HT2TB(html); - if (!prefs.force_my_colors) { - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { - color = a_Html_color_parse(html, attrbuf, prefs.bg_color); - if (color == 0xffffff && !prefs.allow_white_bg) - color = prefs.bg_color; + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { + color = a_Html_color_parse(html, attrbuf, -1); + if (color != -1) + props.set (CSS_PROPERTY_BACKGROUND_COLOR, CSS_TYPE_COLOR, color); + } - style_attrs = *html->dw->getStyle (); - style_attrs.backgroundColor = Color::createShaded(HT2LT(html), color); - style = Style::create (HT2LT(html), &style_attrs); - html->dw->setStyle (style); - style->unref (); - S_TOP(html)->current_bg_color = color; - } + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "text"))) { + color = a_Html_color_parse(html, attrbuf, -1); + if (color != -1) + props.set (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, color); + } - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "text"))) { - color = a_Html_color_parse(html, attrbuf, prefs.text_color); - HTML_SET_TOP_ATTR (html, color, - Color::createSimple (HT2LT(html),color)); - } + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link"))) + html->non_css_link_color = a_Html_color_parse(html, attrbuf, -1); - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link"))) - html->link_color = a_Html_color_parse(html,attrbuf,prefs.link_color); + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vlink"))) + html->non_css_visited_color = a_Html_color_parse(html, attrbuf, -1); - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vlink"))) - html->visited_color = a_Html_color_parse(html, attrbuf, - prefs.visited_color); + html->styleEngine->setNonCssHints (&props); + html->dw->setStyle (html->styleEngine->style ()); - if (prefs.contrast_visited_color) { - /* get a color that has a "safe distance" from text, link and bg */ - html->visited_color = - a_Color_vc(html->visited_color, - S_TOP(html)->style->color->getColor(), - html->link_color, - S_TOP(html)->current_bg_color); - } + /* Determine a color for visited links. + * This color is computed once per page and used for immediate feedback + * when clicking a link. + * On reload style including color for visited links is computed properly + * according to CSS. + */ + html->styleEngine->startElement (tag_index_a); + html->styleEngine->setPseudoVisited (); + if (html->non_css_visited_color != -1) { + CssPropertyList vprops; + vprops.set (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, + html->non_css_visited_color); + html->styleEngine->setNonCssHints (&vprops); + } + html->visited_color = html->styleEngine->style ()->color->getColor (); + html->styleEngine->endElement (tag_index_a); + + if (prefs.contrast_visited_color) { + /* get a color that has a "safe distance" from text, link and bg */ + html->visited_color = + a_Color_vc(html->visited_color, + html->styleEngine->style ()->color->getColor(), + html->non_css_link_color, + html->styleEngine->backgroundStyle()->backgroundColor->getColor()); } S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_BODY; @@ -1775,7 +1801,6 @@ static void Html_tag_close_body(DilloHtml *html, int TagIdx) /* some tag soup pages use multiple BODY tags... */ html->InFlags &= ~IN_BODY; } - a_Html_pop_tag(html, TagIdx); } /* @@ -1785,13 +1810,12 @@ static void Html_tag_close_body(DilloHtml *html, int TagIdx) */ static void Html_tag_open_p(DilloHtml *html, const char *tag, int tagsize) { - if ((html->InFlags & IN_LI) && !html->WordAfterLI) { - /* ignore first parbreak after an empty <LI> */ - html->WordAfterLI = true; - } else { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - } - a_Html_tag_set_align_attr (html, tag, tagsize); + CssPropertyList props; + + a_Html_tag_set_align_attr (html, &props, tag, tagsize); + html->styleEngine->inheritBackgroundColor (); + html->styleEngine->setNonCssHints (&props); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } /* @@ -1805,11 +1829,10 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize) char *src; DilloUrl *url; Textblock *textblock; - StyleAttrs style_attrs; - Style *link_style; Widget *bullet; + CssPropertyList props; - textblock = DW2TB(html->dw); + textblock = HT2TB(html); if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) return; @@ -1819,46 +1842,40 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize) src = dStrdup(attrbuf); - style_attrs = *(S_TOP(html)->style); - - if (a_Capi_get_flags(url) & CAPI_IsCached) { /* visited frame */ - style_attrs.color = - Color::createSimple (HT2LT(html), html->visited_color); - } else { /* unvisited frame */ - style_attrs.color = Color::createSimple (HT2LT(html), html->link_color); + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + /* visited frame */ + html->styleEngine->setPseudoVisited (); + } else { + /* unvisited frame */ + html->styleEngine->setPseudoLink (); } - style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE; - style_attrs.x_link = Html_set_new_link(html, &url); - style_attrs.cursor = CURSOR_POINTER; - link_style = Style::create (HT2LT(html), &style_attrs); - textblock->addParbreak (5, S_TOP(html)->style); + props.set (PROPERTY_X_LINK, CSS_TYPE_INTEGER, Html_set_new_link(html,&url)); + html->styleEngine->setNonCssHints (&props); + + textblock->addParbreak (5, html->styleEngine->wordStyle ()); - /* The bullet will be assigned the current list style, which should - * be "disc" by default, but may in very weird pages be different. - * Anyway, there should be no harm. */ bullet = new Bullet(); - textblock->addWidget(bullet, S_TOP(html)->style); - textblock->addSpace(S_TOP(html)->style); + textblock->addWidget(bullet, html->styleEngine->wordStyle ()); + textblock->addSpace(html->styleEngine->wordStyle ()); if (tolower(tag[1]) == 'i') { /* IFRAME usually comes with very long advertising/spying URLS, * to not break rendering we will force name="IFRAME" */ - textblock->addText ("IFRAME", link_style); + textblock->addText ("IFRAME", html->styleEngine->wordStyle ()); } else { /* FRAME: * If 'name' tag is present use it, if not use 'src' value */ if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) { - textblock->addText (src, link_style); + textblock->addText (src, html->styleEngine->wordStyle ()); } else { - textblock->addText (attrbuf, link_style); + textblock->addText (attrbuf, html->styleEngine->wordStyle ()); } } - textblock->addParbreak (5, S_TOP(html)->style); + textblock->addParbreak (5, html->styleEngine->wordStyle ()); - link_style->unref (); dFree(src); } @@ -1870,9 +1887,9 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize) static void Html_tag_open_frameset (DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - DW2TB(html->dw)->addText("--FRAME--", S_TOP(html)->style); - Html_add_indented(html, 40, 0, 5); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); + HT2TB(html)->addText("--FRAME--", html->styleEngine->wordStyle ()); + Html_add_textblock(html, 5); } /* @@ -1880,53 +1897,26 @@ static void Html_tag_open_frameset (DilloHtml *html, */ static void Html_tag_open_h(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); + CssPropertyList props; + - /* TODO: combining these two would be slightly faster */ - a_Html_set_top_font(html, prefs.vw_fontname, - Html_level_to_fontsize(FontSizesNum - (tag[2] - '0')), - 1, 3); - a_Html_tag_set_align_attr (html, tag, tagsize); + html->styleEngine->inheritBackgroundColor (); + a_Html_tag_set_align_attr (html, &props, tag, tagsize); + html->styleEngine->setNonCssHints (&props); + + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); - /* First finalize unclosed H tags (we test if already named anyway) */ - a_Menu_pagemarks_set_text(html->bw, html->Stash->str); - a_Menu_pagemarks_add(html->bw, DW2TB(html->dw), - S_TOP(html)->style, (tag[2] - '0')); a_Html_stash_init(html); S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_STASH_AND_BODY; } /* - * Handle close: <H1> | <H2> | <H3> | <H4> | <H5> | <H6> - */ -static void Html_tag_close_h(DilloHtml *html, int TagIdx) -{ - a_Menu_pagemarks_set_text(html->bw, html->Stash->str); - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_pop_tag(html, TagIdx); -} - -/* - * <BIG> | <SMALL> - */ -static void Html_tag_open_big_small(DilloHtml *html, - const char *tag, int tagsize) -{ - int level; - - level = - Html_fontsize_to_level(S_TOP(html)->style->font->size) + - ((dStrncasecmp(tag+1, "big", 3)) ? -1 : 1); - a_Html_set_top_font(html, NULL, Html_level_to_fontsize(level), 0, 0); -} - -/* * <BR> */ static void Html_tag_open_br(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addLinebreak (S_TOP(html)->style); + HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ()); } /* @@ -1934,39 +1924,29 @@ static void Html_tag_open_br(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_font(DilloHtml *html, const char *tag, int tagsize) { - StyleAttrs style_attrs; - Style *old_style; - /*Font font;*/ const char *attrbuf; + char *fontFamily = NULL; int32_t color; + CssPropertyList props; - if (!prefs.force_my_colors) { - old_style = S_TOP(html)->style; - style_attrs = *old_style; - - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "color"))) { - if (prefs.contrast_visited_color && html->InVisitedLink) { - color = html->visited_color; - } else { - /* use the tag-specified color */ - color = a_Html_color_parse(html, attrbuf, - style_attrs.color->getColor()); - style_attrs.color = Color::createSimple (HT2LT(html), color); - } + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "color"))) { + if (prefs.contrast_visited_color && html->InVisitedLink) { + color = html->visited_color; + } else { + /* use the tag-specified color */ + color = a_Html_color_parse(html, attrbuf, -1); } + if (color != -1) + props.set (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, color); + } -#if 0 - //if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "face"))) { - // font = *( style_attrs.font ); - // font.name = attrbuf; - // style_attrs.font = a_Dw_style_font_new_from_list (&font); - //} -#endif - - S_TOP(html)->style = - Style::create (HT2LT(html), &style_attrs); - old_style->unref (); + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "face"))) { + fontFamily = dStrdup(attrbuf); + props.set (CSS_PROPERTY_FONT_FAMILY, CSS_TYPE_SYMBOL, fontFamily); } + + html->styleEngine->setNonCssHints (&props); + dFree(fontFamily); } /* @@ -1974,62 +1954,33 @@ static void Html_tag_open_font(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_abbr(DilloHtml *html, const char *tag, int tagsize) { -// DwTooltip *tooltip; -// const char *attrbuf; -// -// if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) { -// tooltip = a_Dw_tooltip_new_no_ref(attrbuf); -// HTML_SET_TOP_ATTR(html, x_tooltip, tooltip); -// } -} - -/* - * <B> - */ -static void Html_tag_open_b(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 1, 1); -} - -/* - * <STRONG> - */ -static void Html_tag_open_strong(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 1, 1); -} + const char *attrbuf; -/* - * <I> - */ -static void Html_tag_open_i(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 2, 2); -} + if (prefs.show_tooltip && + (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) { + CssPropertyList props; + char *tooltip_str = dStrdup(attrbuf); -/* - * <EM> - */ -static void Html_tag_open_em(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 2, 2); + props.set (PROPERTY_X_TOOLTIP, CSS_TYPE_STRING, tooltip_str); + html->styleEngine->setNonCssHints (&props); + dFree(tooltip_str); + } } /* - * <CITE> + * <CENTER> */ -static void Html_tag_open_cite(DilloHtml *html, const char *tag, int tagsize) +static void Html_tag_open_center(DilloHtml *html, const char *tag, int tagsize) { - a_Html_set_top_font(html, NULL, 0, 2, 2); + HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ()); } /* - * <CENTER> + * </CENTER>, also used for </TABLE> */ -static void Html_tag_open_center(DilloHtml *html, const char *tag, int tagsize) +static void Html_tag_close_center(DilloHtml *html, int TagIdx) { - DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style); - HTML_SET_TOP_ATTR(html, textAlign, TEXT_ALIGN_CENTER); + HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ()); } /* @@ -2038,42 +1989,32 @@ static void Html_tag_open_center(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_open_address(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_set_top_font(html, NULL, 0, 2, 2); -} - -/* - * <TT> - */ -static void Html_tag_open_tt(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } /* - * Read image-associated tag attributes, - * create new image and add it to the html page (if add is TRUE). + * Read image-associated tag attributes and create new image. */ -DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag, - int tagsize, DilloUrl *url, - dw::core::style::StyleAttrs *style_attrs, - bool add) +DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, + int tagsize, DilloUrl *url) { - const int MAX_W = 6000, MAX_H = 6000; - DilloImage *Image; char *width_ptr, *height_ptr, *alt_ptr; const char *attrbuf; - Length l_w, l_h; - int space, w = 0, h = 0; + CssLength l_w = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); + CssLength l_h = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); + int space, border, w = 0, h = 0; bool load_now; + CssPropertyList props; + char *tooltip_str = NULL; -// if (prefs.show_tooltip && -// (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) -// style_attrs->x_tooltip = a_Dw_tooltip_new_no_ref(attrbuf); - + if (prefs.show_tooltip && + (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) { + tooltip_str = dStrdup(attrbuf); + props.set (PROPERTY_X_TOOLTIP, CSS_TYPE_STRING, tooltip_str); + } alt_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "alt", NULL); - if ((!alt_ptr || !*alt_ptr) && !a_UIcmd_get_images_enabled(html->bw)) { + if ((!alt_ptr || !*alt_ptr) && !prefs.load_images) { dFree(alt_ptr); alt_ptr = dStrdup("[IMG]"); // Place holder for img_off mode } @@ -2083,17 +2024,35 @@ DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag, // TODO: the same for percentage and relative lengths. if (width_ptr) { l_w = a_Html_parse_length (html, width_ptr); - w = isAbsLength(l_w) ? absLengthVal(l_w) : 0; + w = (int) (CSS_LENGTH_TYPE(l_w) == CSS_LENGTH_TYPE_PX ? + CSS_LENGTH_VALUE(l_w) : 0); } if (height_ptr) { l_h = a_Html_parse_length (html, height_ptr); - h = isAbsLength(l_h) ? absLengthVal(l_h) : 0; - } - if (w < 0 || h < 0 || abs(w*h) > MAX_W * MAX_H) { + h = (int) (CSS_LENGTH_TYPE(l_h) == CSS_LENGTH_TYPE_PX ? + CSS_LENGTH_VALUE(l_h) : 0); + } + /* Check for suspicious image size request that would cause + * an excessive amount of memory to be allocated for the + * image buffer. + * Be careful to avoid integer overflows during the checks. + * There is an additional check in dw/image.cc to catch cases + * where only one dimension is given and the image is scaled + * preserving its original aspect ratio. + * Size requests passed via CSS are also checked there. + */ + if (w < 0 || h < 0 || + w > IMAGE_MAX_AREA || h > IMAGE_MAX_AREA || + (h > 0 && w > IMAGE_MAX_AREA / h)) { dFree(width_ptr); dFree(height_ptr); width_ptr = height_ptr = NULL; - MSG("a_Html_add_new_image: suspicious image size request %dx%d\n", w, h); + MSG("a_Html_image_new: suspicious image size request %dx%d\n", w, h); + } else { + if (CSS_LENGTH_TYPE(l_w) != CSS_LENGTH_TYPE_AUTO) + props.set (CSS_PROPERTY_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, l_w); + if (CSS_LENGTH_TYPE(l_h) != CSS_LENGTH_TYPE_AUTO) + props.set (CSS_PROPERTY_HEIGHT, CSS_TYPE_LENGTH_PERCENTAGE, l_h); } /* TODO: we should scale the image respecting its ratio. @@ -2106,34 +2065,72 @@ DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag, /* Spacing to the left and right */ if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "hspace"))) { space = strtol(attrbuf, NULL, 10); - if (space > 0) - style_attrs->margin.left = style_attrs->margin.right = space; + if (space > 0) { + space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); + props.set (CSS_PROPERTY_MARGIN_LEFT, CSS_TYPE_LENGTH_PERCENTAGE, + space); + props.set (CSS_PROPERTY_MARGIN_RIGHT, CSS_TYPE_LENGTH_PERCENTAGE, + space); + } } /* Spacing at the top and bottom */ if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vspace"))) { space = strtol(attrbuf, NULL, 10); - if (space > 0) - style_attrs->margin.top = style_attrs->margin.bottom = space; + if (space > 0) { + space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); + props.set (CSS_PROPERTY_MARGIN_TOP, CSS_TYPE_LENGTH_PERCENTAGE, + space); + props.set (CSS_PROPERTY_MARGIN_BOTTOM, CSS_TYPE_LENGTH_PERCENTAGE, + space); + } + } + + /* Border */ + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border"))) { + border = strtol(attrbuf, NULL, 10); + if (border >= 0) { + border = CSS_CREATE_LENGTH(border, CSS_LENGTH_TYPE_PX); + props.set (CSS_PROPERTY_BORDER_TOP_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + border); + props.set (CSS_PROPERTY_BORDER_BOTTOM_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + props.set (CSS_PROPERTY_BORDER_LEFT_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + props.set (CSS_PROPERTY_BORDER_RIGHT_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + + props.set (CSS_PROPERTY_BORDER_TOP_STYLE, CSS_TYPE_ENUM, + BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_BOTTOM_STYLE, CSS_TYPE_ENUM, + BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_LEFT_STYLE, CSS_TYPE_ENUM, + BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_RIGHT_STYLE, CSS_TYPE_ENUM, + BORDER_SOLID); + } } /* x_img is an index to a list of {url,image} pairs. - * We know Html_add_new_linkimage() will use size() as its next index */ - style_attrs->x_img = html->images->size(); + * We know Html_add_new_htmlimage() will use size() as its next index */ + props.set (PROPERTY_X_IMG, CSS_TYPE_INTEGER, html->images->size()); - /* Add a new image widget to this page */ - Image = a_Image_new(0, 0, alt_ptr, S_TOP(html)->current_bg_color); - if (add) { - Html_add_widget(html, (Widget*)Image->dw, width_ptr, height_ptr, - style_attrs); - } + html->styleEngine->setNonCssHints(&props); - load_now = a_UIcmd_get_images_enabled(html->bw) || - (a_Capi_get_flags(url) & CAPI_IsCached); - Html_add_new_linkimage(html, &url, load_now ? NULL : Image); + /* Add a new image widget to this page */ + Image = a_Image_new(alt_ptr, 0); + if (HT2TB(html)->getBgColor()) + Image->bg_color = HT2TB(html)->getBgColor()->getColor(); + + load_now = prefs.load_images || + !dStrcasecmp(URL_SCHEME(url), "data") || + (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached); + bool loading = false; if (load_now) - Html_load_image(html->bw, url, Image); + loading = Html_load_image(html->bw, url, html->page_url, Image); + Html_add_new_htmlimage(html, &url, loading ? NULL : Image); + dFree(tooltip_str); dFree(width_ptr); dFree(height_ptr); dFree(alt_ptr); @@ -2143,21 +2140,23 @@ DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag, /* * Tell cache to retrieve image */ -static void Html_load_image(BrowserWindow *bw, DilloUrl *url, - DilloImage *Image) +static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, + const DilloUrl *requester, DilloImage *Image) { DilloWeb *Web; int ClientKey; /* Fill a Web structure for the cache query */ - Web = a_Web_new(url); + Web = a_Web_new(url, requester); Web->bw = bw; Web->Image = Image; + a_Image_ref(Image); Web->flags |= WEB_Image; /* Request image data from the cache */ if ((ClientKey = a_Capi_open_url(Web, NULL, NULL)) != 0) { a_Bw_add_client(bw, ClientKey, 0); a_Bw_add_url(bw, url); } + return ClientKey != 0; } /* @@ -2170,9 +2169,7 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) DilloImage *Image; DilloUrl *url, *usemap_url; Textblock *textblock; - StyleAttrs style_attrs; const char *attrbuf; - int border; /* This avoids loading images. Useful for viewing suspicious HTML email. */ if (URL_FLAGS(html->base_url) & URL_SpamSafe) @@ -2182,41 +2179,21 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) !(url = a_Html_url_new(html, attrbuf, NULL, 0))) return; - textblock = DW2TB(html->dw); + textblock = HT2TB(html); usemap_url = NULL; if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "usemap"))) /* TODO: usemap URLs outside of the document are not used. */ usemap_url = a_Html_url_new(html, attrbuf, NULL, 0); - /* Set the style attributes for this image */ - style_attrs = *S_TOP(html)->style; - if (S_TOP(html)->style->x_link != -1 || - usemap_url != NULL) { - /* Images within links */ - border = 1; - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border"))) - border = strtol (attrbuf, NULL, 10); - - if (S_TOP(html)->style->x_link != -1) { - /* In this case we can use the text color */ - style_attrs.setBorderColor ( - Color::createShaded (HT2LT(html), style_attrs.color->getColor())); - } else { - style_attrs.setBorderColor ( - Color::createShaded (HT2LT(html), html->link_color)); - } - style_attrs.setBorderStyle (BORDER_SOLID); - style_attrs.borderWidth.setVal (border); - } - - Image = a_Html_add_new_image(html, tag, tagsize, url, &style_attrs, true); + Image = a_Html_image_new(html, tag, tagsize, url); + HT2TB(html)->addWidget((Widget*)Image->dw, html->styleEngine->style()); /* Image maps */ if (a_Html_get_attr(html, tag, tagsize, "ismap")) { ((::dw::Image*)Image->dw)->setIsMap(); _MSG(" Html_tag_open_img: server-side map (ISMAP)\n"); - } else if (S_TOP(html)->style->x_link != -1 && + } else if (html->styleEngine->style ()->x_link != -1 && usemap_url == NULL) { /* For simple links, we have to suppress the "image_pressed" signal. * This is overridden for USEMAP images. */ @@ -2225,10 +2202,9 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) if (usemap_url) { ((::dw::Image*)Image->dw)->setUseMap(&html->maps, - new ::object::String(usemap_url->url_string->str)); + new ::object::String(URL_STR(usemap_url))); a_Url_free (usemap_url); } - html->connectSignals((Widget*)Image->dw); } /* @@ -2244,13 +2220,15 @@ static void Html_tag_open_map(DilloHtml *html, const char *tag, int tagsize) BUG_MSG("nested <map>\n"); } else { if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) { + html->InFlags |= IN_MAP; hash_name = dStrconcat("#", attrbuf, NULL); url = a_Html_url_new(html, hash_name, NULL, 0); - html->maps.startNewMap(new ::object::String(url->url_string->str)); + html->maps.startNewMap(new ::object::String(URL_STR(url))); a_Url_free (url); dFree(hash_name); + } else { + BUG_MSG("name attribute is required for <map>\n"); } - html->InFlags |= IN_MAP; } } @@ -2259,8 +2237,18 @@ static void Html_tag_open_map(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_close_map(DilloHtml *html, int TagIdx) { + /* This is a hack for the perhaps frivolous feature of drawing image map + * shapes when there is no image to display. If this map is defined after + * an image that has not been loaded (img != NULL), tell the image to + * redraw. (It will only do so if it uses a map.) + */ + for (int i = 0; i < html->images->size(); i++) { + DilloImage *img = html->images->get(i)->image; + + if (img) + ((dw::Image*) img->dw)->forceMapRedraw(); + } html->InFlags &= ~IN_MAP; - a_Html_pop_tag(html, TagIdx); } /* @@ -2306,7 +2294,7 @@ static void Html_tag_open_area(DilloHtml *html, const char *tag, int tagsize) const char *attrbuf; int link = -1; Shape *shape = NULL; - + if (!(html->InFlags & IN_MAP)) { BUG_MSG("<area> element not inside <map>\n"); return; @@ -2368,7 +2356,7 @@ static void Html_tag_open_area(DilloHtml *html, const char *tag, int tagsize) dReturn_if_fail ( url != NULL ); if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "alt"))) a_Url_set_alt(url, attrbuf); - + link = Html_set_new_link(html, &url); } if (type == BACKGROUND) @@ -2384,45 +2372,30 @@ static void Html_tag_open_area(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_object(DilloHtml *html, const char *tag, int tagsize) { - StyleAttrs style_attrs; - Style *style; DilloUrl *url, *base_url = NULL; const char *attrbuf; + CssPropertyList props; if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "codebase"))) { base_url = a_Html_url_new(html, attrbuf, NULL, 0); } - + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "data"))) { url = a_Html_url_new(html, attrbuf, URL_STR(base_url), (base_url != NULL)); dReturn_if_fail ( url != NULL ); - style_attrs = *S_TOP(html)->style; - - if (a_Capi_get_flags(url) & CAPI_IsCached) { - style_attrs.color = Color::createSimple ( - HT2LT(html), - html->visited_color -/* - a_Color_vc(html->visited_color, - S_TOP(html)->style->color->getColor(), - html->link_color, - S_TOP(html)->style->backgroundColor->getColor()), -*/ - ); + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + html->styleEngine->setPseudoVisited (); } else { - style_attrs.color = Color::createSimple(HT2LT(html), - html->link_color); + html->styleEngine->setPseudoLink (); } - style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE; - style_attrs.x_link = Html_set_new_link(html, &url); - style_attrs.cursor = CURSOR_POINTER; + props.set(PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + html->styleEngine->setNonCssHints (&props); - style = Style::create (HT2LT(html), &style_attrs); - DW2TB(html->dw)->addText("[OBJECT]", style); - style->unref (); + HT2TB(html)->addText("[OBJECT]", html->styleEngine->wordStyle ()); } a_Url_free(base_url); } @@ -2456,7 +2429,7 @@ static const char* Html_get_javascript_link(DilloHtml *html) static void Html_add_anchor(DilloHtml *html, const char *name) { _MSG("Registering ANCHOR: %s\n", name); - if (!DW2TB(html->dw)->addAnchor (name, S_TOP(html)->style)) + if (!HT2TB(html)->addAnchor (name, html->styleEngine->style ())) BUG_MSG("Anchor names must be unique within the document\n"); /* * According to Sec. 12.2.1 of the HTML 4.01 spec, "anchor names that @@ -2473,9 +2446,9 @@ static void Html_add_anchor(DilloHtml *html, const char *name) */ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize) { - StyleAttrs style_attrs; - Style *old_style; DilloUrl *url; + char *tooltip_str = NULL; + CssPropertyList props; const char *attrbuf; /* TODO: add support for MAP with A HREF */ @@ -2490,44 +2463,51 @@ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize) url = a_Html_url_new(html, attrbuf, NULL, 0); dReturn_if_fail ( url != NULL ); - old_style = S_TOP(html)->style; - style_attrs = *old_style; - - if (a_Capi_get_flags(url) & CAPI_IsCached) { + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { html->InVisitedLink = true; - style_attrs.color = Color::createSimple ( - HT2LT(html), - html->visited_color -/* - a_Color_vc(html->visited_color, - S_TOP(html)->style->color->getColor(), - html->link_color, - S_TOP(html)->current_bg_color), -*/ - ); + html->styleEngine->setPseudoVisited (); + if (html->non_css_visited_color != -1) + props.set (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, + html->non_css_visited_color); } else { - style_attrs.color = Color::createSimple(HT2LT(html), - html->link_color); + html->styleEngine->setPseudoLink (); + if (html->non_css_link_color != -1) + props.set (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, + html->non_css_link_color); } -// if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) -// style_attrs.x_tooltip = a_Dw_tooltip_new_no_ref(attrbuf); - - style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE; - style_attrs.x_link = Html_set_new_link(html, &url); - style_attrs.cursor = CURSOR_POINTER; - - S_TOP(html)->style = - Style::create (HT2LT(html), &style_attrs); - old_style->unref (); + props.set (PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + } + if (prefs.show_tooltip && + (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) { + tooltip_str = dStrdup(attrbuf); + props.set (PROPERTY_X_TOOLTIP, CSS_TYPE_STRING, tooltip_str); } + html->styleEngine->setNonCssHints (&props); + dFree(tooltip_str); + + html->styleEngine->inheritBackgroundColor (); if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) { + char *nameVal; + const char *id = html->styleEngine->getId (); + if (prefs.show_extra_warnings) Html_check_name_val(html, attrbuf, "name"); - /* html->NameVal is freed in Html_process_tag */ - html->NameVal = a_Url_decode_hex_str(attrbuf); - Html_add_anchor(html, html->NameVal); + + nameVal = a_Url_decode_hex_str(attrbuf); + + if (nameVal) { + /* We compare the "id" value with the url-decoded "name" value */ + if (!id || strcmp(nameVal, id)) { + if (id) + BUG_MSG("'id' and 'name' attribute of <a> tag differ\n"); + Html_add_anchor(html, nameVal); + } + + dFree(nameVal); + } } } @@ -2537,49 +2517,40 @@ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_close_a(DilloHtml *html, int TagIdx) { html->InVisitedLink = false; - a_Html_pop_tag(html, TagIdx); } /* - * Insert underlined text in the page. + * <BLOCKQUOTE> */ -static void Html_tag_open_u(DilloHtml *html, const char *tag, int tagsize) +static void Html_tag_open_blockquote(DilloHtml *html, + const char *tag, int tagsize) { - Style *style; - StyleAttrs style_attrs; - - style = S_TOP(html)->style; - style_attrs = *style; - style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE; - S_TOP(html)->style = - Style::create (HT2LT(html), &style_attrs); - style->unref (); + Html_add_textblock(html, 9); } /* - * Insert strike-through text. Used by <S>, <STRIKE> and <DEL>. + * <Q> */ -static void Html_tag_open_strike(DilloHtml *html, const char *tag, int tagsize) +static void Html_tag_open_q(DilloHtml *html, const char *tag, int tagsize) { - Style *style; - StyleAttrs style_attrs; + /* + * Left Double Quotation Mark, which is wrong in many cases, but + * should at least be widely recognized. + */ + const char *U201C = "\xe2\x80\x9c"; - style = S_TOP(html)->style; - style_attrs = *style; - style_attrs.textDecoration |= TEXT_DECORATION_LINE_THROUGH; - S_TOP(html)->style = - Style::create (HT2LT(html), &style_attrs); - style->unref (); + HT2TB(html)->addText (U201C, html->styleEngine->wordStyle ()); } /* - * <BLOCKQUOTE> + * </Q> */ -static void Html_tag_open_blockquote(DilloHtml *html, - const char *tag, int tagsize) +static void Html_tag_close_q(DilloHtml *html, int TagIdx) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - Html_add_indented(html, 40, 40, 9); + /* Right Double Quotation Mark */ + const char *U201D = "\xe2\x80\x9d"; + + HT2TB(html)->addText (U201D, html->styleEngine->wordStyle ()); } /* @@ -2590,47 +2561,27 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize) const char *attrbuf; ListStyleType list_style_type; - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - Html_add_indented(html, 40, 0, 9); - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { + CssPropertyList props; + /* list_style_type explicitly defined */ - if (dStrncasecmp(attrbuf, "disc", 4) == 0) + if (dStrcasecmp(attrbuf, "disc") == 0) list_style_type = LIST_STYLE_TYPE_DISC; - else if (dStrncasecmp(attrbuf, "circle", 6) == 0) + else if (dStrcasecmp(attrbuf, "circle") == 0) list_style_type = LIST_STYLE_TYPE_CIRCLE; - else if (dStrncasecmp(attrbuf, "square", 6) == 0) + else if (dStrcasecmp(attrbuf, "square") == 0) list_style_type = LIST_STYLE_TYPE_SQUARE; else /* invalid value */ list_style_type = LIST_STYLE_TYPE_DISC; - } else { - if (S_TOP(html)->list_type == HTML_LIST_UNORDERED) { - /* Nested <UL>'s. */ - /* --EG :: I changed the behavior here : types are cycling instead of - * being forced to square. It's easier for mixed lists level counting. - */ - switch (S_TOP(html)->style->listStyleType) { - case LIST_STYLE_TYPE_DISC: - list_style_type = LIST_STYLE_TYPE_CIRCLE; - break; - case LIST_STYLE_TYPE_CIRCLE: - list_style_type = LIST_STYLE_TYPE_SQUARE; - break; - case LIST_STYLE_TYPE_SQUARE: - default: /* this is actually a bug */ - list_style_type = LIST_STYLE_TYPE_DISC; - break; - } - } else { - /* Either first <UL>, or a <OL> before. */ - list_style_type = LIST_STYLE_TYPE_DISC; - } + + props.set(CSS_PROPERTY_LIST_STYLE_TYPE, CSS_TYPE_ENUM, list_style_type); + html->styleEngine->setNonCssHints (&props); } - HTML_SET_TOP_ATTR(html, listStyleType, list_style_type); - S_TOP(html)->list_type = HTML_LIST_UNORDERED; + Html_add_textblock(html, 9); + S_TOP(html)->list_type = HTML_LIST_UNORDERED; S_TOP(html)->list_number = 0; S_TOP(html)->ref_list_item = NULL; } @@ -2641,11 +2592,8 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_dir(DilloHtml *html, const char *tag, int tagsize) { - ListStyleType list_style_type = LIST_STYLE_TYPE_DISC; + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - Html_add_indented(html, 40, 0, 9); - HTML_SET_TOP_ATTR(html, listStyleType, list_style_type); S_TOP(html)->list_type = HTML_LIST_UNORDERED; S_TOP(html)->list_number = 0; S_TOP(html)->ref_list_item = NULL; @@ -2668,28 +2616,29 @@ static void Html_tag_open_menu(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize) { const char *attrbuf; - ListStyleType list_style_type; int n = 1; - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - Html_add_indented(html, 40, 0, 9); - - list_style_type = LIST_STYLE_TYPE_DECIMAL; - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { + CssPropertyList props; + ListStyleType listStyleType = LIST_STYLE_TYPE_DECIMAL; + if (*attrbuf == '1') - list_style_type = LIST_STYLE_TYPE_DECIMAL; + listStyleType = LIST_STYLE_TYPE_DECIMAL; else if (*attrbuf == 'a') - list_style_type = LIST_STYLE_TYPE_LOWER_ALPHA; + listStyleType = LIST_STYLE_TYPE_LOWER_ALPHA; else if (*attrbuf == 'A') - list_style_type = LIST_STYLE_TYPE_UPPER_ALPHA; + listStyleType = LIST_STYLE_TYPE_UPPER_ALPHA; else if (*attrbuf == 'i') - list_style_type = LIST_STYLE_TYPE_LOWER_ROMAN; + listStyleType = LIST_STYLE_TYPE_LOWER_ROMAN; else if (*attrbuf == 'I') - list_style_type = LIST_STYLE_TYPE_UPPER_ROMAN; + listStyleType = LIST_STYLE_TYPE_UPPER_ROMAN; + + props.set (CSS_PROPERTY_LIST_STYLE_TYPE, CSS_TYPE_ENUM, listStyleType); + html->styleEngine->setNonCssHints (&props); } - HTML_SET_TOP_ATTR(html, listStyleType, list_style_type); + Html_add_textblock(html, 9); + S_TOP(html)->list_type = HTML_LIST_ORDERED; if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "start")) && @@ -2706,59 +2655,45 @@ static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize) { - StyleAttrs style_attrs; - Style *item_style, *word_style; + Style *style = html->styleEngine->style (); + Style *wordStyle = html->styleEngine->wordStyle (); Widget **ref_list_item; ListItem *list_item; int *list_number; const char *attrbuf; char buf[16]; + if (S_TOP(html)->list_type == HTML_LIST_NONE) + BUG_MSG("<li> outside <ul> or <ol>\n"); + html->InFlags |= IN_LI; - html->WordAfterLI = false; /* Get our parent tag's variables (used as state storage) */ list_number = &html->stack->getRef(html->stack->size()-2)->list_number; ref_list_item = &html->stack->getRef(html->stack->size()-2)->ref_list_item; - /* set the item style */ - word_style = S_TOP(html)->style; - style_attrs = *word_style; - //style_attrs.backgroundColor = Color::createShaded (HT2LT(html), 0xffff40); - //style_attrs.setBorderColor (Color::createSimple (HT2LT(html), 0x000000)); - //style_attrs.setBorderStyle (BORDER_SOLID); - //style_attrs.borderWidth.setVal (1); - item_style = Style::create (HT2LT(html), &style_attrs); - - DW2TB(html->dw)->addParbreak (2, word_style); + HT2TB(html)->addParbreak (0, wordStyle); list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width); - DW2TB(html->dw)->addWidget (list_item, item_style); - DW2TB(html->dw)->addParbreak (2, word_style); + HT2TB(html)->addWidget (list_item, style); + HT2TB(html)->addParbreak (0, wordStyle); *ref_list_item = list_item; S_TOP(html)->textblock = html->dw = list_item; - item_style->unref(); - /* Handle it when the user clicks on a link */ - html->connectSignals(list_item); - switch (S_TOP(html)->list_type) { - case HTML_LIST_ORDERED: + if (style->listStyleType == LIST_STYLE_TYPE_NONE) { + // none + } else if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) { + // ordered if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "value")) && (*list_number = strtol(attrbuf, NULL, 10)) < 0) { BUG_MSG("illegal negative LIST VALUE attribute; Starting from 0\n"); *list_number = 0; } - numtostr((*list_number)++, buf, 16, S_TOP(html)->style->listStyleType); - list_item->initWithText (dStrdup(buf), word_style); - list_item->addSpace (word_style); - html->PrevWasSPC = true; - break; - case HTML_LIST_NONE: - BUG_MSG("<li> outside <ul> or <ol>\n"); - default: - list_item->initWithWidget (new Bullet(), word_style); - list_item->addSpace (word_style); - break; + numtostr((*list_number)++, buf, 16, style->listStyleType); + list_item->initWithText (buf, wordStyle); + } else { + // unordered + list_item->initWithWidget (new Bullet(), wordStyle); } } @@ -2768,9 +2703,7 @@ static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_close_li(DilloHtml *html, int TagIdx) { html->InFlags &= ~IN_LI; - html->WordAfterLI = false; ((ListItem *)html->dw)->flush (); - a_Html_pop_tag(html, TagIdx); } /* @@ -2779,58 +2712,55 @@ static void Html_tag_close_li(DilloHtml *html, int TagIdx) static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) { Widget *hruler; - StyleAttrs style_attrs; - Style *style; + CssPropertyList props; char *width_ptr; const char *attrbuf; int32_t size = 0; - - style_attrs = *S_TOP(html)->style; - width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", "100%"); - style_attrs.width = a_Html_parse_length (html, width_ptr); - dFree(width_ptr); + width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", NULL); + if (width_ptr) { + props.set (CSS_PROPERTY_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + a_Html_parse_length (html, width_ptr)); + dFree(width_ptr); + } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "size"))) size = strtol(attrbuf, NULL, 10); - - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) { - if (dStrcasecmp (attrbuf, "left") == 0) - style_attrs.textAlign = TEXT_ALIGN_LEFT; - else if (dStrcasecmp (attrbuf, "right") == 0) - style_attrs.textAlign = TEXT_ALIGN_RIGHT; - else if (dStrcasecmp (attrbuf, "center") == 0) - style_attrs.textAlign = TEXT_ALIGN_CENTER; - } - + + a_Html_tag_set_align_attr(html, &props, tag, tagsize); + /* TODO: evaluate attribute */ if (a_Html_get_attr(html, tag, tagsize, "noshade")) { - style_attrs.setBorderStyle (BORDER_SOLID); - style_attrs.setBorderColor ( - Color::createShaded (HT2LT(html), style_attrs.color->getColor())); - if (size < 1) + props.set (CSS_PROPERTY_BORDER_TOP_STYLE, CSS_TYPE_ENUM, BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_BOTTOM_STYLE,CSS_TYPE_ENUM,BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_LEFT_STYLE, CSS_TYPE_ENUM, BORDER_SOLID); + props.set (CSS_PROPERTY_BORDER_RIGHT_STYLE, CSS_TYPE_ENUM, BORDER_SOLID); + + if (size <= 0) size = 1; - } else { - style_attrs.setBorderStyle (BORDER_INSET); - style_attrs.setBorderColor - (Color::createShaded (HT2LT(html), - S_TOP(html)->current_bg_color)); - if (size < 2) - size = 2; - } - - style_attrs.borderWidth.top = - style_attrs.borderWidth.left = (size + 1) / 2; - style_attrs.borderWidth.bottom = - style_attrs.borderWidth.right = size / 2; - style = Style::create (HT2LT(html), &style_attrs); - - DW2TB(html->dw)->addParbreak (5, S_TOP(html)->style); + } + + if (size > 0) { + CssLength size_top = CSS_CREATE_LENGTH ((size+1)/2, CSS_LENGTH_TYPE_PX); + CssLength size_bottom = CSS_CREATE_LENGTH (size / 2, CSS_LENGTH_TYPE_PX); + props.set (CSS_PROPERTY_BORDER_TOP_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + size_top); + props.set (CSS_PROPERTY_BORDER_LEFT_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + size_top); + props.set (CSS_PROPERTY_BORDER_BOTTOM_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + size_bottom); + props.set (CSS_PROPERTY_BORDER_RIGHT_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, + size_bottom); + } + + html->styleEngine->setNonCssHints (&props); + + HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); + hruler = new Ruler(); - hruler->setStyle (style); - DW2TB(html->dw)->addWidget (hruler, style); - style->unref (); - DW2TB(html->dw)->addParbreak (5, S_TOP(html)->style); + hruler->setStyle (html->styleEngine->style ()); + HT2TB(html)->addWidget (hruler, html->styleEngine->style ()); + HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); } /* @@ -2839,7 +2769,7 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_open_dl(DilloHtml *html, const char *tag, int tagsize) { /* may want to actually do some stuff here. */ - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } /* @@ -2847,8 +2777,7 @@ static void Html_tag_open_dl(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_dt(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_set_top_font(html, NULL, 0, 1, 1); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } /* @@ -2856,8 +2785,7 @@ static void Html_tag_open_dt(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_dd(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - Html_add_indented(html, 40, 40, 9); + Html_add_textblock(html, 9); } /* @@ -2865,14 +2793,8 @@ static void Html_tag_open_dd(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_pre(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); - /* Is the placement of this statement right? */ - S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_PRE; - HTML_SET_TOP_ATTR (html, whiteSpace, WHITE_SPACE_PRE); - html->pre_column = 0; - html->PreFirstChar = true; html->InFlags |= IN_PRE; } @@ -2882,8 +2804,7 @@ static void Html_tag_open_pre(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_close_pre(DilloHtml *html, int TagIdx) { html->InFlags &= ~IN_PRE; - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_pop_tag(html, TagIdx); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } /* @@ -2899,7 +2820,7 @@ static int Html_tag_pre_excludes(int tag_idx) /* initialize array */ if (!ei_set[0]) for (i = 0; es_set[i]; ++i) - ei_set[i] = Html_tag_index(es_set[i]); + ei_set[i] = a_Html_tag_index(es_set[i]); for (i = 0; ei_set[i]; ++i) if (tag_idx == ei_set[i]) @@ -2909,12 +2830,12 @@ static int Html_tag_pre_excludes(int tag_idx) /* * Handle <META> - * We do not support http-equiv=refresh because it's non standard, - * (the HTML 4.01 SPEC recommends explicitly to avoid it), and it - * can be easily abused! - * + * We do not support http-equiv=refresh with delay>0 because it's + * non standard, (the HTML 4.01 SPEC recommends explicitly to avoid it). * More info at: * http://lists.w3.org/Archives/Public/www-html/2000Feb/thread.html#msg232 + * Instant client-side redirects (delay=0) are supported: + * http://www.w3.org/TR/2008/NOTE-WCAG20-TECHS-20081211/H76.html * * TODO: Note that we're sending custom HTML while still IN_HEAD. This * is a hackish way to put the message. A much cleaner approach is to @@ -2930,9 +2851,8 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) " <tr><td bgcolor='#a0a0a0' colspan='2'>The author wanted you to go\n" " <a href='%s'>here</a>%s</td></tr></table><br>\n"; - const char *equiv, *content; - char delay_str[64]; - Dstr *ds_msg; + const char *p, *equiv, *content, *new_content; + char delay_str[64], *mr_url; int delay; /* only valid inside HEAD */ @@ -2943,49 +2863,178 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) if ((equiv = a_Html_get_attr(html, tag, tagsize, "http-equiv"))) { if (!dStrcasecmp(equiv, "refresh") && - (content = a_Html_get_attr(html, tag, tagsize, "content"))) { + (content = a_Html_get_attr(html, tag, tagsize, "content"))) { /* Get delay, if present, and make a message with it */ - if ((delay = strtol(content, NULL, 0))) + if ((delay = strtol(content, NULL, 0))) { snprintf(delay_str, 64, " after %d second%s.", - delay, (delay > 1) ? "s" : ""); - else + delay, (delay > 1) ? "s" : ""); + } else { sprintf(delay_str, "."); - + } /* Skip to anything after "URL=" */ - while (*content && *(content++) != '='); - - /* Send a custom HTML message. - * TODO: This is a hairy hack, - * It'd be much better to build a widget. */ - ds_msg = dStr_sized_new(256); - dStr_sprintf(ds_msg, meta_template, content, delay_str); - { - int SaveFlags = html->InFlags; - html->InFlags = IN_BODY; - html->TagSoup = false; - Html_write_raw(html, ds_msg->str, ds_msg->len, 0); - html->TagSoup = true; - html->InFlags = SaveFlags; + while (*content && *(content++) != '=') ; + /* Handle the case of a quoted URL */ + if (*content == '"' || *content == '\'') { + if ((p = strchr(content + 1, *content))) + mr_url = dStrndup(content + 1, p - content - 1); + else + mr_url = dStrdup(content + 1); + } else { + mr_url = dStrdup(content); } - dStr_free(ds_msg, 1); + + if (delay == 0) { + /* zero-delay redirection */ + html->stop_parser = true; + DilloUrl *new_url = a_Url_new(mr_url, URL_STR(html->base_url)); + if (a_Capi_dpi_verify_request(html->bw, new_url)) + a_UIcmd_redirection0((void*)html->bw, new_url); + a_Url_free(new_url); + } else { + /* Send a custom HTML message. + * TODO: This is a hairy hack, + * It'd be much better to build a widget. */ + Dstr *ds_msg = dStr_sized_new(256); + dStr_sprintf(ds_msg, meta_template, mr_url, delay_str); + { + int o_InFlags = html->InFlags; + int o_TagSoup = html->TagSoup; + html->InFlags = IN_BODY; + html->TagSoup = false; + Html_write_raw(html, ds_msg->str, ds_msg->len, 0); + html->TagSoup = o_TagSoup; + html->InFlags = o_InFlags; + } + dStr_free(ds_msg, 1); + } + dFree(mr_url); } else if (!dStrcasecmp(equiv, "content-type") && (content = a_Html_get_attr(html, tag, tagsize, "content"))) { - if (a_Misc_content_type_cmp(html->content_type, content)) { - const bool_t force = FALSE; - const char *new_content = - a_Capi_set_content_type(html->page_url, content, force); - /* Cannot ask cache whether the content type was changed, as - * this code in another bw might have already changed it for us. - */ - if (a_Misc_content_type_cmp(html->content_type, new_content)) { - a_Nav_repush(html->bw); - html->stop_parser = true; + _MSG("Html_tag_open_meta: content={%s}\n", content); + /* Cannot ask cache whether the content type was changed, as + * this code in another bw might have already changed it for us. + */ + new_content = a_Capi_set_content_type(html->page_url,content,"meta"); + if (a_Misc_content_type_cmp(html->content_type, new_content)) { + html->stop_parser = true; /* The cache buffer is no longer valid */ + a_UIcmd_repush(html->bw); + } + } + } +} + +/* + * Called by the network engine when a stylesheet has new data. + */ +static void Html_css_load_callback(int Op, CacheClient_t *Client) +{ + _MSG("Html_css_load_callback: Op=%d\n", Op); + if (Op) { /* EOF */ + BrowserWindow *bw = ((DilloWeb *)Client->Web)->bw; + /* Repush when we've got them all */ + if (--bw->NumPendingStyleSheets == 0) + a_UIcmd_repush(bw); + } +} + +/* + * Tell cache to retrieve a stylesheet + */ +void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url) +{ + char *data; + int len; + + dReturn_if (url == NULL || ! prefs.load_stylesheets); + + _MSG("Html_load_stylesheet: "); + if (a_Capi_get_buf(url, &data, &len)) { + _MSG("cached URL=%s len=%d", URL_STR(url), len); + if (a_Capi_get_flags_with_redirection(url) & CAPI_Completed) { + if (strncmp("@charset \"", data, 10) == 0) { + char *endq = strchr(data+10, '"'); + + if (endq && (endq - data <= 51)) { + /* IANA limits charset names to 40 characters */ + const char *ignored; + char *content_type; + + *endq = '\0'; + content_type = dStrconcat("text/css; charset=", data+10, NULL); + *endq = '"'; + a_Capi_unref_buf(url); + ignored = a_Capi_set_content_type(url, content_type, "meta"); + dFree(content_type); + a_Capi_get_buf(url, &data, &len); } } - } + html->styleEngine->parse(html, url, data, len, CSS_ORIGIN_AUTHOR); + } + a_Capi_unref_buf(url); + } else { + /* Fill a Web structure for the cache query */ + int ClientKey; + DilloWeb *Web = a_Web_new(url, html->page_url); + Web->bw = html->bw; + if ((ClientKey = a_Capi_open_url(Web, Html_css_load_callback, NULL))) { + ++html->bw->NumPendingStyleSheets; + a_Bw_add_client(html->bw, ClientKey, 0); + a_Bw_add_url(html->bw, url); + MSG("NumPendingStyleSheets=%d", html->bw->NumPendingStyleSheets); + } + } + MSG("\n"); +} + +/* + * Parse the LINK element (Only CSS stylesheets by now). + * (If it either hits or misses, is not relevant here; that's up to the + * cache functions) + * + * TODO: How will we know when to use "handheld"? Ask the html->bw->ui for + * screen dimensions, or a dillorc preference. + */ +static void Html_tag_open_link(DilloHtml *html, const char *tag, int tagsize) +{ + DilloUrl *url; + const char *attrbuf; + + //char *tag_str = dStrndup(tag, tagsize); + //MSG("Html_tag_open_link(): %s\n", tag_str); + //dFree(tag_str); + + /* When viewing suspicious HTML email, don't load LINK */ + dReturn_if (URL_FLAGS(html->base_url) & URL_SpamSafe); + + /* Ignore LINK outside HEAD */ + if (!(html->InFlags & IN_HEAD)) { + BUG_MSG("the LINK element must be inside the HEAD section\n"); + return; } + /* Remote stylesheets enabled? */ + dReturn_if_fail (prefs.load_stylesheets); + /* CSS stylesheet link */ + if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "rel")) || + dStrcasecmp(attrbuf, "stylesheet")) + return; + + /* IMPLIED attributes? */ + if (((attrbuf = a_Html_get_attr(html, tag, tagsize, "type")) && + dStrcasecmp(attrbuf, "text/css")) || + ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) && + !dStristr(attrbuf, "screen") && dStrcasecmp(attrbuf, "all"))) + return; + + if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "href")) || + !(url = a_Html_url_new(html, attrbuf, NULL, 0))) + return; + + MSG(" Html_tag_open_link(): addCssUrl %s\n", URL_STR(url)); + + html->addCssUrl(url); + a_Url_free(url); } /* @@ -3031,60 +3080,9 @@ static void Html_tag_open_base(DilloHtml *html, const char *tag, int tagsize) } } -/* - * <CODE> - */ -static void Html_tag_open_code(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0); -} - -/* - * <DFN> - */ -static void Html_tag_open_dfn(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 2, 3); -} - -/* - * <KBD> - */ -static void Html_tag_open_kbd(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0); -} - -/* - * <SAMP> - */ -static void Html_tag_open_samp(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0); -} - -/* - * <VAR> - */ -static void Html_tag_open_var(DilloHtml *html, const char *tag, int tagsize) -{ - a_Html_set_top_font(html, NULL, 0, 2, 2); -} - -/* - * <SUB> - */ -static void Html_tag_open_sub(DilloHtml *html, const char *tag, int tagsize) -{ - HTML_SET_TOP_ATTR (html, valign, VALIGN_SUB); -} - -/* - * <SUP> - */ -static void Html_tag_open_sup(DilloHtml *html, const char *tag, int tagsize) +static void Html_tag_open_default(DilloHtml *html,const char *tag,int tagsize) { - HTML_SET_TOP_ATTR (html, valign, VALIGN_SUPER); + html->styleEngine->inheritBackgroundColor(); } /* @@ -3092,25 +3090,18 @@ static void Html_tag_open_sup(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_div(DilloHtml *html, const char *tag, int tagsize) { - DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style); - a_Html_tag_set_align_attr (html, tag, tagsize); -} + CssPropertyList props; -/* - * </DIV>, also used for </TABLE> and </CENTER> - */ -static void Html_tag_close_div(DilloHtml *html, int TagIdx) -{ - DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style); - a_Html_pop_tag(html, TagIdx); + a_Html_tag_set_align_attr (html, &props, tag, tagsize); + html->styleEngine->setNonCssHints (&props); + Html_add_textblock(html, 0); } /* - * Default close for most tags - just pop the stack. + * Default close for most tags. */ static void Html_tag_close_default(DilloHtml *html, int TagIdx) { - a_Html_pop_tag(html, TagIdx); } /* @@ -3118,8 +3109,7 @@ static void Html_tag_close_default(DilloHtml *html, int TagIdx) */ static void Html_tag_close_par(DilloHtml *html, int TagIdx) { - DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style); - a_Html_pop_tag(html, TagIdx); + HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ()); } @@ -3158,55 +3148,56 @@ const TagInfo Tags[] = { /* acronym 010101 */ {"address", B8(010110),'R',2, Html_tag_open_address, Html_tag_close_par}, {"area", B8(010001),'F',0, Html_tag_open_area, Html_tag_close_default}, - {"b", B8(010101),'R',2, Html_tag_open_b, Html_tag_close_default}, + {"b", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, {"base", B8(100001),'F',0, Html_tag_open_base, Html_tag_close_default}, /* basefont 010001 */ /* bdo 010101 */ - {"big", B8(010101),'R',2, Html_tag_open_big_small, Html_tag_close_default}, - {"blockquote", B8(011110),'R',2,Html_tag_open_blockquote,Html_tag_close_par}, + {"big", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"blockquote", B8(011110),'R',2, Html_tag_open_blockquote, + Html_tag_close_default}, {"body", B8(011110),'O',1, Html_tag_open_body, Html_tag_close_body}, {"br", B8(010001),'F',0, Html_tag_open_br, Html_tag_close_default}, {"button", B8(011101),'R',2, Html_tag_open_button, Html_tag_close_button}, /* caption */ - {"center", B8(011110),'R',2, Html_tag_open_center, Html_tag_close_div}, - {"cite", B8(010101),'R',2, Html_tag_open_cite, Html_tag_close_default}, - {"code", B8(010101),'R',2, Html_tag_open_code, Html_tag_close_default}, + {"center", B8(011110),'R',2, Html_tag_open_center, Html_tag_close_center}, + {"cite", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"code", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, /* col 010010 'F' */ /* colgroup */ - {"dd", B8(011110),'O',1, Html_tag_open_dd, Html_tag_close_par}, - {"del", B8(011101),'R',2, Html_tag_open_strike, Html_tag_close_default}, - {"dfn", B8(010101),'R',2, Html_tag_open_dfn, Html_tag_close_default}, + {"dd", B8(011110),'O',1, Html_tag_open_dd, Html_tag_close_default}, + {"del", B8(011101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"dfn", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, {"dir", B8(011010),'R',2, Html_tag_open_dir, Html_tag_close_par}, /* TODO: complete <div> support! */ - {"div", B8(011110),'R',2, Html_tag_open_div, Html_tag_close_div}, + {"div", B8(011110),'R',2, Html_tag_open_div, Html_tag_close_default}, {"dl", B8(011010),'R',2, Html_tag_open_dl, Html_tag_close_par}, {"dt", B8(010110),'O',1, Html_tag_open_dt, Html_tag_close_par}, - {"em", B8(010101),'R',2, Html_tag_open_em, Html_tag_close_default}, + {"em", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, /* fieldset */ {"font", B8(010101),'R',2, Html_tag_open_font, Html_tag_close_default}, {"form", B8(011110),'R',2, Html_tag_open_form, Html_tag_close_form}, {"frame", B8(010010),'F',0, Html_tag_open_frame, Html_tag_close_default}, {"frameset", B8(011110),'R',2,Html_tag_open_frameset, Html_tag_close_default}, - {"h1", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, - {"h2", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, - {"h3", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, - {"h4", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, - {"h5", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, - {"h6", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_h}, + {"h1", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, + {"h2", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, + {"h3", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, + {"h4", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, + {"h5", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, + {"h6", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par}, {"head", B8(101101),'O',1, Html_tag_open_head, Html_tag_close_head}, {"hr", B8(010010),'F',0, Html_tag_open_hr, Html_tag_close_default}, {"html", B8(001110),'O',1, Html_tag_open_html, Html_tag_close_html}, - {"i", B8(010101),'R',2, Html_tag_open_i, Html_tag_close_default}, + {"i", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, {"iframe", B8(011110),'R',2, Html_tag_open_frame, Html_tag_close_default}, {"img", B8(010001),'F',0, Html_tag_open_img, Html_tag_close_default}, {"input", B8(010001),'F',0, Html_tag_open_input, Html_tag_close_default}, /* ins */ {"isindex", B8(110001),'F',0, Html_tag_open_isindex, Html_tag_close_default}, - {"kbd", B8(010101),'R',2, Html_tag_open_kbd, Html_tag_close_default}, + {"kbd", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, /* label 010101 */ /* legend 01?? */ {"li", B8(011110),'O',1, Html_tag_open_li, Html_tag_close_li}, - /* link 100000 'F' */ + {"link", B8(100001),'F',0, Html_tag_open_link, Html_tag_close_default}, {"map", B8(011001),'R',2, Html_tag_open_map, Html_tag_close_map}, /* menu 1010 -- TODO: not exactly 1010, it can contain LI and inline */ {"menu", B8(011010),'R',2, Html_tag_open_menu, Html_tag_close_par}, @@ -3214,25 +3205,25 @@ const TagInfo Tags[] = { /* noframes 1011 */ /* noscript 1011 */ {"object", B8(111101),'R',2, Html_tag_open_object, Html_tag_close_default}, - {"ol", B8(011010),'R',2, Html_tag_open_ol, Html_tag_close_par}, + {"ol", B8(011010),'R',2, Html_tag_open_ol, Html_tag_close_default}, /* optgroup */ {"option", B8(010001),'O',1, Html_tag_open_option, Html_tag_close_default}, {"p", B8(010110),'O',1, Html_tag_open_p, Html_tag_close_par}, /* param 010001 'F' */ {"pre", B8(010110),'R',2, Html_tag_open_pre, Html_tag_close_pre}, - /* q 010101 */ - {"s", B8(010101),'R',2, Html_tag_open_strike, Html_tag_close_default}, - {"samp", B8(010101),'R',2, Html_tag_open_samp, Html_tag_close_default}, + {"q", B8(010101),'R',2, Html_tag_open_q, Html_tag_close_q}, + {"s", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"samp", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, {"script", B8(111001),'R',2, Html_tag_open_script, Html_tag_close_script}, {"select", B8(010101),'R',2, Html_tag_open_select, Html_tag_close_select}, - {"small", B8(010101),'R',2, Html_tag_open_big_small, Html_tag_close_default}, - /* span 0101 */ - {"strike", B8(010101),'R',2, Html_tag_open_strike, Html_tag_close_default}, - {"strong", B8(010101),'R',2, Html_tag_open_strong, Html_tag_close_default}, + {"small", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"span", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"strike", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"strong", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, {"style", B8(100101),'R',2, Html_tag_open_style, Html_tag_close_style}, - {"sub", B8(010101),'R',2, Html_tag_open_sub, Html_tag_close_default}, - {"sup", B8(010101),'R',2, Html_tag_open_sup, Html_tag_close_default}, - {"table", B8(011010),'R',5, Html_tag_open_table, Html_tag_close_div}, + {"sub", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"sup", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"table", B8(011010),'R',5, Html_tag_open_table, Html_tag_close_center}, /* tbody */ {"td", B8(011110),'O',3, Html_tag_open_td, Html_tag_close_default}, {"textarea", B8(010101),'R',2,Html_tag_open_textarea,Html_tag_close_textarea}, @@ -3241,10 +3232,10 @@ const TagInfo Tags[] = { /* thead */ {"title", B8(100101),'R',2, Html_tag_open_title, Html_tag_close_title}, {"tr", B8(011010),'O',4, Html_tag_open_tr, Html_tag_close_default}, - {"tt", B8(010101),'R',2, Html_tag_open_tt, Html_tag_close_default}, - {"u", B8(010101),'R',2, Html_tag_open_u, Html_tag_close_default}, - {"ul", B8(011010),'R',2, Html_tag_open_ul, Html_tag_close_par}, - {"var", B8(010101),'R',2, Html_tag_open_var, Html_tag_close_default} + {"tt", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"u", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}, + {"ul", B8(011010),'R',2, Html_tag_open_ul, Html_tag_close_default}, + {"var", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default} }; #define NTAGS (sizeof(Tags)/sizeof(Tags[0])) @@ -3270,7 +3261,7 @@ static int Html_tag_compare(const char *p1, const char *p2) * Get 'tag' index * return -1 if tag is not handled yet */ -static int Html_tag_index(const char *tag) +int a_Html_tag_index(const char *tag) { int low, high, mid, cond; @@ -3301,17 +3292,17 @@ static int Html_needs_optional_close(int old_idx, int cur_idx) if (i_P == -1) { /* initialize the indexes of elements with optional close */ - i_P = Html_tag_index("p"), - i_LI = Html_tag_index("li"), - i_TD = Html_tag_index("td"), - i_TR = Html_tag_index("tr"), - i_TH = Html_tag_index("th"), - i_DD = Html_tag_index("dd"), - i_DT = Html_tag_index("dt"), - i_OPTION = Html_tag_index("option"); - // i_THEAD = Html_tag_index("thead"); - // i_TFOOT = Html_tag_index("tfoot"); - // i_COLGROUP = Html_tag_index("colgroup"); + i_P = a_Html_tag_index("p"), + i_LI = a_Html_tag_index("li"), + i_TD = a_Html_tag_index("td"), + i_TR = a_Html_tag_index("tr"), + i_TH = a_Html_tag_index("th"), + i_DD = a_Html_tag_index("dd"), + i_DT = a_Html_tag_index("dt"), + i_OPTION = a_Html_tag_index("option"); + // i_THEAD = a_Html_tag_index("thead"); + // i_TFOOT = a_Html_tag_index("tfoot"); + // i_COLGROUP = a_Html_tag_index("colgroup"); } if (old_idx == i_P || old_idx == i_DT) { @@ -3408,10 +3399,11 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) if (!(html->InFlags & IN_HTML)) { tag = "<html>"; - tag_idx = Html_tag_index(tag + 1); + tag_idx = a_Html_tag_index(tag + 1); if (tag_idx != new_idx || IsCloseTag) { /* implicit open */ Html_force_push_tag(html, tag_idx); + _MSG("Open : %*s%s\n", html->stack->size()," ",Tags[tag_idx].name); Tags[tag_idx].open (html, tag, strlen(tag)); } } @@ -3420,10 +3412,11 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) /* head element */ if (!(html->InFlags & IN_HEAD)) { tag = "<head>"; - tag_idx = Html_tag_index(tag + 1); + tag_idx = a_Html_tag_index(tag + 1); if (tag_idx != new_idx || IsCloseTag) { /* implicit open of the head element */ Html_force_push_tag(html, tag_idx); + _MSG("Open : %*s%s\n", html->stack->size()," ",Tags[tag_idx].name); Tags[tag_idx].open (html, tag, strlen(tag)); } } @@ -3432,20 +3425,57 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) /* body element */ if (html->InFlags & IN_HEAD) { tag = "</head>"; - tag_idx = Html_tag_index(tag + 2); - Tags[tag_idx].close (html, tag_idx); + tag_idx = a_Html_tag_index(tag + 2); + Html_tag_cleanup_at_close(html, tag_idx); } tag = "<body>"; - tag_idx = Html_tag_index(tag + 1); + tag_idx = a_Html_tag_index(tag + 1); if (tag_idx != new_idx || IsCloseTag) { /* implicit open */ Html_force_push_tag(html, tag_idx); + _MSG("Open : %*s%s\n", html->stack->size()," ",Tags[tag_idx].name); Tags[tag_idx].open (html, tag, strlen(tag)); } } } /* + * Parse attributes that can appear on any tag. + */ +static void Html_parse_common_attrs(DilloHtml *html, char *tag, int tagsize) +{ + const char *attrbuf; + + if (tagsize >= 8 && /* length of "<t id=i>" */ + (attrbuf = Html_get_attr2(html, tag, tagsize, "id", + HTML_LeftTrim | HTML_RightTrim))) { + /* According to the SGML declaration of HTML 4, all NAME values + * occuring outside entities must be converted to uppercase + * (this is what "NAMECASE GENERAL YES" says). But the HTML 4 + * spec states in Sec. 7.5.2 that anchor ids are case-sensitive. + * So we don't do it and hope for better specs in the future ... + */ + Html_check_name_val(html, attrbuf, "id"); + + html->styleEngine->setId(attrbuf); + } + + if (tagsize >= 11 && (prefs.parse_embedded_css || prefs.load_stylesheets)) { + /* length of "<t class=i>" or "<t style=i>" */ + attrbuf = Html_get_attr2(html, tag, tagsize, "class", + HTML_LeftTrim | HTML_RightTrim); + if (attrbuf) + html->styleEngine->setClass (attrbuf); + + attrbuf = Html_get_attr2(html, tag, tagsize, "style", + HTML_LeftTrim | HTML_RightTrim); + if (attrbuf) + html->styleEngine->setStyle (attrbuf); + } + +} + +/* * Process a tag, given as 'tag' and 'tagsize'. -- tagsize is [1 based] * ('tag' must include the enclosing angle brackets) * This function calls the right open or close function for the tag. @@ -3453,11 +3483,12 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) { int ci, ni; /* current and new tag indexes */ - const char *attrbuf; char *start = tag + 1; /* discard the '<' */ int IsCloseTag = (*start == '/'); - ni = Html_tag_index(start + IsCloseTag); + dReturn_if (html->stop_parser == true); + + ni = a_Html_tag_index(start + IsCloseTag); if (ni == -1) { /* TODO: doctype parsing is a bit fuzzy, but enough for the time being */ if (!(html->InFlags & IN_HTML)) { @@ -3491,40 +3522,30 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) /* Push the tag into the stack */ Html_push_tag(html, ni); + html->styleEngine->startElement (ni); + _MSG("Open : %*s%s\n", html->stack->size(), " ", Tags[ni].name); + + /* Parse attributes that can appear on any tag */ + Html_parse_common_attrs(html, tag, tagsize); + /* Call the open function for this tag */ + _MSG("Open : %s\n", Tags[ni].name); Tags[ni].open (html, tag, tagsize); if (html->stop_parser) break; - /* Now parse attributes that can appear on any tag */ - if (tagsize >= 8 && /* length of "<t id=i>" */ - (attrbuf = Html_get_attr2(html, tag, tagsize, "id", - HTML_LeftTrim | HTML_RightTrim))) { - /* According to the SGML declaration of HTML 4, all NAME values - * occuring outside entities must be converted to uppercase - * (this is what "NAMECASE GENERAL YES" says). But the HTML 4 - * spec states in Sec. 7.5.2 that anchor ids are case-sensitive. - * So we don't do it and hope for better specs in the future ... - */ - Html_check_name_val(html, attrbuf, "id"); - /* We compare the "id" value with the url-decoded "name" value */ - if (!html->NameVal || strcmp(html->NameVal, attrbuf)) { - if (html->NameVal) - BUG_MSG("'id' and 'name' attribute of <a> tag differ\n"); - Html_add_anchor(html, attrbuf); - } + if (S_TOP(html)->parse_mode != DILLO_HTML_PARSE_MODE_PRE && + (html->styleEngine->style ()->whiteSpace == WHITE_SPACE_PRE || + html->styleEngine->style ()->whiteSpace == WHITE_SPACE_PRE_WRAP)) { + S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_PRE; + html->pre_column = 0; + html->PreFirstChar = true; } - /* Reset NameVal */ - if (html->NameVal) { - dFree(html->NameVal); - html->NameVal = NULL; - } - - /* let the parser know this was an open tag */ - html->PrevWasOpenTag = true; + if (html->styleEngine->getId ()) + Html_add_anchor(html, html->styleEngine->getId ()); - /* Request inmediate close for elements with forbidden close tag. */ + /* Request immediate close for elements with forbidden close tag. */ /* TODO: XHTML always requires close tags. A simple implementation * of the commented clause below will make it work. */ if (/* parsing HTML && */ Tags[ni].EndTag == 'F') @@ -3538,13 +3559,13 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) /* Test for </x>, ReqTagClose, <x /> and <x/> */ if (*start == '/' || /* </x> */ html->ReqTagClose || /* request */ - (tag[tagsize - 2] == '/' && /* XML: */ - (isspace(tag[tagsize - 3]) || /* <x /> */ + (tag[tagsize-2] == '/' && /* XML: */ + (strchr(" \"'", tag[tagsize-3]) || /* [ "']/> */ (size_t)tagsize == strlen(Tags[ni].name) + 3))) { /* <x/> */ - - Tags[ni].close (html, ni); + + _MSG("Close: %s\n", Tags[ni].name); + Html_tag_cleanup_at_close(html, ni); /* This was a close tag */ - html->PrevWasOpenTag = false; html->ReqTagClose = false; } } @@ -3623,7 +3644,7 @@ static const char *Html_get_attr2(DilloHtml *html, tagsize-i, &entsize)) >= 0) { if (isocode >= 128) { char buf[4]; - int k, n = utf8encode(isocode, buf); + int k, n = a_Utf8_encode(isocode, buf); for (k = 0; k < n; ++k) dStr_append_c(Buf, buf[k]); } else { @@ -3687,29 +3708,6 @@ char *a_Html_get_attr_wdef(DilloHtml *html, } /* - * Add a widget to the page. - */ -static void Html_add_widget(DilloHtml *html, - Widget *widget, - char *width_str, - char *height_str, - StyleAttrs *style_attrs) -{ - StyleAttrs new_style_attrs; - Style *style; - - new_style_attrs = *style_attrs; - new_style_attrs.width = width_str ? - a_Html_parse_length (html, width_str) : LENGTH_AUTO; - new_style_attrs.height = height_str ? - a_Html_parse_length (html, height_str) : LENGTH_AUTO; - style = Style::create (HT2LT(html), &new_style_attrs); - DW2TB(html->dw)->addWidget (widget, style); - style->unref (); -} - - -/* * Dispatch the apropriate function for 'Op' * This function is a Cache client and gets called whenever new data arrives * Op : operation to perform. @@ -3739,13 +3737,13 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) Textblock *textblock; int token_start, buf_index; - dReturn_val_if_fail ((textblock = DW2TB(html->dw)) != NULL, 0); + dReturn_val_if_fail ((textblock = HT2TB(html)) != NULL, 0); /* Now, 'buf' and 'bufsize' define a buffer aligned to start at a token * boundary. Iterate through tokens until end of buffer is reached. */ buf_index = 0; token_start = buf_index; - while ((buf_index < bufsize) && (html->stop_parser == false)) { + while ((buf_index < bufsize) && !html->stop_parser) { /* invariant: buf_index == bufsize || token_start == buf_index */ if (S_TOP(html)->parse_mode == @@ -3774,7 +3772,7 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) if (isspace(buf[buf_index])) { /* whitespace: group all available whitespace */ - while (++buf_index < bufsize && isspace(buf[buf_index])); + while (++buf_index < bufsize && isspace(buf[buf_index])) ; Html_process_space(html, buf + token_start, buf_index - token_start); token_start = buf_index; |