/** * Handle token in "in table" insertion mode * * \param treebuilder The treebuilder instance * \param token The token to handle * \return True to reprocess token, false otherwise */ hubbub_error handle_in_table(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; bool handled = true; switch (token->type) { case HUBBUB_TOKEN_CHARACTER: if (treebuilder->context.element_stack[ current_table(treebuilder) ].tainted) { handled = false; } else { err = process_characters_expect_whitespace( treebuilder, token, true); handled = (err == HUBBUB_OK); } break; case HUBBUB_TOKEN_COMMENT: err = 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); bool tainted = treebuilder->context.element_stack[ current_table(treebuilder) ].tainted; if (type == CAPTION) { clear_stack_table_context(treebuilder); treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); if (err != HUBBUB_OK) { treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); return err; } err = insert_element(treebuilder, &token->data.tag, true); if (err != HUBBUB_OK) { hubbub_ns ns; element_type type; void *node; uint32_t index; formatting_list_remove(treebuilder, treebuilder->context.formatting_list_end, &ns, &type, &node, &index); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, node); return err; } treebuilder->context.mode = IN_CAPTION; } else if (type == COLGROUP || type == COL) { hubbub_error e; hubbub_tag tag = token->data.tag; if (type == COL) { /* Insert colgroup and reprocess */ tag.name.ptr = (const uint8_t *) "colgroup"; tag.name.len = SLEN("colgroup"); tag.n_attributes = 0; tag.attributes = NULL; err = HUBBUB_REPROCESS; } clear_stack_table_context(treebuilder); e = insert_element(treebuilder, &tag, true); if (e != HUBBUB_OK) return e; treebuilder->context.mode = IN_COLUMN_GROUP; } else if (type == TBODY || type == TFOOT || type == THEAD || type == TD || type == TH || type == TR) { hubbub_error e; hubbub_tag tag = token->data.tag; if (type == TD || type == TH || type == TR) { /* Insert tbody and reprocess */ tag.name.ptr = (const uint8_t *) "tbody"; tag.name.len = SLEN("tbody"); tag.n_attributes = 0; tag.attributes = NULL; err = HUBBUB_REPROCESS; } clear_stack_table_context(treebuilder); e = insert_element(treebuilder, &tag, true); if (e != HUBBUB_OK) return e; treebuilder->context.mode = IN_TABLE_BODY; } else if (type == TABLE) { /** \todo parse error */ /* This should match "</table>" handling */ element_stack_pop_until(treebuilder, TABLE); reset_insertion_mode(treebuilder); err = HUBBUB_REPROCESS; } else if (!tainted && (type == STYLE || type == SCRIPT)) { err = handle_in_head(treebuilder, token); } else if (!tainted && type == INPUT) { err = process_input_in_table(treebuilder, token); handled = (err == HUBBUB_OK); } else { handled = false; } } break; case HUBBUB_TOKEN_END_TAG: { element_type type = element_type_from_name(treebuilder, &token->data.tag.name); if (type == TABLE) { /** \todo fragment case */ element_stack_pop_until(treebuilder, TABLE); reset_insertion_mode(treebuilder); } else if (type == BODY || type == CAPTION || type == COL || type == COLGROUP || type == HTML || type == TBODY || type == TD || type == TFOOT || type == TH || type == THEAD || type == TR) { /** \todo parse error */ } else { handled = false; } } break; case HUBBUB_TOKEN_EOF: break; } if (!handled) { treebuilder->context.in_table_foster = true; /** \todo parse error */ err = handle_in_body(treebuilder, token); treebuilder->context.in_table_foster = false; } return err; }
/** * Handle token in "in head" insertion mode * * \param treebuilder The treebuilder instance * \param token The token to handle * \return True to reprocess token, false otherwise */ hubbub_error handle_in_head(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; bool handled = false; switch (token->type) { case HUBBUB_TOKEN_CHARACTER: err = process_characters_expect_whitespace(treebuilder, token, true); break; case HUBBUB_TOKEN_COMMENT: err = 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); if (type == HTML) { /* Process as if "in body" */ err = handle_in_body(treebuilder, token); } else if (type == BASE || type == COMMAND || type == LINK) { err = insert_element(treebuilder, &token->data.tag, false); /** \todo ack sc flag */ } else if (type == META) { err = process_meta_in_head(treebuilder, token); } else if (type == TITLE) { err = parse_generic_rcdata(treebuilder, token, true); } else if (type == NOFRAMES || type == STYLE) { err = parse_generic_rcdata(treebuilder, token, false); } else if (type == NOSCRIPT) { if (treebuilder->context.enable_scripting) { err = parse_generic_rcdata(treebuilder, token, false); } else { err = insert_element(treebuilder, &token->data.tag, true); if (err != HUBBUB_OK) return err; treebuilder->context.mode = IN_HEAD_NOSCRIPT; } } else if (type == SCRIPT) { /** \todo need to ensure that the client callback * sets the parser-inserted/already-executed script * flags. */ err = parse_generic_rcdata(treebuilder, token, false); } else if (type == HEAD) { /** \todo parse error */ } else { err = HUBBUB_REPROCESS; } } break; case HUBBUB_TOKEN_END_TAG: { element_type type = element_type_from_name(treebuilder, &token->data.tag.name); if (type == HEAD) { handled = true; } else if (type == HTML || type == BODY || type == BR) { err = HUBBUB_REPROCESS; } /** \todo parse error */ } break; case HUBBUB_TOKEN_EOF: err = HUBBUB_REPROCESS; break; } if (handled || err == HUBBUB_REPROCESS) { hubbub_ns ns; element_type otype; void *node; element_stack_pop(treebuilder, &ns, &otype, &node); treebuilder->context.mode = AFTER_HEAD; } return err; }
/** * Handle token in initial insertion mode * * \param treebuilder The treebuilder instance * \param token The token to handle * \return True to reprocess token, false otherwise */ hubbub_error handle_initial(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; switch (token->type) { case HUBBUB_TOKEN_CHARACTER: err = process_characters_expect_whitespace(treebuilder, token, false); if (err == HUBBUB_REPROCESS) { /** \todo parse error */ treebuilder->tree_handler->set_quirks_mode( treebuilder->tree_handler->ctx, HUBBUB_QUIRKS_MODE_FULL); treebuilder->context.mode = BEFORE_HTML; } break; case HUBBUB_TOKEN_COMMENT: err = process_comment_append(treebuilder, token, treebuilder->context.document); break; case HUBBUB_TOKEN_DOCTYPE: { void *doctype, *appended; const hubbub_doctype *cdoc; /** \todo parse error */ err = treebuilder->tree_handler->create_doctype( treebuilder->tree_handler->ctx, &token->data.doctype, &doctype); if (err != HUBBUB_OK) return err; /* Append to Document node */ err = treebuilder->tree_handler->append_child( treebuilder->tree_handler->ctx, treebuilder->context.document, doctype, &appended); treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, doctype); if (err != HUBBUB_OK) return err; treebuilder->tree_handler->unref_node( treebuilder->tree_handler->ctx, appended); cdoc = &token->data.doctype; /* Work out whether we need quirks mode or not */ if (cdoc->force_quirks == true || lookup_full_quirks(treebuilder, cdoc)) { treebuilder->tree_handler->set_quirks_mode( treebuilder->tree_handler->ctx, HUBBUB_QUIRKS_MODE_FULL); } else if (lookup_limited_quirks(treebuilder, cdoc)) { treebuilder->tree_handler->set_quirks_mode( treebuilder->tree_handler->ctx, HUBBUB_QUIRKS_MODE_LIMITED); } treebuilder->context.mode = BEFORE_HTML; } break; case HUBBUB_TOKEN_START_TAG: case HUBBUB_TOKEN_END_TAG: case HUBBUB_TOKEN_EOF: /** \todo parse error */ treebuilder->tree_handler->set_quirks_mode( treebuilder->tree_handler->ctx, HUBBUB_QUIRKS_MODE_FULL); err = HUBBUB_REPROCESS; break; } if (err == HUBBUB_REPROCESS) { treebuilder->context.mode = BEFORE_HTML; } return err; }
/** * Handle tokens in "in column group" insertion mode * * \param treebuilder The treebuilder instance * \param token The token to process * \return True to reprocess the token, false otherwise */ hubbub_error handle_in_column_group(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; bool handled = false; switch (token->type) { case HUBBUB_TOKEN_CHARACTER: err = process_characters_expect_whitespace(treebuilder, token, true); break; case HUBBUB_TOKEN_COMMENT: err = 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); if (type == HTML) { /* Process as if "in body" */ err = handle_in_body(treebuilder, token); } else if (type == COL) { err = insert_element(treebuilder, &token->data.tag, false); /** \todo ack sc flag */ } else { err = HUBBUB_REPROCESS; } } break; case HUBBUB_TOKEN_END_TAG: { element_type type = element_type_from_name(treebuilder, &token->data.tag.name); if (type == COLGROUP) { /** \todo fragment case */ handled = true; } else if (type == COL) { /** \todo parse error */ } else { err = HUBBUB_REPROCESS; } } break; case HUBBUB_TOKEN_EOF: /** \todo fragment case */ err = HUBBUB_REPROCESS; break; } if (handled || err == HUBBUB_REPROCESS) { hubbub_ns ns; element_type otype; void *node; /* Pop the current node (which will be a colgroup) */ element_stack_pop(treebuilder, &ns, &otype, &node); treebuilder->context.mode = IN_TABLE; } return err; }