diff options
author | Andrew Sidwell <andy@entai.co.uk> | 2008-06-30 10:45:26 +0000 |
---|---|---|
committer | Andrew Sidwell <andy@entai.co.uk> | 2008-06-30 10:45:26 +0000 |
commit | 833ee4b1f01b5da2327ab79777219b88528162c6 (patch) | |
tree | 6e740940753b73513528c6cc932361008af3860b /src/treebuilder/in_foreign_content.c | |
parent | 17447f074c102bdac9fdf3e1e0308c1b2e9718b6 (diff) | |
download | libhubbub-833ee4b1f01b5da2327ab79777219b88528162c6.tar.gz libhubbub-833ee4b1f01b5da2327ab79777219b88528162c6.tar.bz2 |
Add "in foreign content" handling. Not convinced this is the best way.
svn path=/trunk/hubbub/; revision=4475
Diffstat (limited to 'src/treebuilder/in_foreign_content.c')
-rw-r--r-- | src/treebuilder/in_foreign_content.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/treebuilder/in_foreign_content.c b/src/treebuilder/in_foreign_content.c new file mode 100644 index 0000000..d1338e7 --- /dev/null +++ b/src/treebuilder/in_foreign_content.c @@ -0,0 +1,139 @@ +/* + * This file is part of Hubbub. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2008 Andrew Sidwell + */ + +#include <assert.h> +#include <string.h> + +#include "treebuilder/modes.h" +#include "treebuilder/internal.h" +#include "treebuilder/treebuilder.h" +#include "utils/utils.h" + + + +static bool element_in_scope_in_non_html_ns(hubbub_treebuilder *treebuilder) +{ + uint32_t node; + + if (treebuilder->context.element_stack == NULL) + return false; + + for (node = treebuilder->context.current_node; node > 0; node--) { + element_type node_ns = + treebuilder->context.element_stack[node].ns; + + if (node_ns != HTML) + return true; + } + + return false; +} + + + +/** + * Handle tokens in "in foreign content" insertion mode + * + * \param treebuilder The treebuilder instance + * \param token The token to process + * \return True to reprocess the token, false otherwise + */ +bool handle_in_foreign_content(hubbub_treebuilder *treebuilder, + const hubbub_token *token) +{ + bool reprocess = false; + + switch (token->type) { + case HUBBUB_TOKEN_CHARACTER: + append_text(treebuilder, &token->data.character); + break; + case HUBBUB_TOKEN_COMMENT: + process_comment_append(treebuilder, token, + treebuilder->context.element_stack[ + treebuilder->context.current_node].node); + break; + case HUBBUB_TOKEN_DOCTYPE: + /** \todo parse error */ + break; + case HUBBUB_TOKEN_START_TAG: + { + element_type type = element_type_from_name(treebuilder, + &token->data.tag.name); + + element_type cur_node = current_node(treebuilder); + hubbub_ns cur_node_ns = current_node_ns(treebuilder); + + if (cur_node_ns == HUBBUB_NS_HTML || + (cur_node_ns == HUBBUB_NS_MATHML && + (type != MGLYPH && type != MALIGNMARK) && + (cur_node == MI || cur_node == MO || + cur_node == MN || cur_node == MS || + cur_node == MTEXT))) { + treebuilder->context.mode = + treebuilder->context.second_mode; + hubbub_treebuilder_token_handler(token, treebuilder); + + if (treebuilder->context.mode == IN_FOREIGN_CONTENT && + !element_in_scope_in_non_html_ns(treebuilder)) { + treebuilder->context.mode = + treebuilder->context.second_mode; + } + } else if (type == B || type == BIG || type == BLOCKQUOTE || + type == BODY || type == BR || type == CENTER || + type == CODE || type == DD || type == DIV || + type == DL || type == DT || type == EM || + type == EMBED || type == FONT || type == H1 || + type == H2 || type == H3 || type == H4 || + type == H5 || type == H6 || type == HEAD || + type == HR || type == I || type == IMG || + type == LI || type == LISTING || + type == MENU || type == META || type == NOBR || + type == OL || type == P || type == PRE || + type == RUBY || type == S || type == SMALL || + type == SPAN || type == STRONG || + type == STRIKE || type == SUB || type == SUP || + type == TABLE || type == TT || type == U || + type == UL || type == VAR) { + /** \todo parse error */ + + while (cur_node_ns != HUBBUB_NS_HTML) { + void *node; + element_stack_pop(treebuilder, &cur_node_ns, + &cur_node, &node); + cur_node_ns = current_node_ns(treebuilder); + } + + treebuilder->context.mode = + treebuilder->context.second_mode; + } else { + hubbub_tag tag = token->data.tag; + + adjust_foreign_attributes(treebuilder, &tag); + + /* Set to the right namespace and insert */ + tag.ns = cur_node_ns; + + if (token->data.tag.self_closing) { + insert_element_no_push(treebuilder, &tag); + /** \todo ack sc flag */ + } else { + insert_element(treebuilder, &tag); + } + } + } + break; + case HUBBUB_TOKEN_END_TAG: + /** \parse error */ + break; + case HUBBUB_TOKEN_EOF: + reprocess = true; + break; + } + + return reprocess; +} + |