etc. */
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
* an empty string (don't know whether the latter is
* correct, has to be clarified with the specs), so
* that for empty strings, " " is assumed. */
style_attrs.textAlignChar = ' ';
else
style_attrs.textAlignChar = charattr[0];
} else
/* TODO: Examine LANG attr of . */
style_attrs.textAlignChar = '.';
}
#endif
html->styleEngine->setNonCssHint(CSS_PROPERTY_TEXT_ALIGN, CSS_TYPE_ENUM,
textAlignType);
}
}
/*
* Evaluates the VALIGN attribute (top|bottom|middle|baseline) and
* sets the style in style_attrs. Returns true when set.
*/
bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize)
{
const char *attr;
VAlignType valign;
if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) {
if (dStrAsciiCasecmp (attr, "top") == 0)
valign = VALIGN_TOP;
else if (dStrAsciiCasecmp (attr, "bottom") == 0)
valign = VALIGN_BOTTOM;
else if (dStrAsciiCasecmp (attr, "baseline") == 0)
valign = VALIGN_BASELINE;
else
valign = VALIGN_MIDDLE;
html->styleEngine->setNonCssHint (CSS_PROPERTY_VERTICAL_ALIGN,
CSS_TYPE_ENUM, valign);
return true;
} else
return false;
}
/*
* Create and add a new Textblock to the current Textblock
*/
static void Html_add_textblock(DilloHtml *html, int space)
{
Textblock *textblock = new Textblock (prefs.limit_text_width);
HT2TB(html)->addParbreak (space, html->wordStyle ());
HT2TB(html)->addWidget (textblock, html->style ());
HT2TB(html)->addParbreak (space, html->wordStyle ());
S_TOP(html)->textblock = html->dw = textblock;
S_TOP(html)->hand_over_break = true;
}
/*
* Create and initialize a new DilloHtml class
*/
DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url,
const char *content_type)
{
/* 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 */
Start_Buf = NULL;
Start_Ofs = 0;
_MSG("DilloHtml(): content type: %s\n", content_type);
this->content_type = dStrdup(content_type);
/* get charset */
a_Misc_parse_content_type(content_type, NULL, NULL, &charset);
stop_parser = false;
CurrTagOfs = 0;
OldTagOfs = 0;
OldTagLine = 1;
DocType = DT_NONE; /* assume Tag Soup 0.0! :-) */
DocTypeVersion = 0.0f;
styleEngine = new StyleEngine (HT2LT (this));
cssUrls = new misc::SimpleVector \n");
offset = TAB_SIZE - html->pre_column % TAB_SIZE;
spaceCnt += offset;
html->pre_column += offset;
break;
default:
spaceCnt++;
html->pre_column++;
break;
}
html->PrevWasCR = (space[i] == '\r');
}
if (spaceCnt) {
// add break possibility for the white-space:pre-wrap case
HT2TB(html)->addBreakOption (html->wordStyle (), false);
spc = dStrnfill(spaceCnt, ' ');
HT2TB(html)->addText (spc, spaceCnt, html->wordStyle ());
dFree(spc);
}
} else {
if (SGML_SPCDEL) {
/* SGML_SPCDEL ignores white space immediately after an open tag */
} else if (html->wordStyle ()->whiteSpace == WHITE_SPACE_PRE_LINE) {
Html_process_space_pre_line(html, space, spacesize);
} else {
HT2TB(html)->addSpace(html->wordStyle ());
}
if (parse_mode == DILLO_HTML_PARSE_MODE_STASH_AND_BODY)
html->StashSpace = (html->Stash->len > 0);
}
}
/*
* Handles putting the word into its proper place
* > STASH and VERBATIM --> html->Stash
* > otherwise it goes through addText()
*
* Entities are parsed (or not) according to parse_mode.
* 'word' is a '\0'-terminated string.
*/
static void Html_process_word(DilloHtml *html, const char *word, int size)
{
int i, j, start;
char *Pword;
DilloHtmlParseMode parse_mode = S_TOP(html)->parse_mode;
if (S_TOP(html)->display_none)
return;
if (parse_mode == DILLO_HTML_PARSE_MODE_STASH ||
parse_mode == DILLO_HTML_PARSE_MODE_STASH_AND_BODY) {
if (html->StashSpace) {
dStr_append_c(html->Stash, ' ');
html->StashSpace = false;
}
Pword = a_Html_parse_entities(html, word, size);
dStr_append(html->Stash, Pword);
dFree(Pword);
} else if (parse_mode == DILLO_HTML_PARSE_MODE_VERBATIM) {
/* word goes in untouched, it is not processed here. */
dStr_append_l(html->Stash, word, size);
}
if (parse_mode == DILLO_HTML_PARSE_MODE_STASH ||
parse_mode == DILLO_HTML_PARSE_MODE_VERBATIM) {
/* skip until the closing instructions */
} else if (parse_mode == DILLO_HTML_PARSE_MODE_PRE) {
/* all this overhead is to catch white-space entities */
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])) ;
Html_process_space(html, Pword + start, i - start);
} else {
while (Pword[++i] && !isspace(Pword[i])) ;
HT2TB(html)->addText(Pword + start, i - start, html->wordStyle ());
html->pre_column += i - start;
html->PreFirstChar = false;
}
dFree(Pword);
} else {
const char *word2, *beyond_word2;
Pword = NULL;
if (!memchr(word,'&', size)) {
/* No entities */
word2 = word;
beyond_word2 = word + size;
} else {
/* Collapse white-space entities inside the word (except ) */
Pword = a_Html_parse_entities(html, word, size);
/* 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;
beyond_word2 = word2 + strlen(word2);
}
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;
HT2TB(html)->addBreakOption(html->wordStyle (), false);
} else if (a_Utf8_ideographic(word2+i, beyond_word2, &len)) {
i += len;
HT2TB(html)->addText(word2 + start, i - start, html->wordStyle ());
HT2TB(html)->addBreakOption(html->wordStyle (), false);
} else {
do {
i += len;
} while (word2[i] && !isspace(word2[i]) &&
strncmp(word2+i, utf8_zero_width_space, 3) &&
(!a_Utf8_ideographic(word2+i, beyond_word2, &len)));
HT2TB(html)->addText(word2 + start, i - start, html->wordStyle ());
}
}
if (Pword == word2)
dFree(Pword);
}
}
/*
* Does the tag in tagstr (e.g. "p") match the tag in the tag, tagsize
* structure, with the initial < skipped over (e.g. "P align=center>")?
*/
static bool Html_match_tag(const char *tagstr, char *tag, int tagsize)
{
int i;
for (i = 0; i < tagsize && tagstr[i] != '\0'; i++) {
if (D_ASCII_TOLOWER(tagstr[i]) != D_ASCII_TOLOWER(tag[i]))
return false;
}
/* The test for '/' is for xml compatibility: "empty/>" will be matched. */
if (i < tagsize && (isspace(tag[i]) || tag[i] == '>' || tag[i] == '/'))
return true;
return false;
}
/*
* This function is called after popping the stack, to
* 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)
HT2TB(html)->handOverBreak (html->style ());
HT2TB(html)->flush ();
html->dw = S_TOP(html)->textblock;
}
}
/*
* Push the tag (copying attributes from the top of the stack)
*/
static void Html_push_tag(DilloHtml *html, int tag_idx)
{
int n_items;
n_items = html->stack->size ();
html->stack->increase ();
/* We'll copy the former stack item and just change the tag and its index
* 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;
html->dw = S_TOP(html)->textblock;
}
/*
* Push the tag (used to force en element with optional open into the stack)
* Note: now it's the same as Html_push_tag(), but things may change...
*/
static void Html_force_push_tag(DilloHtml *html, int tag_idx)
{
html->startElement (tag_idx);
Html_push_tag(html, tag_idx);
}
/*
* Pop the top tag in the stack
*/
static void Html_real_pop_tag(DilloHtml *html)
{
bool hand_over_break;
html->styleEngine->endElement (S_TOP(html)->tag_idx);
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);
if (toptag.close)
toptag.close(html);
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
* which defines optional close tags, and the will to deliver useful diagnose
* messages for bad-formed HTML, it'll go as follows:
* 1.- Search the stack for the first tag that requires a close tag.
* 2.- If it matches, clean all the optional-close tags in between.
* 3.- Cleanup the matching tag. (on error, give a warning message)
*
* If 'w3c_mode' is NOT enabled:
* 1.- Search the stack for a matching tag based on tag level.
* 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 new_idx)
{
static int i_BUTTON = a_Html_tag_index("button"),
i_SELECT = a_Html_tag_index("select"),
i_TEXTAREA = a_Html_tag_index("textarea");
int w3c_mode = !prefs.w3c_plus_heuristics;
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();
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 ((new_idx == i_BUTTON && html->InFlags & IN_BUTTON) ||
(new_idx == i_SELECT && html->InFlags & IN_SELECT) ||
(new_idx == i_TEXTAREA && html->InFlags & IN_TEXTAREA)) {
/* let these elements close tags inside them */
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 {
BUG_MSG("unexpected closing tag: %s>.\n", new_tag.name);
}
}
/*
* Avoid nesting and inter-nesting of BUTTON, SELECT and TEXTAREA,
* by closing them before opening another.
* This is not an HTML SPEC restriction , but it avoids lots of trouble
* inside dillo (concurrent inputs), and makes almost no sense to have.
*/
static void Html_tag_cleanup_nested_inputs(DilloHtml *html, int new_idx)
{
static int i_BUTTON = a_Html_tag_index("button"),
i_SELECT = a_Html_tag_index("select"),
i_TEXTAREA = a_Html_tag_index("textarea");
int stack_idx, u_idx, matched = 0;
dReturn_if_fail(html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA));
dReturn_if_fail(new_idx == i_BUTTON || new_idx == i_SELECT ||
new_idx == i_TEXTAREA);
/* Get the unclosed tag index */
u_idx = (html->InFlags & IN_BUTTON) ? i_BUTTON :
(html->InFlags & IN_SELECT) ? i_SELECT : i_TEXTAREA;
/* Look for it inside the stack */
stack_idx = html->stack->size();
while (--stack_idx) {
if (html->stack->getRef(stack_idx)->tag_idx == u_idx) {
/* matching tag found */
matched = 1;
break;
}
}
if (matched) {
BUG_MSG("attempt to nest <%s> element inside <%s> -- closing <%s>\n",
Tags[new_idx].name, Tags[u_idx].name, Tags[u_idx].name);
Html_tag_cleanup_to_idx(html, stack_idx);
} else {
MSG_WARN("Inconsistent parser state, flag is SET but no '%s' element"
"was found in the stack\n", Tags[u_idx].name);
}
html->InFlags &= ~(IN_BUTTON | IN_SELECT | IN_TEXTAREA);
}
/*
* Some parsing routines.
*/
/*
* Used by a_Html_parse_length
*/
static CssLength Html_parse_length_or_multi_length (const char *attr,
char **endptr)
{
CssLength l;
double v;
char *end;
v = strtod (attr, &end);
switch (*end) {
case '%':
end++;
l = CSS_CREATE_LENGTH (v / 100, CSS_LENGTH_TYPE_PERCENTAGE);
break;
case '*':
end++;
l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_RELATIVE);
break;
/*
The "px" suffix seems not allowed by HTML4.01 SPEC.
case 'p':
if (end[1] == 'x')
end += 2;
*/
default:
l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_PX);
break;
}
if (endptr)
*endptr = end;
return l;
}
/*
* Returns a length or a percentage, or UNDEF_LENGTH in case
* of an error, or if attr is NULL.
*/
CssLength a_Html_parse_length (DilloHtml *html, const char *attr)
{
CssLength l;
char *end;
l = Html_parse_length_or_multi_length (attr, &end);
if (CSS_LENGTH_TYPE (l) == CSS_LENGTH_TYPE_RELATIVE)
/* not allowed as &Length; */
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);
l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
}
}
_MSG("a_Html_parse_length: \"%s\" %d\n", attr, CSS_LENGTH_VALUE(l));
return l;
}
/*
* Parse a color attribute.
* Return value: parsed color, or default_color (+ error msg) on error.
*/
int32_t a_Html_color_parse(DilloHtml *html, const char *str,
int32_t default_color)
{
int err = 1;
int32_t color = a_Color_parse(str, default_color, &err);
if (err) {
BUG_MSG("color \"%s\" is not in \"#RRGGBB\" format\n", str);
}
return color;
}
/*
* Check that 'val' is composed of characters inside [A-Za-z0-9:_.-]
* Note: ID can't have entities, but this check is enough (no '&').
* Return value: 1 if OK, 0 otherwise.
*/
static int
Html_check_name_val(DilloHtml *html, const char *val, const char *attrname)
{
if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) {
bool valid = *val && !strchr(val, ' ');
if (!valid) {
BUG_MSG("'%s' value must not be empty and must not contain spaces.\n",
attrname);
}
return valid ? 1 : 0;
} else {
int i;
for (i = 0; val[i]; ++i)
if (!isascii(val[i]) || !(isalnum(val[i]) || strchr(":_.-", val[i])))
break;
if (val[i] || !(isascii(val[0]) && isalpha(val[0])))
BUG_MSG("'%s' value \"%s\" is not of the form "
"[A-Za-z][A-Za-z0-9:_.-]*\n", attrname, val);
return !(val[i]);
}
}
/*
* Handle DOCTYPE declaration
*
* Follows the convention that HTML 4.01
* doctypes which include a full w3c DTD url are treated as
* standards-compliant, but 4.01 without the url and HTML 4.0 and
* earlier are not. XHTML doctypes are always standards-compliant
* whether or not an url is present.
*
* Note: I'm not sure about this convention. The W3C validator
* 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
*
* This is not a full DOCTYPE parser, just enough for what Dillo uses.
*/
static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize)
{
static const char HTML_SGML_sig [] = "";
static const char HTML20 [] = "-//IETF//DTD HTML";
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";
static const char HTML401_url[] = "http://www.w3.org/TR/html4/";
static const char XHTML1 [] = "-//W3C//DTD XHTML 1.0";
static const char XHTML1_url [] = "http://www.w3.org/TR/xhtml1/DTD/";
static const char XHTML11 [] = "-//W3C//DTD XHTML 1.1";
static const char XHTML11_url[] = "http://www.w3.org/TR/xhtml11/DTD/";
size_t i;
int quote;
char *p, *ntag = dStrndup(tag, tagsize);
/* Tag sanitization: Collapse whitespace between tokens
* 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) ;
} else if ((quote = *p) == '"' || *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;
}
} else {
ntag[i++] = *p;
}
if (!*p)
break;
}
ntag[i] = 0;
_MSG("New: {%s}\n", ntag);
if (html->DocType != DT_NONE)
BUG_MSG("Multiple DOCTYPE declarations.\n");
/* The default DT_NONE type is TagSoup */
if (i > strlen(HTML_SGML_sig) && // avoid out of bounds reads!
!dStrnAsciiCasecmp(ntag, HTML_SGML_sig, strlen(HTML_SGML_sig))) {
p = ntag + strlen(HTML_SGML_sig) + 1;
if (!strncmp(p, HTML401, strlen(HTML401)) &&
dStriAsciiStr(p + strlen(HTML401), HTML401_url)) {
html->DocType = DT_HTML;
html->DocTypeVersion = 4.01f;
} else if (!strncmp(p, XHTML1, strlen(XHTML1)) &&
dStriAsciiStr(p + strlen(XHTML1), XHTML1_url)) {
html->DocType = DT_XHTML;
html->DocTypeVersion = 1.0f;
} else if (!strncmp(p, XHTML11, strlen(XHTML11)) &&
dStriAsciiStr(p + strlen(XHTML11), XHTML11_url)) {
html->DocType = DT_XHTML;
html->DocTypeVersion = 1.1f;
} else if (!strncmp(p, HTML40, strlen(HTML40))) {
html->DocType = DT_HTML;
html->DocTypeVersion = 4.0f;
} else if (!strncmp(p, HTML32, strlen(HTML32))) {
html->DocType = DT_HTML;
html->DocTypeVersion = 3.2f;
} else if (!strncmp(p, HTML20, strlen(HTML20))) {
html->DocType = DT_HTML;
html->DocTypeVersion = 2.0f;
}
} else if (!dStrAsciiCasecmp(ntag, HTML5_sig)) {
html->DocType = DT_HTML;
html->DocTypeVersion = 5.0f;
}
if (html->DocType == DT_NONE) {
html->DocType = DT_UNRECOGNIZED;
BUG_MSG("DOCTYPE not recognized:\n%s.\n", ntag);
}
dFree(ntag);
}
/*
* Handle open HTML element
*/
static void Html_tag_open_html(DilloHtml *html, const char *tag, int tagsize)
{
/* The IN_HTML flag will be kept set until at IN_EOF condition.
* This allows to handle pages with multiple or uneven HTML tags */
if (!(html->InFlags & IN_HTML))
html->InFlags |= IN_HTML;
if (html->Num_HTML < UCHAR_MAX)
++html->Num_HTML;
if (html->Num_HTML > 1) {
BUG_MSG("HTML element was already open\n");
html->ReqTagClose = true;
}
}
/*
* Handle close HTML element
*/
static void Html_tag_close_html(DilloHtml *html)
{
_MSG("Html_tag_close_html: Num_HTML=%d\n", html->Num_HTML);
}
/*
* Handle open HEAD element
*/
static void Html_tag_open_head(DilloHtml *html, const char *tag, int tagsize)
{
if (html->InFlags & IN_BODY) {
BUG_MSG("HEAD element must go before the BODY section\n");
html->ReqTagClose = true;
return;
}
if (html->Num_HEAD < UCHAR_MAX)
++html->Num_HEAD;
if (html->InFlags & IN_HEAD) {
BUG_MSG("HEAD element was already open\n");
html->ReqTagClose = true;
} else if (html->Num_HEAD > 1) {
BUG_MSG("HEAD section already finished -- ignoring\n");
html->ReqTagClose = true;
} else {
html->InFlags |= IN_HEAD;
}
}
/*
* Handle close HEAD element
* Note: HEAD is parsed once completely got.
*/
static void Html_tag_close_head(DilloHtml *html)
{
if (html->InFlags & IN_HEAD) {
if (html->Num_HEAD == 1) {
/* match for the well formed start of HEAD section */
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));
}
} else if (html->Num_HEAD > 1) {
--html->Num_HEAD;
}
} else {
/* not reached, see Html_tag_cleanup_at_close() */
}
}
/*
* Handle open TITLE
* calls stash init, where the title string will be stored
*/
static void Html_tag_open_title(DilloHtml *html, const char *tag, int tagsize)
{
/* fill the stash buffer so TITLE content can be ignored
* when not valid, redundant or outside HEAD section */
a_Html_stash_init(html);
if (html->InFlags & IN_HEAD) {
if (html->Num_TITLE < UCHAR_MAX)
++html->Num_TITLE;
if (html->Num_TITLE > 1)
BUG_MSG("A redundant TITLE element was found\n");
} else {
BUG_MSG("TITLE element must be inside the HEAD section -- ignoring\n");
}
}
/*
* Handle close TITLE
* set page-title in the browser window and in the history.
*/
static void Html_tag_close_title(DilloHtml *html)
{
if (html->InFlags & IN_HEAD && html->Num_TITLE == 1) {
/* title is only valid inside HEAD */
a_UIcmd_set_page_title(html->bw, html->Stash->str);
a_History_set_title_by_url(html->page_url, html->Stash->str);
}
}
/*
* Handle open SCRIPT
* initializes stash, where the embedded code will be stored.
* MODE_VERBATIM is used because MODE_STASH catches entities.
*/
static void Html_tag_open_script(DilloHtml *html, const char *tag, int tagsize)
{
a_Html_stash_init(html);
S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM;
}
/*
* Handle close SCRIPT
*/
static void Html_tag_close_script(DilloHtml *html)
{
/* eventually the stash will be sent to an interpreter for parsing */
}
/*
* Handle open STYLE
* 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"))) {
if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f)
BUG_MSG("type attribute is required for