Hubbub
in_body.c
Go to the documentation of this file.
1 /*
2  * This file is part of Hubbub.
3  * Licensed under the MIT License,
4  * http://www.opensource.org/licenses/mit-license.php
5  * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
6  */
7 
8 #include <assert.h>
9 #include <string.h>
10 
11 #include "treebuilder/modes.h"
12 #include "treebuilder/internal.h"
14 #include "utils/utils.h"
15 
16 #undef DEBUG_IN_BODY
17 
21 typedef struct bookmark {
24 } bookmark;
25 
27  const hubbub_token *token);
29  const hubbub_token *token);
31  const hubbub_token *token);
32 
34  const hubbub_token *token);
36  const hubbub_token *token);
38  const hubbub_token *token);
40  const hubbub_token *token);
42  const hubbub_token *token);
44  const hubbub_token *token);
46  const hubbub_token *token, element_type type);
48  const hubbub_token *token);
50  const hubbub_token *token);
52  hubbub_treebuilder *treebuilder,
53  const hubbub_token *token, element_type type);
55  const hubbub_token *token);
57  const hubbub_token *token);
59  hubbub_treebuilder *treebuilder, const hubbub_token *token,
62  const hubbub_token *token);
64  const hubbub_token *token);
66  const hubbub_token *token);
68  const hubbub_token *token);
70  const hubbub_token *token);
72  const hubbub_token *token);
74  const hubbub_token *token);
75 
86  hubbub_treebuilder *treebuilder,
89  hubbub_treebuilder *treebuilder, element_type type);
93 
95  hubbub_treebuilder *treebuilder, element_type type,
96  formatting_list_entry **element);
98  hubbub_treebuilder *treebuilder, element_type type);
100  formatting_list_entry *formatting_element,
101  uint32_t *furthest_block);
103  void *node, void *new_parent, void **reparented);
105  hubbub_treebuilder *treebuilder,
106  uint32_t formatting_element, uint32_t *furthest_block,
107  bookmark *bookmark, uint32_t *last_node);
109  hubbub_treebuilder *treebuilder,
110  uint32_t index, uint32_t limit);
112  hubbub_treebuilder *treebuilder,
113  formatting_list_entry *element);
114 
115 
124  const hubbub_token *token)
125 {
126  hubbub_error err = HUBBUB_OK;
127  uint32_t i;
128 
129 #if !defined(NDEBUG) && defined(DEBUG_IN_BODY)
130  fprintf(stdout, "Processing token %d\n", token->type);
131  element_stack_dump(treebuilder, stdout);
132  formatting_list_dump(treebuilder, stdout);
133 #endif
134 
135  if (treebuilder->context.strip_leading_lr &&
136  token->type != HUBBUB_TOKEN_CHARACTER) {
137  /* Reset the LR stripping flag */
138  treebuilder->context.strip_leading_lr = false;
139  }
140 
141  switch (token->type) {
143  err = process_character(treebuilder, token);
144  break;
146  err = process_comment_append(treebuilder, token,
147  treebuilder->context.element_stack[
148  treebuilder->context.current_node].node);
149  break;
152  break;
154  err = process_start_tag(treebuilder, token);
155  break;
157  err = process_end_tag(treebuilder, token);
158  break;
159  case HUBBUB_TOKEN_EOF:
160  for (i = treebuilder->context.current_node;
161  i > 0; i--) {
162  element_type type =
163  treebuilder->context.element_stack[i].type;
164 
165  if (!(type == DD || type == DT || type == LI ||
166  type == P || type == TBODY ||
167  type == TD || type == TFOOT ||
168  type == TH || type == THEAD ||
169  type == TR || type == BODY)) {
171  break;
172  }
173  }
174  break;
175  }
176 
177 #if !defined(NDEBUG) && defined(DEBUG_IN_BODY)
178  fprintf(stdout, "Processed\n");
179  element_stack_dump(treebuilder, stdout);
180  formatting_list_dump(treebuilder, stdout);
181 #endif
182 
183  return err;
184 }
185 
193  const hubbub_token *token)
194 {
195  hubbub_error err = HUBBUB_OK;
196  hubbub_string dummy = token->data.character;
197  bool lr_flag = treebuilder->context.strip_leading_lr;
198  const uint8_t *p;
199 
200  err = reconstruct_active_formatting_list(treebuilder);
201  if (err != HUBBUB_OK)
202  return err;
203 
204  if (treebuilder->context.strip_leading_lr) {
205  const uint8_t *str = dummy.ptr;
206 
207  if (*str == '\n') {
208  dummy.ptr++;
209  dummy.len--;
210  }
211 
212  treebuilder->context.strip_leading_lr = false;
213  }
214 
215  if (dummy.len) {
216  err = append_text(treebuilder, &dummy);
217  if (err != HUBBUB_OK) {
218  /* Restore LR stripping flag */
219  treebuilder->context.strip_leading_lr = lr_flag;
220 
221  return err;
222  }
223  }
224 
225  if (treebuilder->context.frameset_ok) {
226  for (p = dummy.ptr; p < dummy.ptr + dummy.len; p++) {
227  if (*p != 0x0009 && *p != 0x000a &&
228  *p != 0x000c && *p != 0x0020) {
229  treebuilder->context.frameset_ok = false;
230  break;
231  }
232  }
233  }
234 
235  return HUBBUB_OK;
236 }
237 
248  const hubbub_token *token)
249 {
250  hubbub_error err = HUBBUB_OK;
252  &token->data.tag.name);
253 
254  if (type == HTML) {
255  err = process_html_in_body(treebuilder, token);
256  } else if (type == BASE || type == COMMAND || type == LINK ||
257  type == META || type == NOFRAMES || type == SCRIPT ||
258  type == STYLE || type == TITLE) {
259  /* Process as "in head" */
260  err = handle_in_head(treebuilder, token);
261  } else if (type == BODY) {
262  err = process_body_in_body(treebuilder, token);
263  } else if (type == FRAMESET) {
264  err = process_frameset_in_body(treebuilder, token);
265  } else if (type == ADDRESS || type == ARTICLE || type == ASIDE ||
266  type == BLOCKQUOTE || type == CENTER ||
267  type == DATAGRID || type == DETAILS ||
268  type == DIALOG || type == DIR ||
269  type == DIV || type == DL || type == FIELDSET ||
270  type == FIGURE || type == FOOTER ||
271  type == HEADER || type == MENU || type == NAV ||
272  type == OL || type == P || type == SECTION ||
273  type == UL) {
274  err = process_container_in_body(treebuilder, token);
275  } else if (type == H1 || type == H2 || type == H3 ||
276  type == H4 || type == H5 || type == H6) {
277  err = process_hN_in_body(treebuilder, token);
278  } else if (type == PRE || type == LISTING) {
279  err = process_container_in_body(treebuilder, token);
280 
281  if (err == HUBBUB_OK) {
282  treebuilder->context.strip_leading_lr = true;
283  treebuilder->context.frameset_ok = false;
284  }
285  } else if (type == FORM) {
286  err = process_form_in_body(treebuilder, token);
287  } else if (type == DD || type == DT || type == LI) {
288  err = process_dd_dt_li_in_body(treebuilder, token, type);
289  } else if (type == PLAINTEXT) {
290  err = process_plaintext_in_body(treebuilder, token);
291  } else if (type == A) {
292  err = process_a_in_body(treebuilder, token);
293  } else if (type == B || type == BIG || type == CODE || type == EM ||
294  type == FONT || type == I || type == S ||
295  type == SMALL || type == STRIKE ||
296  type == STRONG || type == TT || type == U) {
297  err = process_presentational_in_body(treebuilder,
298  token, type);
299  } else if (type == NOBR) {
300  err = process_nobr_in_body(treebuilder, token);
301  } else if (type == BUTTON) {
302  err = process_button_in_body(treebuilder, token);
303  } else if (type == APPLET || type == MARQUEE ||
304  type == OBJECT) {
305  err = process_applet_marquee_object_in_body(treebuilder,
306  token, type);
307  } else if (type == XMP) {
308  err = reconstruct_active_formatting_list(treebuilder);
309  if (err != HUBBUB_OK)
310  return err;
311 
312  treebuilder->context.frameset_ok = false;
313 
314  err = parse_generic_rcdata(treebuilder, token, false);
315  } else if (type == TABLE) {
316  err = process_container_in_body(treebuilder, token);
317  if (err == HUBBUB_OK) {
318  treebuilder->context.frameset_ok = false;
319 
320  treebuilder->context.element_stack[
321  current_table(treebuilder)].tainted = false;
322  treebuilder->context.mode = IN_TABLE;
323  }
324  } else if (type == AREA || type == BASEFONT ||
325  type == BGSOUND || type == BR ||
326  type == EMBED || type == IMG || type == INPUT ||
327  type == PARAM || type == SPACER || type == WBR) {
328  err = reconstruct_active_formatting_list(treebuilder);
329  if (err != HUBBUB_OK)
330  return err;
331 
332  err = insert_element(treebuilder, &token->data.tag, false);
333  if (err == HUBBUB_OK)
334  treebuilder->context.frameset_ok = false;
335  } else if (type == HR) {
336  err = process_hr_in_body(treebuilder, token);
337  } else if (type == IMAGE) {
338  err = process_image_in_body(treebuilder, token);
339  } else if (type == ISINDEX) {
340  err = process_isindex_in_body(treebuilder, token);
341  } else if (type == TEXTAREA) {
342  err = process_textarea_in_body(treebuilder, token);
343  } else if (type == IFRAME || type == NOEMBED ||
344  type == NOFRAMES ||
345  (treebuilder->context.enable_scripting &&
346  type == NOSCRIPT)) {
347  if (type == IFRAME)
348  treebuilder->context.frameset_ok = false;
349  err = parse_generic_rcdata(treebuilder, token, false);
350  } else if (type == SELECT) {
351  err = process_select_in_body(treebuilder, token);
352  if (err != HUBBUB_OK)
353  return err;
354 
355  if (treebuilder->context.mode == IN_BODY) {
356  treebuilder->context.mode = IN_SELECT;
357  } else if (treebuilder->context.mode == IN_TABLE ||
358  treebuilder->context.mode == IN_CAPTION ||
359  treebuilder->context.mode == IN_COLUMN_GROUP ||
360  treebuilder->context.mode == IN_TABLE_BODY ||
361  treebuilder->context.mode == IN_ROW ||
362  treebuilder->context.mode == IN_CELL) {
363  treebuilder->context.mode = IN_SELECT_IN_TABLE;
364  }
365  } else if (type == OPTGROUP || type == OPTION) {
366  err = process_opt_in_body(treebuilder, token);
367  } else if (type == RP || type == RT) {
369  } else if (type == MATH || type == SVG) {
370  hubbub_tag tag = token->data.tag;
371 
372  err = reconstruct_active_formatting_list(treebuilder);
373  if (err != HUBBUB_OK)
374  return err;
375 
376  adjust_foreign_attributes(treebuilder, &tag);
377 
378  if (type == SVG) {
379  adjust_svg_attributes(treebuilder, &tag);
380  tag.ns = HUBBUB_NS_SVG;
381  } else {
382  adjust_mathml_attributes(treebuilder, &tag);
383  tag.ns = HUBBUB_NS_MATHML;
384  }
385 
386  if (token->data.tag.self_closing) {
387  err = insert_element(treebuilder, &tag, false);
389  } else {
390  err = insert_element(treebuilder, &tag, true);
391  if (err == HUBBUB_OK) {
392  treebuilder->context.second_mode =
393  treebuilder->context.mode;
394  treebuilder->context.mode = IN_FOREIGN_CONTENT;
395  }
396  }
397  } else if (type == CAPTION || type == COL || type == COLGROUP ||
398  type == FRAME || type == HEAD || type == TBODY ||
399  type == TD || type == TFOOT || type == TH ||
400  type == THEAD || type == TR) {
402  } else {
403  err = process_phrasing_in_body(treebuilder, token);
404  }
405 
406  return err;
407 }
408 
417  const hubbub_token *token)
418 {
419  hubbub_error err = HUBBUB_OK;
421  &token->data.tag.name);
422 
423  if (type == BODY) {
424  err = process_0body_in_body(treebuilder);
425  /* Never reprocess */
426  if (err == HUBBUB_REPROCESS)
427  err = HUBBUB_OK;
428  } else if (type == HTML) {
429  /* Act as if </body> has been seen then, if
430  * that wasn't ignored, reprocess this token */
431  err = process_0body_in_body(treebuilder);
432  } else if (type == ADDRESS || type == ARTICLE || type == ASIDE ||
433  type == BLOCKQUOTE || type == CENTER || type == DIR ||
434  type == DATAGRID || type == DIV || type == DL ||
435  type == FIELDSET || type == FOOTER || type == HEADER ||
436  type == LISTING || type == MENU || type == NAV ||
437  type == OL || type == PRE || type == SECTION ||
438  type == UL) {
439  err = process_0container_in_body(treebuilder, type);
440  } else if (type == FORM) {
441  err = process_0form_in_body(treebuilder);
442  } else if (type == P) {
443  err = process_0p_in_body(treebuilder);
444  } else if (type == DD || type == DT || type == LI) {
445  err = process_0dd_dt_li_in_body(treebuilder, type);
446  } else if (type == H1 || type == H2 || type == H3 ||
447  type == H4 || type == H5 || type == H6) {
448  err = process_0h_in_body(treebuilder, type);
449  } else if (type == A || type == B || type == BIG || type == CODE ||
450  type == EM || type == FONT || type == I ||
451  type == NOBR || type == S || type == SMALL ||
452  type == STRIKE || type == STRONG ||
453  type == TT || type == U) {
454  err = process_0presentational_in_body(treebuilder, type);
455  } else if (type == APPLET || type == BUTTON ||
456  type == MARQUEE || type == OBJECT) {
458  treebuilder, type);
459  } else if (type == BR) {
460  err = process_0br_in_body(treebuilder);
461  } else if (type == AREA || type == BASEFONT ||
462  type == BGSOUND || type == EMBED ||
463  type == HR || type == IFRAME ||
464  type == IMAGE || type == IMG ||
465  type == INPUT || type == ISINDEX ||
466  type == NOEMBED || type == NOFRAMES ||
467  type == PARAM || type == SELECT ||
468  type == SPACER || type == TABLE ||
469  type == TEXTAREA || type == WBR ||
470  (treebuilder->context.enable_scripting &&
471  type == NOSCRIPT)) {
473  } else {
474  err = process_0generic_in_body(treebuilder, type);
475  }
476 
477  return err;
478 }
479 
487  const hubbub_token *token)
488 {
491  return treebuilder->tree_handler->add_attributes(
492  treebuilder->tree_handler->ctx,
493  treebuilder->context.element_stack[0].node,
494  token->data.tag.attributes,
495  token->data.tag.n_attributes);
496 }
497 
505  const hubbub_token *token)
506 {
509  if (treebuilder->context.current_node < 1 ||
510  treebuilder->context.element_stack[1].type != BODY)
511  return HUBBUB_OK;
512 
513  return treebuilder->tree_handler->add_attributes(
514  treebuilder->tree_handler->ctx,
515  treebuilder->context.element_stack[1].node,
516  token->data.tag.attributes,
517  token->data.tag.n_attributes);
518 }
519 
527  const hubbub_token *token)
528 {
529  hubbub_error err = HUBBUB_OK;
530 
533  if (treebuilder->context.current_node < 1 ||
534  treebuilder->context.element_stack[1].type != BODY)
535  return HUBBUB_OK;
536 
537  if (treebuilder->context.frameset_ok == false)
538  return HUBBUB_OK;
539 
540  err = remove_node_from_dom(treebuilder,
541  treebuilder->context.element_stack[1].node);
542  if (err != HUBBUB_OK)
543  return err;
544 
545  err = element_stack_pop_until(treebuilder, BODY);
546  assert(err == HUBBUB_OK);
547 
548  err = insert_element(treebuilder, &token->data.tag, true);
549  if (err == HUBBUB_OK)
550  treebuilder->context.mode = IN_FRAMESET;
551 
552  return err;
553 }
554 
562  const hubbub_token *token)
563 {
564  hubbub_error err;
565 
566  if (element_in_scope(treebuilder, P, false)) {
567  err = process_0p_in_body(treebuilder);
568  if (err != HUBBUB_OK)
569  return err;
570  }
571 
572  return insert_element(treebuilder, &token->data.tag, true);
573 }
574 
582  const hubbub_token *token)
583 {
584  hubbub_error err;
586 
587  if (element_in_scope(treebuilder, P, false)) {
588  err = process_0p_in_body(treebuilder);
589  if (err != HUBBUB_OK)
590  return err;
591  }
592 
593  type = treebuilder->context.element_stack[
594  treebuilder->context.current_node].type;
595 
596  if (type == H1 || type == H2 || type == H3 || type == H4 ||
597  type == H5 || type == H6) {
598  hubbub_ns ns;
599  element_type otype;
600  void *node;
601 
604  err = element_stack_pop(treebuilder, &ns, &otype, &node);
605  assert(err == HUBBUB_OK);
606 
607  treebuilder->tree_handler->unref_node(
608  treebuilder->tree_handler->ctx,
609  node);
610  }
611 
612  return insert_element(treebuilder, &token->data.tag, true);
613 }
614 
622  const hubbub_token *token)
623 {
624  hubbub_error err;
625 
626  if (treebuilder->context.form_element != NULL) {
628  } else {
629  if (element_in_scope(treebuilder, P, false)) {
630  err = process_0p_in_body(treebuilder);
631  if (err != HUBBUB_OK)
632  return err;
633  }
634 
635  err = insert_element(treebuilder, &token->data.tag, true);
636  if (err != HUBBUB_OK)
637  return err;
638 
639  /* Claim a reference on the node and
640  * use it as the current form element */
641  treebuilder->tree_handler->ref_node(
642  treebuilder->tree_handler->ctx,
643  treebuilder->context.element_stack[
644  treebuilder->context.current_node].node);
645 
646  treebuilder->context.form_element =
647  treebuilder->context.element_stack[
648  treebuilder->context.current_node].node;
649  }
650 
651  return HUBBUB_OK;
652 }
653 
662  const hubbub_token *token, element_type type)
663 {
664  hubbub_error err;
665  element_context *stack = treebuilder->context.element_stack;
666  uint32_t node;
667 
668  treebuilder->context.frameset_ok = false;
669 
670  if (element_in_scope(treebuilder, P, false)) {
671  err = process_0p_in_body(treebuilder);
672  if (err != HUBBUB_OK)
673  return err;
674  }
675 
676  /* Find last LI/(DD,DT) on stack, if any */
677  for (node = treebuilder->context.current_node; node > 0; node--) {
678  element_type ntype = stack[node].type;
679 
680  if (type == LI && ntype == LI)
681  break;
682 
683  if (((type == DD || type == DT) &&
684  (ntype == DD || ntype == DT)))
685  break;
686 
687  if (!is_formatting_element(ntype) &&
688  !is_phrasing_element(ntype) &&
689  ntype != ADDRESS &&
690  ntype != DIV)
691  break;
692  }
693 
694  /* If we found one, then pop all nodes up to and including it */
695  if (stack[node].type == LI || stack[node].type == DD ||
696  stack[node].type == DT) {
697  /* Check that we're only popping one node
698  * and emit a parse error if not */
699  if (treebuilder->context.current_node > node) {
701  }
702 
703  do {
704  hubbub_ns ns;
705  element_type otype;
706  void *node;
707 
708  err = element_stack_pop(treebuilder, &ns,
709  &otype, &node);
710  assert(err == HUBBUB_OK);
711 
712  treebuilder->tree_handler->unref_node(
713  treebuilder->tree_handler->ctx,
714  node);
715  } while (treebuilder->context.current_node >= node);
716  }
717 
718  return insert_element(treebuilder, &token->data.tag, true);
719 }
720 
728  const hubbub_token *token)
729 {
730  hubbub_error err;
732 
733  if (element_in_scope(treebuilder, P, false)) {
734  err = process_0p_in_body(treebuilder);
735  if (err != HUBBUB_OK)
736  return err;
737  }
738 
739  err = insert_element(treebuilder, &token->data.tag, true);
740  if (err != HUBBUB_OK)
741  return err;
742 
744 
745  err = hubbub_tokeniser_setopt(treebuilder->tokeniser,
747  &params);
748  assert(err == HUBBUB_OK);
749 
750  return HUBBUB_OK;
751 }
752 
760  const hubbub_token *token)
761 {
762  hubbub_error err;
763  formatting_list_entry *entry =
764  aa_find_formatting_element(treebuilder, A);
765 
766  if (entry != NULL) {
767  uint32_t index = entry->stack_index;
768  void *node = entry->details.node;
769  formatting_list_entry *entry2;
770 
773  /* Act as if </a> were seen */
774  err = process_0presentational_in_body(treebuilder, A);
775  if (err != HUBBUB_OK)
776  return err;
777 
778  entry2 = aa_find_formatting_element(treebuilder, A);
779 
780  /* Remove from formatting list, if it's still there */
781  if (entry2 == entry && entry2->details.node == node) {
782  hubbub_ns ons;
783  element_type otype;
784  void *onode;
785  uint32_t oindex;
786 
787  err = formatting_list_remove(treebuilder, entry,
788  &ons, &otype, &onode, &oindex);
789  assert(err == HUBBUB_OK);
790 
791  treebuilder->tree_handler->unref_node(
792  treebuilder->tree_handler->ctx, onode);
793 
794  }
795 
796  /* Remove from the stack of open elements, if still there */
797  if (index <= treebuilder->context.current_node &&
798  treebuilder->context.element_stack[index].node
799  == node) {
800  hubbub_ns ns;
801  element_type otype;
802  void *onode;
803 
804  err = element_stack_remove(treebuilder, index, &ns,
805  &otype, &onode);
806  assert(err == HUBBUB_OK);
807 
808  treebuilder->tree_handler->unref_node(
809  treebuilder->tree_handler->ctx, onode);
810  }
811  }
812 
813  err = reconstruct_active_formatting_list(treebuilder);
814  if (err != HUBBUB_OK)
815  return err;
816 
817  err = insert_element(treebuilder, &token->data.tag, true);
818  if (err != HUBBUB_OK)
819  return err;
820 
821  treebuilder->tree_handler->ref_node(treebuilder->tree_handler->ctx,
822  treebuilder->context.element_stack[
823  treebuilder->context.current_node].node);
824 
825  err = formatting_list_append(treebuilder, token->data.tag.ns, A,
826  treebuilder->context.element_stack[
827  treebuilder->context.current_node].node,
828  treebuilder->context.current_node);
829  if (err != HUBBUB_OK) {
830  hubbub_ns ns;
832  void *node;
833 
834  remove_node_from_dom(treebuilder,
835  treebuilder->context.element_stack[
836  treebuilder->context.current_node].node);
837 
838  element_stack_pop(treebuilder, &ns, &type, &node);
839 
840  /* Unref twice (once for stack, once for formatting list) */
841  treebuilder->tree_handler->unref_node(
842  treebuilder->tree_handler->ctx, node);
843 
844  treebuilder->tree_handler->unref_node(
845  treebuilder->tree_handler->ctx, node);
846 
847  return err;
848  }
849 
850  return HUBBUB_OK;
851 }
852 
862  const hubbub_token *token, element_type type)
863 {
864  hubbub_error err;
865 
866  err = reconstruct_active_formatting_list(treebuilder);
867  if (err != HUBBUB_OK)
868  return err;
869 
870  err = insert_element(treebuilder, &token->data.tag, true);
871  if (err != HUBBUB_OK)
872  return err;
873 
874  treebuilder->tree_handler->ref_node(treebuilder->tree_handler->ctx,
875  treebuilder->context.element_stack[
876  treebuilder->context.current_node].node);
877 
878  err = formatting_list_append(treebuilder, token->data.tag.ns, type,
879  treebuilder->context.element_stack[
880  treebuilder->context.current_node].node,
881  treebuilder->context.current_node);
882  if (err != HUBBUB_OK) {
883  hubbub_ns ns;
885  void *node;
886 
887  remove_node_from_dom(treebuilder,
888  treebuilder->context.element_stack[
889  treebuilder->context.current_node].node);
890 
891  element_stack_pop(treebuilder, &ns, &type, &node);
892 
893  /* Unref twice (once for stack, once for formatting list) */
894  treebuilder->tree_handler->unref_node(
895  treebuilder->tree_handler->ctx, node);
896 
897  treebuilder->tree_handler->unref_node(
898  treebuilder->tree_handler->ctx, node);
899 
900  return err;
901  }
902 
903  return HUBBUB_OK;
904 }
905 
913  const hubbub_token *token)
914 {
915  hubbub_error err;
916 
917  err = reconstruct_active_formatting_list(treebuilder);
918  if (err != HUBBUB_OK)
919  return err;
920 
921  if (element_in_scope(treebuilder, NOBR, false)) {
924  /* Act as if </nobr> were seen */
925  err = process_0presentational_in_body(treebuilder, NOBR);
926  if (err != HUBBUB_OK)
927  return err;
928 
929  /* Yes, again */
930  err = reconstruct_active_formatting_list(treebuilder);
931  if (err != HUBBUB_OK)
932  return err;
933  }
934 
935  err = insert_element(treebuilder, &token->data.tag, true);
936  if (err != HUBBUB_OK)
937  return err;
938 
939  treebuilder->tree_handler->ref_node(
940  treebuilder->tree_handler->ctx,
941  treebuilder->context.element_stack[
942  treebuilder->context.current_node].node);
943 
944  err = formatting_list_append(treebuilder, token->data.tag.ns, NOBR,
945  treebuilder->context.element_stack[
946  treebuilder->context.current_node].node,
947  treebuilder->context.current_node);
948  if (err != HUBBUB_OK) {
949  hubbub_ns ns;
951  void *node;
952 
953  remove_node_from_dom(treebuilder,
954  treebuilder->context.element_stack[
955  treebuilder->context.current_node].node);
956 
957  element_stack_pop(treebuilder, &ns, &type, &node);
958 
959  /* Unref twice (once for stack, once for formatting list) */
960  treebuilder->tree_handler->unref_node(
961  treebuilder->tree_handler->ctx, node);
962 
963  treebuilder->tree_handler->unref_node(
964  treebuilder->tree_handler->ctx, node);
965 
966  return err;
967  }
968 
969  return HUBBUB_OK;
970 }
971 
979  const hubbub_token *token)
980 {
981  hubbub_error err;
982 
983  if (element_in_scope(treebuilder, BUTTON, false)) {
986  /* Act as if </button> has been seen */
988  treebuilder, BUTTON);
989  assert(err == HUBBUB_OK);
990  }
991 
992  err = reconstruct_active_formatting_list(treebuilder);
993  if (err != HUBBUB_OK)
994  return err;
995 
996  err = insert_element(treebuilder, &token->data.tag, true);
997  if (err != HUBBUB_OK)
998  return err;
999 
1000  treebuilder->tree_handler->ref_node(
1001  treebuilder->tree_handler->ctx,
1002  treebuilder->context.element_stack[
1003  treebuilder->context.current_node].node);
1004 
1005  err = formatting_list_append(treebuilder, token->data.tag.ns, BUTTON,
1006  treebuilder->context.element_stack[
1007  treebuilder->context.current_node].node,
1008  treebuilder->context.current_node);
1009  if (err != HUBBUB_OK) {
1010  hubbub_ns ns;
1012  void *node;
1013 
1014  remove_node_from_dom(treebuilder,
1015  treebuilder->context.element_stack[
1016  treebuilder->context.current_node].node);
1017 
1018  element_stack_pop(treebuilder, &ns, &type, &node);
1019 
1020  /* Unref twice (once for stack, once for formatting list) */
1021  treebuilder->tree_handler->unref_node(
1022  treebuilder->tree_handler->ctx, node);
1023 
1024  treebuilder->tree_handler->unref_node(
1025  treebuilder->tree_handler->ctx, node);
1026 
1027  return err;
1028  }
1029 
1030  treebuilder->context.frameset_ok = false;
1031 
1032  return HUBBUB_OK;
1033 }
1034 
1043  hubbub_treebuilder *treebuilder,
1044  const hubbub_token *token, element_type type)
1045 {
1046  hubbub_error err;
1047 
1048  err = reconstruct_active_formatting_list(treebuilder);
1049  if (err != HUBBUB_OK)
1050  return err;
1051 
1052  err = insert_element(treebuilder, &token->data.tag, true);
1053  if (err != HUBBUB_OK)
1054  return err;
1055 
1056  treebuilder->tree_handler->ref_node(
1057  treebuilder->tree_handler->ctx,
1058  treebuilder->context.element_stack[
1059  treebuilder->context.current_node].node);
1060 
1061  err = formatting_list_append(treebuilder, token->data.tag.ns, type,
1062  treebuilder->context.element_stack[
1063  treebuilder->context.current_node].node,
1064  treebuilder->context.current_node);
1065  if (err != HUBBUB_OK) {
1066  hubbub_ns ns;
1068  void *node;
1069 
1070  remove_node_from_dom(treebuilder,
1071  treebuilder->context.element_stack[
1072  treebuilder->context.current_node].node);
1073 
1074  element_stack_pop(treebuilder, &ns, &type, &node);
1075 
1076  /* Unref twice (once for stack, once for formatting list) */
1077  treebuilder->tree_handler->unref_node(
1078  treebuilder->tree_handler->ctx, node);
1079 
1080  treebuilder->tree_handler->unref_node(
1081  treebuilder->tree_handler->ctx, node);
1082 
1083  return err;
1084  }
1085 
1086  treebuilder->context.frameset_ok = false;
1087 
1088  return HUBBUB_OK;
1089 }
1090 
1098  const hubbub_token *token)
1099 {
1100  hubbub_error err;
1101 
1102  if (element_in_scope(treebuilder, P, false)) {
1103  err = process_0p_in_body(treebuilder);
1104  if (err != HUBBUB_OK)
1105  return err;
1106  }
1107 
1108  err = insert_element(treebuilder, &token->data.tag, false);
1109  if (err == HUBBUB_OK)
1110  treebuilder->context.frameset_ok = false;
1111 
1112  return err;
1113 }
1114 
1122  const hubbub_token *token)
1123 {
1124  hubbub_error err;
1125  hubbub_tag tag;
1126 
1127  tag.ns = HUBBUB_NS_HTML;
1128  tag.name.ptr = (const uint8_t *) "img";
1129  tag.name.len = SLEN("img");
1130 
1131  tag.n_attributes = token->data.tag.n_attributes;
1132  tag.attributes = token->data.tag.attributes;
1133 
1134  err = reconstruct_active_formatting_list(treebuilder);
1135  if (err != HUBBUB_OK)
1136  return err;
1137 
1138  return insert_element(treebuilder, &tag, false);
1139 }
1140 
1148  const hubbub_token *token)
1149 {
1150  hubbub_error err;
1151  hubbub_token dummy;
1152  hubbub_attribute *action = NULL;
1153  hubbub_attribute *prompt = NULL;
1154  hubbub_attribute *attrs = NULL;
1155  size_t n_attrs = 0;
1156 
1159  if (treebuilder->context.form_element != NULL)
1160  return HUBBUB_OK;
1161 
1162  /* First up, clone the token's attributes */
1163  if (token->data.tag.n_attributes > 0) {
1164  uint32_t i;
1165  attrs = malloc((token->data.tag.n_attributes + 1) *
1166  sizeof(hubbub_attribute));
1167  if (attrs == NULL)
1168  return HUBBUB_NOMEM;
1169 
1170  for (i = 0; i < token->data.tag.n_attributes; i++) {
1171  hubbub_attribute *attr = &token->data.tag.attributes[i];
1172  const uint8_t *name = attr->name.ptr;
1173 
1174  if (strncmp((const char *) name, "action",
1175  attr->name.len) == 0) {
1176  action = attr;
1177  } else if (strncmp((const char *) name, "prompt",
1178  attr->name.len) == 0) {
1179  prompt = attr;
1180  } else if (strncmp((const char *) name, "name",
1181  attr->name.len) == 0) {
1182  } else {
1183  attrs[n_attrs++] = *attr;
1184  }
1185  }
1186 
1187  attrs[n_attrs].ns = HUBBUB_NS_HTML;
1188  attrs[n_attrs].name.ptr = (const uint8_t *) "name";
1189  attrs[n_attrs].name.len = SLEN("name");
1190  attrs[n_attrs].value.ptr = (const uint8_t *) "isindex";
1191  attrs[n_attrs].value.len = SLEN("isindex");
1192  n_attrs++;
1193  }
1194 
1195  /* isindex algorithm */
1196 
1197  /* Set up dummy as a start tag token */
1198  dummy.type = HUBBUB_TOKEN_START_TAG;
1199  dummy.data.tag.ns = HUBBUB_NS_HTML;
1200 
1201  /* Act as if <form> were seen */
1202  dummy.data.tag.name.ptr = (const uint8_t *) "form";
1203  dummy.data.tag.name.len = SLEN("form");
1204 
1205  dummy.data.tag.n_attributes = action != NULL ? 1 : 0;
1206  dummy.data.tag.attributes = action;
1207 
1208  err = process_form_in_body(treebuilder, &dummy);
1209  if (err != HUBBUB_OK) {
1210  free(attrs);
1211  return err;
1212  }
1213 
1214  /* Act as if <hr> were seen */
1215  dummy.data.tag.name.ptr = (const uint8_t *) "hr";
1216  dummy.data.tag.name.len = SLEN("hr");
1217  dummy.data.tag.n_attributes = 0;
1218  dummy.data.tag.attributes = NULL;
1219 
1220  err = process_hr_in_body(treebuilder, &dummy);
1221  if (err != HUBBUB_OK) {
1222  free(attrs);
1223  return err;
1224  }
1225 
1226  /* Act as if <p> were seen */
1227  dummy.data.tag.name.ptr = (const uint8_t *) "p";
1228  dummy.data.tag.name.len = SLEN("p");
1229  dummy.data.tag.n_attributes = 0;
1230  dummy.data.tag.attributes = NULL;
1231 
1232  err = process_container_in_body(treebuilder, &dummy);
1233  if (err != HUBBUB_OK) {
1234  free(attrs);
1235  return err;
1236  }
1237 
1238  /* Act as if <label> were seen */
1239  dummy.data.tag.name.ptr = (const uint8_t *) "label";
1240  dummy.data.tag.name.len = SLEN("label");
1241  dummy.data.tag.n_attributes = 0;
1242  dummy.data.tag.attributes = NULL;
1243 
1244  err = process_phrasing_in_body(treebuilder, &dummy);
1245  if (err != HUBBUB_OK) {
1246  free(attrs);
1247  return err;
1248  }
1249 
1250  /* Act as if a stream of characters were seen */
1251  dummy.type = HUBBUB_TOKEN_CHARACTER;
1252  if (prompt != NULL) {
1253  dummy.data.character = prompt->value;
1254  } else {
1256 #define PROMPT "This is a searchable index. Insert your search keywords here: "
1257  dummy.data.character.ptr = (const uint8_t *) PROMPT;
1258  dummy.data.character.len = SLEN(PROMPT);
1259 #undef PROMPT
1260  }
1261 
1262  err = process_character(treebuilder, &dummy);
1263  if (err != HUBBUB_OK) {
1264  free(attrs);
1265  return err;
1266  }
1267 
1268  /* Act as if <input> was seen */
1269  dummy.type = HUBBUB_TOKEN_START_TAG;
1270  dummy.data.tag.ns = HUBBUB_NS_HTML;
1271  dummy.data.tag.name.ptr = (const uint8_t *) "input";
1272  dummy.data.tag.name.len = SLEN("input");
1273 
1274  dummy.data.tag.n_attributes = n_attrs;
1275  dummy.data.tag.attributes = attrs;
1276 
1277  err = reconstruct_active_formatting_list(treebuilder);
1278  if (err != HUBBUB_OK) {
1279  free(attrs);
1280  return err;
1281  }
1282 
1283  err = insert_element(treebuilder, &dummy.data.tag, false);
1284  if (err != HUBBUB_OK) {
1285  free(attrs);
1286  return err;
1287  }
1288 
1289  /* No longer need attrs */
1290  free(attrs);
1291 
1292  treebuilder->context.frameset_ok = false;
1293 
1294  /* Act as if </label> was seen */
1295  err = process_0generic_in_body(treebuilder, LABEL);
1296  assert(err == HUBBUB_OK);
1297 
1298  /* Act as if </p> was seen */
1299  err = process_0p_in_body(treebuilder);
1300  if (err != HUBBUB_OK)
1301  return err;
1302 
1303  /* Act as if <hr> was seen */
1304  dummy.data.tag.name.ptr = (const uint8_t *) "hr";
1305  dummy.data.tag.name.len = SLEN("hr");
1306  dummy.data.tag.n_attributes = 0;
1307  dummy.data.tag.attributes = NULL;
1308 
1309  err = process_hr_in_body(treebuilder, &dummy);
1310  if (err != HUBBUB_OK)
1311  return err;
1312 
1313  /* Act as if </form> was seen */
1314  return process_0container_in_body(treebuilder, FORM);
1315 }
1316 
1324  const hubbub_token *token)
1325 {
1326  treebuilder->context.strip_leading_lr = true;
1327  treebuilder->context.frameset_ok = false;
1328  return parse_generic_rcdata(treebuilder, token, true);
1329 }
1330 
1338  const hubbub_token *token)
1339 {
1340  hubbub_error err;
1341 
1342  err = reconstruct_active_formatting_list(treebuilder);
1343  if (err != HUBBUB_OK)
1344  return err;
1345 
1346  err = insert_element(treebuilder, &token->data.tag, true);
1347  if (err == HUBBUB_OK)
1348  treebuilder->context.frameset_ok = false;
1349 
1350  return err;
1351 }
1352 
1360  const hubbub_token *token)
1361 {
1362  hubbub_error err;
1363 
1364  if (element_in_scope(treebuilder, OPTION, false)) {
1365  err = process_0generic_in_body(treebuilder, OPTION);
1366  /* Cannot fail */
1367  assert(err == HUBBUB_OK);
1368  }
1369 
1370  err = reconstruct_active_formatting_list(treebuilder);
1371  if (err != HUBBUB_OK)
1372  return err;
1373 
1374  return insert_element(treebuilder, &token->data.tag, true);
1375 }
1376 
1384  const hubbub_token *token)
1385 {
1386  hubbub_error err;
1387 
1388  err = reconstruct_active_formatting_list(treebuilder);
1389  if (err != HUBBUB_OK)
1390  return err;
1391 
1392  return insert_element(treebuilder, &token->data.tag, true);
1393 }
1394 
1402 {
1403  hubbub_error err = HUBBUB_OK;
1404 
1405  if (!element_in_scope(treebuilder, BODY, false)) {
1407  } else {
1408  element_context *stack = treebuilder->context.element_stack;
1409  uint32_t node;
1410 
1411  for (node = treebuilder->context.current_node;
1412  node > 0; node--) {
1413  element_type ntype = stack[node].type;
1414 
1415  if (ntype != DD && ntype != DT && ntype != LI &&
1416  ntype != OPTGROUP && ntype != OPTION &&
1417  ntype != P && ntype != RP &&
1418  ntype != RT && ntype != TBODY &&
1419  ntype != TD && ntype != TFOOT &&
1420  ntype != TH && ntype != THEAD &&
1421  ntype != TR && ntype != BODY) {
1423  }
1424  }
1425 
1426  if (treebuilder->context.mode == IN_BODY)
1427  treebuilder->context.mode = AFTER_BODY;
1428 
1429  err = HUBBUB_REPROCESS;
1430  }
1431 
1432  return err;
1433 }
1434 
1443 {
1444  if (!element_in_scope(treebuilder, type, false)) {
1446  } else {
1447  uint32_t popped = 0;
1448  element_type otype;
1449 
1450  close_implied_end_tags(treebuilder, UNKNOWN);
1451 
1452  do {
1453  hubbub_ns ns;
1454  void *node;
1455 
1456  element_stack_pop(treebuilder, &ns, &otype, &node);
1457 
1458  treebuilder->tree_handler->unref_node(
1459  treebuilder->tree_handler->ctx,
1460  node);
1461 
1462  popped++;
1463  } while (otype != type);
1464 
1465  if (popped > 1) {
1467  }
1468  }
1469 
1470  return HUBBUB_OK;
1471 }
1472 
1479 {
1480  void *node = treebuilder->context.form_element;
1481  uint32_t idx = 0;
1482 
1483  if (treebuilder->context.form_element != NULL)
1484  treebuilder->tree_handler->unref_node(
1485  treebuilder->tree_handler->ctx,
1486  treebuilder->context.form_element);
1487  treebuilder->context.form_element = NULL;
1488 
1489  idx = element_in_scope(treebuilder, FORM, false);
1490 
1491  if (idx == 0 || node == NULL ||
1492  treebuilder->context.element_stack[idx].node != node) {
1494  } else {
1495  hubbub_ns ns;
1496  element_type otype;
1497  void *onode;
1498 
1499  close_implied_end_tags(treebuilder, UNKNOWN);
1500 
1501  if (treebuilder->context.element_stack[
1502  treebuilder->context.current_node].node !=
1503  node) {
1505  }
1506 
1507  element_stack_remove(treebuilder, idx,
1508  &ns, &otype, &onode);
1509 
1510  treebuilder->tree_handler->unref_node(
1511  treebuilder->tree_handler->ctx,
1512  onode);
1513  }
1514 
1515  return HUBBUB_OK;
1516 }
1517 
1518 
1525 {
1526  hubbub_error err = HUBBUB_OK;
1527  uint32_t popped = 0;
1528 
1529  if (treebuilder->context.element_stack[
1530  treebuilder->context.current_node].type != P) {
1532  }
1533 
1534  while (element_in_scope(treebuilder, P, false)) {
1535  hubbub_ns ns;
1537  void *node;
1538 
1539  err = element_stack_pop(treebuilder, &ns, &type, &node);
1540  assert(err == HUBBUB_OK);
1541 
1542  treebuilder->tree_handler->unref_node(
1543  treebuilder->tree_handler->ctx, node);
1544 
1545  popped++;
1546  }
1547 
1548  if (popped == 0) {
1549  hubbub_token dummy;
1550 
1551  dummy.type = HUBBUB_TOKEN_START_TAG;
1552  dummy.data.tag.ns = HUBBUB_NS_HTML;
1553  dummy.data.tag.name.ptr = (const uint8_t *) "p";
1554  dummy.data.tag.name.len = SLEN("p");
1555  dummy.data.tag.n_attributes = 0;
1556  dummy.data.tag.attributes = NULL;
1557 
1558  err = process_container_in_body(treebuilder, &dummy);
1559  if (err != HUBBUB_OK)
1560  return err;
1561 
1562  /* Reprocess the end tag. This is safe as we've just
1563  * inserted a <p> into the current scope */
1564  err = process_0p_in_body(treebuilder);
1565  /* Cannot fail */
1566  assert(err == HUBBUB_OK);
1567  }
1568 
1569  return err;
1570 }
1571 
1580 {
1581  if (!element_in_scope(treebuilder, type, false)) {
1583  } else {
1584  uint32_t popped = 0;
1585  element_type otype;
1586 
1587  close_implied_end_tags(treebuilder, type);
1588 
1589  do {
1590  hubbub_ns ns;
1591  void *node;
1592 
1593  element_stack_pop(treebuilder,
1594  &ns, &otype, &node);
1595 
1596  treebuilder->tree_handler->unref_node(
1597  treebuilder->tree_handler->ctx,
1598  node);
1599 
1600  popped++;
1601  } while (otype != type);
1602 
1603  if (popped > 1) {
1605  }
1606  }
1607 
1608  return HUBBUB_OK;
1609 }
1610 
1619 {
1620  UNUSED(type);
1621 
1623  if (element_in_scope(treebuilder, H1, false) ||
1624  element_in_scope(treebuilder, H2, false) ||
1625  element_in_scope(treebuilder, H3, false) ||
1626  element_in_scope(treebuilder, H4, false) ||
1627  element_in_scope(treebuilder, H5, false) ||
1628  element_in_scope(treebuilder, H6, false)) {
1629  uint32_t popped = 0;
1630  element_type otype;
1631 
1632  close_implied_end_tags(treebuilder, UNKNOWN);
1633 
1634  do {
1635  hubbub_ns ns;
1636  void *node;
1637 
1638  element_stack_pop(treebuilder, &ns, &otype, &node);
1639 
1640  treebuilder->tree_handler->unref_node(
1641  treebuilder->tree_handler->ctx,
1642  node);
1643 
1644  popped++;
1645  } while (otype != H1 && otype != H2 &&
1646  otype != H3 && otype != H4 &&
1647  otype != H5 && otype != H6);
1648 
1649  if (popped > 1) {
1651  }
1652  } else {
1654  }
1655 
1656  return HUBBUB_OK;
1657 }
1658 
1667 {
1668  hubbub_error err;
1669 
1670  /* Welcome to the adoption agency */
1671 
1672  while (true) {
1673  element_context *stack = treebuilder->context.element_stack;
1674 
1675  formatting_list_entry *entry;
1676  uint32_t formatting_element;
1677  uint32_t common_ancestor;
1678  uint32_t furthest_block;
1680  uint32_t last_node;
1681  void *reparented;
1682  void *fe_clone = NULL;
1683  void *clone_appended = NULL;
1684  hubbub_ns ons;
1685  element_type otype;
1686  void *onode;
1687  uint32_t oindex;
1688 
1689  /* 1 */
1690  err = aa_find_and_validate_formatting_element(treebuilder,
1691  type, &entry);
1692  assert(err == HUBBUB_OK || err == HUBBUB_REPROCESS);
1693  if (err == HUBBUB_OK)
1694  return err;
1695 
1696  assert(entry->details.type == type);
1697 
1698  /* Take a copy of the stack index for use
1699  * during stack manipulation */
1700  formatting_element = entry->stack_index;
1701 
1702  /* 2 & 3 */
1703  err = aa_find_furthest_block(treebuilder,
1704  entry, &furthest_block);
1705  assert(err == HUBBUB_OK || err == HUBBUB_REPROCESS);
1706  if (err == HUBBUB_OK)
1707  return err;
1708 
1709  /* 4 */
1710  common_ancestor = formatting_element - 1;
1711 
1712  /* 5 */
1713  bookmark.prev = entry->prev;
1714  bookmark.next = entry->next;
1715 
1716  /* 6 */
1718  treebuilder, formatting_element,
1719  &furthest_block, &bookmark, &last_node);
1720  if (err != HUBBUB_OK)
1721  return err;
1722 
1723  /* 7 */
1724  if (stack[common_ancestor].type == TABLE ||
1725  stack[common_ancestor].type == TBODY ||
1726  stack[common_ancestor].type == TFOOT ||
1727  stack[common_ancestor].type == THEAD ||
1728  stack[common_ancestor].type == TR) {
1729  err = aa_insert_into_foster_parent(treebuilder,
1730  stack[last_node].node, &reparented);
1731  } else {
1732  err = aa_reparent_node(treebuilder,
1733  stack[last_node].node,
1734  stack[common_ancestor].node,
1735  &reparented);
1736  }
1737  if (err != HUBBUB_OK)
1738  return err;
1739 
1740  treebuilder->tree_handler->unref_node(
1741  treebuilder->tree_handler->ctx,
1742  stack[last_node].node);
1743 
1744  /* If the reparented node is not the same as the one we were
1745  * previously using, then have it take the place of the other
1746  * one in the formatting list and stack. */
1747  if (reparented != stack[last_node].node) {
1748  struct formatting_list_entry *node_entry;
1749  for (node_entry = treebuilder->context.formatting_list_end;
1750  node_entry != NULL;
1751  node_entry = node_entry->prev) {
1752  if (node_entry->stack_index == last_node) {
1753  treebuilder->tree_handler->ref_node(
1754  treebuilder->tree_handler->ctx,
1755  reparented);
1756  node_entry->details.node = reparented;
1757  treebuilder->tree_handler->unref_node(
1758  treebuilder->tree_handler->ctx,
1759  stack[last_node].node);
1760  break;
1761  }
1762  }
1763  /* Already have enough references, so don't need to
1764  * explicitly reference it here. */
1765  stack[last_node].node = reparented;
1766  }
1767 
1768  /* 8 */
1769  err = treebuilder->tree_handler->clone_node(
1770  treebuilder->tree_handler->ctx,
1771  entry->details.node, false, &fe_clone);
1772  if (err != HUBBUB_OK)
1773  return err;
1774 
1775  /* 9 */
1776  err = treebuilder->tree_handler->reparent_children(
1777  treebuilder->tree_handler->ctx,
1778  stack[furthest_block].node, fe_clone);
1779  if (err != HUBBUB_OK) {
1780  treebuilder->tree_handler->unref_node(
1781  treebuilder->tree_handler->ctx,
1782  fe_clone);
1783  return err;
1784  }
1785 
1786  /* 10 */
1787  err = treebuilder->tree_handler->append_child(
1788  treebuilder->tree_handler->ctx,
1789  stack[furthest_block].node, fe_clone,
1790  &clone_appended);
1791  if (err != HUBBUB_OK) {
1792  treebuilder->tree_handler->unref_node(
1793  treebuilder->tree_handler->ctx,
1794  fe_clone);
1795  return err;
1796  }
1797 
1798  if (clone_appended != fe_clone) {
1799  /* No longer interested in fe_clone */
1800  treebuilder->tree_handler->unref_node(
1801  treebuilder->tree_handler->ctx,
1802  fe_clone);
1803  /* Need an extra reference, as we'll insert into the
1804  * formatting list and element stack */
1805  treebuilder->tree_handler->ref_node(
1806  treebuilder->tree_handler->ctx,
1807  clone_appended);
1808  }
1809 
1810  /* 11 and 12 are reversed here so that we know the correct
1811  * stack index to use when inserting into the formatting list */
1812 
1813  /* 12 */
1814  err = aa_remove_element_stack_item(treebuilder,
1815  formatting_element, furthest_block);
1816  assert(err == HUBBUB_OK);
1817 
1818  /* Fix up furthest block index */
1819  furthest_block--;
1820 
1821  /* Now, in the gap after furthest block,
1822  * we insert an entry for clone */
1823  stack[furthest_block + 1].type = entry->details.type;
1824  stack[furthest_block + 1].node = clone_appended;
1825 
1826  /* 11 */
1827  err = formatting_list_remove(treebuilder, entry,
1828  &ons, &otype, &onode, &oindex);
1829  assert(err == HUBBUB_OK);
1830 
1831  treebuilder->tree_handler->unref_node(
1832  treebuilder->tree_handler->ctx, onode);
1833 
1834  err = formatting_list_insert(treebuilder,
1835  bookmark.prev, bookmark.next,
1836  ons, otype, clone_appended, furthest_block + 1);
1837  if (err != HUBBUB_OK) {
1838  treebuilder->tree_handler->unref_node(
1839  treebuilder->tree_handler->ctx,
1840  clone_appended);
1841  return err;
1842  }
1843 
1844  /* 13 */
1845  }
1846 }
1847 
1858  hubbub_treebuilder *treebuilder,
1860 {
1861  formatting_list_entry *entry;
1862 
1863  entry = aa_find_formatting_element(treebuilder, type);
1864 
1865  if (entry == NULL || (entry->stack_index != 0 &&
1866  element_in_scope(treebuilder, entry->details.type,
1867  false) != entry->stack_index)) {
1869  return HUBBUB_OK;
1870  }
1871 
1872  if (entry->stack_index == 0) {
1873  /* Not in element stack => remove from formatting list */
1874  hubbub_ns ns;
1876  void *node;
1877  uint32_t index;
1878 
1881  formatting_list_remove(treebuilder, entry,
1882  &ns, &type, &node, &index);
1883 
1884  treebuilder->tree_handler->unref_node(
1885  treebuilder->tree_handler->ctx, node);
1886 
1887  return HUBBUB_OK;
1888  }
1889 
1890  if (entry->stack_index != treebuilder->context.current_node) {
1892  }
1893 
1894  *element = entry;
1895 
1896  return HUBBUB_REPROCESS;
1897 }
1898 
1907  hubbub_treebuilder *treebuilder, element_type type)
1908 {
1909  formatting_list_entry *entry;
1910 
1911  for (entry = treebuilder->context.formatting_list_end;
1912  entry != NULL; entry = entry->prev) {
1913 
1914  /* Assumption: HTML and TABLE elements are not in the list */
1915  if (is_scoping_element(entry->details.type) ||
1916  entry->details.type == type)
1917  break;
1918  }
1919 
1920  /* Check if we stopped on a marker, rather than a formatting element */
1921  if (entry != NULL && is_scoping_element(entry->details.type))
1922  entry = NULL;
1923 
1924  return entry;
1925 }
1926 
1937  formatting_list_entry *formatting_element,
1938  uint32_t *furthest_block)
1939 {
1940  uint32_t fe_index = formatting_element->stack_index;
1941  uint32_t fb;
1942 
1943  for (fb = fe_index + 1; fb <= treebuilder->context.current_node; fb++) {
1944  element_type type = treebuilder->context.element_stack[fb].type;
1945 
1946  if (!(is_phrasing_element(type) || is_formatting_element(type)))
1947  break;
1948  }
1949 
1950  if (fb > treebuilder->context.current_node) {
1951  hubbub_ns ns;
1953  void *node;
1954  uint32_t index;
1955 
1956  /* Pop all elements off the stack up to,
1957  * and including, the formatting element */
1958  do {
1959  element_stack_pop(treebuilder, &ns, &type, &node);
1960 
1961  treebuilder->tree_handler->unref_node(
1962  treebuilder->tree_handler->ctx,
1963  node);
1964  } while (treebuilder->context.current_node >= fe_index);
1965 
1966  /* Remove the formatting element from the list */
1967  formatting_list_remove(treebuilder, formatting_element,
1968  &ns, &type, &node, &index);
1969 
1970  treebuilder->tree_handler->unref_node(
1971  treebuilder->tree_handler->ctx, node);
1972 
1973  return HUBBUB_OK;
1974  }
1975 
1976  *furthest_block = fb;
1977 
1978  return HUBBUB_REPROCESS;
1979 }
1980 
1991  void *new_parent, void **reparented)
1992 {
1993  hubbub_error err;
1994 
1995  err = remove_node_from_dom(treebuilder, node);
1996  if (err != HUBBUB_OK)
1997  return err;
1998 
1999  return treebuilder->tree_handler->append_child(
2000  treebuilder->tree_handler->ctx,
2001  new_parent, node, reparented);
2002 }
2003 
2015  hubbub_treebuilder *treebuilder,
2016  uint32_t formatting_element, uint32_t *furthest_block,
2017  bookmark *bookmark, uint32_t *last_node)
2018 {
2019  hubbub_error err;
2020  element_context *stack = treebuilder->context.element_stack;
2021  uint32_t node, last, fb;
2022  formatting_list_entry *node_entry;
2023 
2024  node = last = fb = *furthest_block;
2025 
2026  while (true) {
2027  void *reparented;
2028 
2029  /* i */
2030  node--;
2031 
2032  /* ii */
2033  for (node_entry = treebuilder->context.formatting_list_end;
2034  node_entry != NULL;
2035  node_entry = node_entry->prev) {
2036  if (node_entry->stack_index == node)
2037  break;
2038  }
2039 
2040  /* Node is not in list of active formatting elements */
2041  if (node_entry == NULL) {
2042  err = aa_remove_element_stack_item(treebuilder,
2043  node, treebuilder->context.current_node);
2044  assert(err == HUBBUB_OK);
2045 
2046  /* Update furthest block index and the last node index,
2047  * as these are always below node in the stack */
2048  fb--;
2049  last--;
2050 
2051  /* Fixup the current_node index */
2052  treebuilder->context.current_node--;
2053 
2054  /* Back to i */
2055  continue;
2056  }
2057 
2058  /* iii */
2059  if (node == formatting_element)
2060  break;
2061 
2062  /* iv */
2063  if (last == fb) {
2064  bookmark->prev = node_entry;
2065  bookmark->next = node_entry->next;
2066  }
2067 
2068  /* v */
2069  err = aa_clone_and_replace_entries(treebuilder, node_entry);
2070  if (err != HUBBUB_OK)
2071  return err;
2072 
2073  /* vi */
2074  err = aa_reparent_node(treebuilder, stack[last].node,
2075  stack[node].node, &reparented);
2076  if (err != HUBBUB_OK)
2077  return err;
2078 
2079  treebuilder->tree_handler->unref_node(
2080  treebuilder->tree_handler->ctx,
2081  stack[last].node);
2082 
2083  /* If the reparented node is not the same as the one we were
2084  * previously using, then have it take the place of the other
2085  * one in the formatting list and stack. */
2086  if (reparented != stack[last].node) {
2087  for (node_entry =
2088  treebuilder->context.formatting_list_end;
2089  node_entry != NULL;
2090  node_entry = node_entry->prev) {
2091  if (node_entry->stack_index == last) {
2092  treebuilder->tree_handler->ref_node(
2093  treebuilder->tree_handler->ctx,
2094  reparented);
2095  node_entry->details.node = reparented;
2096  treebuilder->tree_handler->unref_node(
2097  treebuilder->tree_handler->ctx,
2098  stack[last].node);
2099  break;
2100  }
2101  }
2102  /* Already have enough references, so don't need to
2103  * explicitly reference it here. */
2104  stack[last].node = reparented;
2105  }
2106 
2107  /* vii */
2108  last = node;
2109 
2110  /* viii */
2111  }
2112 
2113  *furthest_block = fb;
2114  *last_node = last;
2115 
2116  return HUBBUB_OK;
2117 }
2118 
2130  uint32_t index, uint32_t limit)
2131 {
2132  element_context *stack = treebuilder->context.element_stack;
2133  uint32_t n;
2134 
2135  assert(index < limit);
2136  assert(limit <= treebuilder->context.current_node);
2137 
2138  /* First, scan over subsequent entries in the stack,
2139  * searching for them in the list of active formatting
2140  * entries. If found, update the corresponding
2141  * formatting list entry's stack index to match the
2142  * new stack location */
2143  for (n = index + 1; n <= limit; n++) {
2144  if (is_formatting_element(stack[n].type) ||
2145  (is_scoping_element(stack[n].type) &&
2146  stack[n].type != HTML &&
2147  stack[n].type != TABLE)) {
2149 
2150  for (e = treebuilder->context.formatting_list_end;
2151  e != NULL; e = e->prev) {
2152  if (e->stack_index == n)
2153  e->stack_index--;
2154  }
2155  }
2156  }
2157 
2158  /* Reduce node's reference count */
2159  treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx,
2160  stack[index].node);
2161 
2162  /* Now, shuffle the stack up one, removing node in the process */
2163  memmove(&stack[index], &stack[index + 1],
2164  (limit - index) * sizeof(element_context));
2165 
2166  return HUBBUB_OK;
2167 }
2168 
2177  formatting_list_entry *element)
2178 {
2179  hubbub_error err;
2180  hubbub_ns ons;
2181  element_type otype;
2182  uint32_t oindex;
2183  void *clone, *onode;
2184 
2185  /* Shallow clone of node */
2186  err = treebuilder->tree_handler->clone_node(
2187  treebuilder->tree_handler->ctx,
2188  element->details.node, false, &clone);
2189  if (err != HUBBUB_OK)
2190  return err;
2191 
2192  /* Replace formatting list entry for node with clone */
2193  err = formatting_list_replace(treebuilder, element,
2194  element->details.ns, element->details.type,
2195  clone, element->stack_index,
2196  &ons, &otype, &onode, &oindex);
2197  assert(err == HUBBUB_OK);
2198 
2199  treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx,
2200  onode);
2201 
2202  treebuilder->tree_handler->ref_node(treebuilder->tree_handler->ctx,
2203  clone);
2204 
2205  /* Replace node's stack entry with clone */
2206  treebuilder->context.element_stack[element->stack_index].node = clone;
2207 
2208  treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx,
2209  onode);
2210 
2211  return HUBBUB_OK;
2212 }
2213 
2223  void *node, void **inserted)
2224 {
2225  hubbub_error err;
2226  element_context *stack = treebuilder->context.element_stack;
2227  void *foster_parent = NULL;
2228  bool insert = false;
2229 
2230  uint32_t cur_table = current_table(treebuilder);
2231 
2232  stack[cur_table].tainted = true;
2233 
2234  if (cur_table == 0) {
2235  treebuilder->tree_handler->ref_node(
2236  treebuilder->tree_handler->ctx,
2237  stack[0].node);
2238 
2239  foster_parent = stack[0].node;
2240  } else {
2241  void *t_parent = NULL;
2242 
2243  treebuilder->tree_handler->get_parent(
2244  treebuilder->tree_handler->ctx,
2245  stack[cur_table].node,
2246  true, &t_parent);
2247 
2248  if (t_parent != NULL) {
2249  foster_parent = t_parent;
2250  insert = true;
2251  } else {
2252  treebuilder->tree_handler->ref_node(
2253  treebuilder->tree_handler->ctx,
2254  stack[cur_table - 1].node);
2255  foster_parent = stack[cur_table - 1].node;
2256  }
2257  }
2258 
2259  err = remove_node_from_dom(treebuilder, node);
2260  if (err != HUBBUB_OK) {
2261  treebuilder->tree_handler->unref_node(
2262  treebuilder->tree_handler->ctx,
2263  foster_parent);
2264  return err;
2265  }
2266 
2267  if (insert) {
2268  err = treebuilder->tree_handler->insert_before(
2269  treebuilder->tree_handler->ctx,
2270  foster_parent, node,
2271  stack[cur_table].node,
2272  inserted);
2273  } else {
2274  err = treebuilder->tree_handler->append_child(
2275  treebuilder->tree_handler->ctx,
2276  foster_parent, node,
2277  inserted);
2278  }
2279  if (err != HUBBUB_OK) {
2280  treebuilder->tree_handler->unref_node(
2281  treebuilder->tree_handler->ctx,
2282  foster_parent);
2283  return err;
2284  }
2285 
2286  treebuilder->tree_handler->unref_node(treebuilder->tree_handler->ctx,
2287  foster_parent);
2288 
2289  return HUBBUB_OK;
2290 }
2291 
2292 
2300  hubbub_treebuilder *treebuilder, element_type type)
2301 {
2302  if (!element_in_scope(treebuilder, type, false)) {
2304  } else {
2305  uint32_t popped = 0;
2306  element_type otype;
2307 
2308  close_implied_end_tags(treebuilder, UNKNOWN);
2309 
2310  do {
2311  hubbub_ns ns;
2312  void *node;
2313 
2314  element_stack_pop(treebuilder, &ns, &otype, &node);
2315 
2316  treebuilder->tree_handler->unref_node(
2317  treebuilder->tree_handler->ctx,
2318  node);
2319 
2320  popped++;
2321  } while (otype != type);
2322 
2323  if (popped > 1) {
2325  }
2326 
2328  }
2329 
2330  return HUBBUB_OK;
2331 }
2332 
2339 {
2340  hubbub_error err;
2341  hubbub_tag tag;
2342 
2345  /* Act as if <br> has been seen. */
2346 
2347  tag.ns = HUBBUB_NS_HTML;
2348  tag.name.ptr = (const uint8_t *) "br";
2349  tag.name.len = SLEN("br");
2350 
2351  tag.n_attributes = 0;
2352  tag.attributes = NULL;
2353 
2354  err = reconstruct_active_formatting_list(treebuilder);
2355  if (err != HUBBUB_OK)
2356  return err;
2357 
2358  return insert_element(treebuilder, &tag, false);
2359 }
2360 
2369 {
2370  element_context *stack = treebuilder->context.element_stack;
2371  uint32_t node = treebuilder->context.current_node;
2372 
2373  do {
2374  if (stack[node].type == type) {
2375  uint32_t popped = 0;
2376  element_type otype;
2377 
2378  close_implied_end_tags(treebuilder, UNKNOWN);
2379 
2380  while (treebuilder->context.current_node >= node) {
2381  hubbub_ns ns;
2382  void *node;
2383 
2384  element_stack_pop(treebuilder,
2385  &ns, &otype, &node);
2386 
2387  treebuilder->tree_handler->unref_node(
2388  treebuilder->tree_handler->ctx,
2389  node);
2390 
2391  popped++;
2392 
2393  if (otype == type)
2394  break;
2395  }
2396 
2397  if (popped > 1) {
2399  }
2400 
2401  break;
2402  } else if (!is_formatting_element(stack[node].type) &&
2403  !is_phrasing_element(stack[node].type)) {
2405  break;
2406  }
2407  } while (--node > 0);
2408 
2409  return HUBBUB_OK;
2410 }
2411 
#define SLEN(s)
Definition: utils.h:21
hubbub_ns ns
Element namespace.
Definition: internal.h:44
Definition: internal.h:20
bool tainted
Only for tables.
Definition: internal.h:48
formatting_list_entry * prev
Previous entry.
Definition: in_body.c:22
hubbub_error process_comment_append(hubbub_treebuilder *treebuilder, const hubbub_token *token, void *parent)
Process a comment token, appending it to the given parent.
Definition: treebuilder.c:421
void formatting_list_dump(hubbub_treebuilder *treebuilder, FILE *fp)
Dump a formatting list to the given file pointer.
Definition: treebuilder.c:1475
Definition: internal.h:25
Definition: internal.h:18
static hubbub_error process_0container_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process a container end tag as if in "in body".
Definition: in_body.c:1441
Definition: internal.h:30
hubbub_token_type type
The token type.
Definition: types.h:120
struct hubbub_tokeniser_optparams::@11 content_model
Current content model.
Definition: internal.h:20
Definition: internal.h:20
static hubbub_error process_0presentational_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process a presentational end tag as if in "in body".
Definition: in_body.c:1665
void * ctx
Context pointer.
Definition: tree.h:292
hubbub_ns ns
Tag namespace.
Definition: types.h:109
Definition: internal.h:18
Definition: internal.h:27
uint32_t stack_index
Index into element stack.
Definition: internal.h:64
Data for a tag.
Definition: types.h:108
Token data.
Definition: types.h:119
static hubbub_error process_start_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a start tag.
Definition: in_body.c:247
hubbub_content_model model
Definition: tokeniser.h:48
bool is_scoping_element(element_type type)
Determine if a node is a scoping element.
Definition: treebuilder.c:1027
hubbub_string name
Tag name.
Definition: types.h:110
Definition: internal.h:16
static hubbub_error process_0form_in_body(hubbub_treebuilder *treebuilder)
Process a form end tag as if in "in body".
Definition: in_body.c:1478
Entry in a formatting list.
Definition: internal.h:60
void adjust_foreign_attributes(hubbub_treebuilder *treebuilder, hubbub_tag *tag)
Adjust foreign attributes.
hubbub_tree_handler * tree_handler
Callback table.
Definition: internal.h:122
const uint8_t * ptr
Pointer to data.
Definition: types.h:77
Definition: modes.h:28
Definition: modes.h:27
static hubbub_error process_textarea_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a textarea start tag as if in "in body".
Definition: in_body.c:1323
void close_implied_end_tags(hubbub_treebuilder *treebuilder, element_type except)
Close implied end tags.
Definition: treebuilder.c:829
hubbub_error aa_insert_into_foster_parent(hubbub_treebuilder *treebuilder, void *node, void **inserted)
Adoption agency: locate foster parent and insert node into it.
Definition: in_body.c:2222
bool is_phrasing_element(element_type type)
Determine if a node is a phrasing element.
Definition: treebuilder.c:1049
static hubbub_error process_0br_in_body(hubbub_treebuilder *treebuilder)
Process a br end tag as if in "in body".
Definition: in_body.c:2338
Definition: internal.h:21
element_type
Definition: internal.h:13
Definition: internal.h:30
Tokeniser string type.
Definition: types.h:76
static hubbub_error process_hN_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a hN start tag as if in "in body".
Definition: in_body.c:581
static hubbub_error aa_reparent_node(hubbub_treebuilder *treebuilder, void *node, void *new_parent, void **reparented)
Adoption agency: reparent a node.
Definition: in_body.c:1990
Definition: internal.h:17
hubbub_string value
Attribute value.
Definition: types.h:87
static hubbub_error aa_remove_element_stack_item(hubbub_treebuilder *treebuilder, uint32_t index, uint32_t limit)
Adoption agency: remove an entry from the stack at the given index.
Definition: in_body.c:2129
hubbub_error hubbub_tokeniser_setopt(hubbub_tokeniser *tokeniser, hubbub_tokeniser_opttype type, hubbub_tokeniser_optparams *params)
Configure a hubbub tokeniser.
Definition: tokeniser.c:366
Definition: internal.h:27
void element_stack_dump(hubbub_treebuilder *treebuilder, FILE *fp)
Dump an element stack to the given file pointer.
Definition: treebuilder.c:1456
bool is_formatting_element(element_type type)
Determine if a node is a formatting element.
Definition: treebuilder.c:1038
struct formatting_list_entry * prev
Previous in list.
Definition: internal.h:66
Definition: internal.h:18
Definition: internal.h:17
Definition: internal.h:18
Definition: internal.h:25
Definition: internal.h:25
hubbub_error formatting_list_remove(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns *ns, element_type *type, void **node, uint32_t *stack_index)
Remove an element from the list of active formatting elements.
Definition: treebuilder.c:1384
static formatting_list_entry * aa_find_formatting_element(hubbub_treebuilder *treebuilder, element_type type)
Adoption agency: find formatting element.
Definition: in_body.c:1906
bool strip_leading_lr
Whether to strip a LR from the start of the next character sequence received.
Definition: internal.h:102
Bookmark for formatting list.
Definition: in_body.c:21
#define UNUSED(x)
Definition: utils.h:25
Definition: internal.h:22
static hubbub_error process_image_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an image start tag as if in "in body".
Definition: in_body.c:1121
hubbub_string name
Attribute name.
Definition: types.h:86
static hubbub_error aa_clone_and_replace_entries(hubbub_treebuilder *treebuilder, formatting_list_entry *element)
Adoption agency: shallow clone a node and replace its formatting list and element stack entries...
Definition: in_body.c:2176
Definition: internal.h:25
static hubbub_error process_0applet_button_marquee_object_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process an applet, button, marquee, or object end tag as if in "in body".
Definition: in_body.c:2299
Definition: internal.h:16
insertion_mode mode
The current insertion mode.
Definition: internal.h:75
Definition: internal.h:27
Definition: internal.h:23
static hubbub_error process_isindex_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an isindex start tag as if in "in body".
Definition: in_body.c:1147
void * form_element
Pointer to most recently opened FORM element.
Definition: internal.h:90
static hubbub_error process_phrasing_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a phrasing start tag as if in "in body".
Definition: in_body.c:1383
Definition: internal.h:22
Hubbub tokeniser option parameters.
Definition: tokeniser.h:36
Definition: internal.h:19
hubbub_error reconstruct_active_formatting_list(hubbub_treebuilder *treebuilder)
Reconstruct the list of active formatting elements.
Definition: treebuilder.c:543
size_t len
Byte length of string.
Definition: types.h:78
Definition: internal.h:22
hubbub_tokeniser * tokeniser
Underlying tokeniser.
Definition: internal.h:118
Definition: internal.h:23
formatting_list_entry * next
Next entry.
Definition: in_body.c:23
Definition: internal.h:22
bool self_closing
Whether the tag can have children.
Definition: types.h:113
Definition: internal.h:27
static hubbub_error process_body_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a body start tag as if in "in body".
Definition: in_body.c:504
hubbub_error handle_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Handle tokens in "in body" insertion mode.
Definition: in_body.c:123
Definition: internal.h:19
Definition: internal.h:20
hubbub_tree_clone_node clone_node
Clone node.
Definition: tree.h:283
formatting_list_entry * formatting_list_end
End of active formatting list.
Definition: internal.h:85
Definition: internal.h:30
bool enable_scripting
Whether scripting is enabled.
Definition: internal.h:95
Definition: modes.h:22
struct bookmark bookmark
Bookmark for formatting list.
#define PROMPT
static hubbub_error process_character(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a character token.
Definition: in_body.c:192
Definition: internal.h:20
Definition: internal.h:19
const char * name
Definition: initial.c:22
Definition: internal.h:34
static hubbub_error process_container_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a generic container start tag as if in "in body".
Definition: in_body.c:561
static hubbub_error process_0body_in_body(hubbub_treebuilder *treebuilder)
Process a body end tag as if in "in body".
Definition: in_body.c:1401
hubbub_treebuilder_context context
Our context.
Definition: internal.h:120
static hubbub_error process_hr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an hr start tag as if in "in body".
Definition: in_body.c:1097
static hubbub_error aa_find_furthest_block(hubbub_treebuilder *treebuilder, formatting_list_entry *formatting_element, uint32_t *furthest_block)
Adoption agency: find furthest block.
Definition: in_body.c:1936
Definition: internal.h:21
Definition: internal.h:21
Definition: internal.h:19
hubbub_error remove_node_from_dom(hubbub_treebuilder *treebuilder, void *node)
Remove a node from the DOM.
Definition: treebuilder.c:681
Definition: internal.h:18
hubbub_error insert_element(hubbub_treebuilder *treebuilder, const hubbub_tag *tag_name, bool push)
Create element and insert it into the DOM, potentially pushing it on the stack.
Definition: treebuilder.c:752
hubbub_error handle_in_head(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Handle token in "in head" insertion mode.
Definition: in_head.c:109
static hubbub_error process_0dd_dt_li_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process a dd, dt, or li end tag as if in "in body".
Definition: in_body.c:1578
hubbub_attribute * attributes
Array of attribute data.
Definition: types.h:112
hubbub_error formatting_list_replace(hubbub_treebuilder *treebuilder, formatting_list_entry *entry, hubbub_ns ns, element_type type, void *node, uint32_t stack_index, hubbub_ns *ons, element_type *otype, void **onode, uint32_t *ostack_index)
Remove an element from the list of active formatting elements.
Definition: treebuilder.c:1424
static hubbub_error process_frameset_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a frameset start tag as if in "in body".
Definition: in_body.c:526
static hubbub_error aa_find_and_validate_formatting_element(hubbub_treebuilder *treebuilder, element_type type, formatting_list_entry **element)
Adoption agency: find and validate the formatting element.
Definition: in_body.c:1857
struct formatting_list_entry * next
Next in list.
Definition: internal.h:67
Definition: internal.h:27
hubbub_error
Definition: errors.h:18
hubbub_tree_reparent_children reparent_children
Reparent children.
Definition: tree.h:284
hubbub_error element_stack_pop_until(hubbub_treebuilder *treebuilder, element_type type)
Pop elements until an element of type "element" has been popped.
Definition: treebuilder.c:1162
void * node
Node pointer.
Definition: internal.h:54
Definition: internal.h:19
static hubbub_error process_0p_in_body(hubbub_treebuilder *treebuilder)
Process a p end tag as if in "in body".
Definition: in_body.c:1524
uint32_t current_table(hubbub_treebuilder *treebuilder)
Find the stack index of the current table.
Definition: treebuilder.c:1239
hubbub_error append_text(hubbub_treebuilder *treebuilder, const hubbub_string *string)
Append text to the current node, inserting into the last child of the current node, iff it's a Text node.
Definition: treebuilder.c:944
Item on the element stack.
Definition: internal.h:42
Definition: internal.h:20
hubbub_string character
Definition: types.h:129
hubbub_tree_ref_node ref_node
Reference node.
Definition: tree.h:278
Definition: internal.h:22
static hubbub_error process_form_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a form start tag as if in "in body".
Definition: in_body.c:621
hubbub_tree_get_parent get_parent
Get parent.
Definition: tree.h:285
Definition: internal.h:16
hubbub_tree_unref_node unref_node
Unreference node.
Definition: tree.h:279
Definition: internal.h:17
element_type type
Definition: treebuilder.c:26
static hubbub_error process_presentational_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type)
Process a b, big, em, font, i, s, small, strike, strong, tt, or u start tag as if in "in body"...
Definition: in_body.c:861
No error.
Definition: errors.h:19
Definition: internal.h:27
bool frameset_ok
Whether to process a frameset.
Definition: internal.h:110
hubbub_tag tag
Definition: types.h:125
Definition: internal.h:19
Definition: internal.h:27
static hubbub_error process_dd_dt_li_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type)
Process a dd, dt or li start tag as if in "in body".
Definition: in_body.c:661
hubbub_tree_insert_before insert_before
Insert before.
Definition: tree.h:281
Definition: internal.h:19
Tag attribute data.
Definition: types.h:84
Definition: internal.h:19
Definition: internal.h:19
hubbub_ns
Possible namespaces.
Definition: types.h:63
union hubbub_token::@3 data
Type-specific data.
static hubbub_error process_end_tag(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an end tag.
Definition: in_body.c:416
hubbub_tree_add_attributes add_attributes
Add attributes.
Definition: tree.h:288
hubbub_error formatting_list_insert(hubbub_treebuilder *treebuilder, formatting_list_entry *prev, formatting_list_entry *next, hubbub_ns ns, element_type type, void *node, uint32_t stack_index)
Insert an element into the list of active formatting elements.
Definition: treebuilder.c:1332
hubbub_ns ns
Attribute namespace.
Definition: types.h:85
Definition: internal.h:27
static hubbub_error process_a_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an "a" start tag as if in "in body".
Definition: in_body.c:759
Definition: internal.h:27
static hubbub_error process_plaintext_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a plaintext start tag as if in "in body".
Definition: in_body.c:727
hubbub_error formatting_list_append(hubbub_treebuilder *treebuilder, hubbub_ns ns, element_type type, void *node, uint32_t stack_index)
Append an element to the end of the list of active formatting elements.
Definition: treebuilder.c:1292
Definition: modes.h:23
static hubbub_error process_applet_marquee_object_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token, element_type type)
Process an applet, marquee or object start tag as if in "in body".
Definition: in_body.c:1042
insertion_mode second_mode
The secondary insertion mode.
Definition: internal.h:76
static hubbub_error process_nobr_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a nobr start tag as if in "in body".
Definition: in_body.c:912
static hubbub_error process_select_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a select start tag as if in "in body".
Definition: in_body.c:1337
void adjust_mathml_attributes(hubbub_treebuilder *treebuilder, hubbub_tag *tag)
Adjust MathML attributes.
void adjust_svg_attributes(hubbub_treebuilder *treebuilder, hubbub_tag *tag)
Adjust SVG attributes.
Definition: internal.h:18
Definition: internal.h:27
Definition: internal.h:21
Definition: internal.h:27
element_type type
Element type.
Definition: internal.h:45
Definition: internal.h:32
static hubbub_error process_0h_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process a h1, h2, h3, h4, h5, or h6 end tag as if in "in body".
Definition: in_body.c:1617
Definition: internal.h:17
Definition: internal.h:30
hubbub_error element_stack_remove(hubbub_treebuilder *treebuilder, uint32_t index, hubbub_ns *ns, element_type *type, void **removed)
Remove a node from the stack of open elements.
Definition: treebuilder.c:1191
static hubbub_error process_0generic_in_body(hubbub_treebuilder *treebuilder, element_type type)
Process a generic end tag as if in "in body".
Definition: in_body.c:2367
uint32_t element_in_scope(hubbub_treebuilder *treebuilder, element_type type, bool in_table)
Determine if an element is in (table) scope.
Definition: treebuilder.c:500
hubbub_error element_stack_pop(hubbub_treebuilder *treebuilder, hubbub_ns *ns, element_type *type, void **node)
Pop an element off the stack of open elements.
Definition: treebuilder.c:1113
static hubbub_error process_html_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a html start tag as if in "in body".
Definition: in_body.c:486
element_type element_type_from_name(hubbub_treebuilder *treebuilder, const hubbub_string *tag_name)
Convert an element name into an element type.
Definition: treebuilder.c:987
static hubbub_error process_opt_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process an option or optgroup start tag as if in "in body".
Definition: in_body.c:1359
Definition: internal.h:23
element_context details
Entry details.
Definition: internal.h:62
Treebuilder object.
Definition: internal.h:116
hubbub_tree_append_child append_child
Append child.
Definition: tree.h:280
static hubbub_error process_button_in_body(hubbub_treebuilder *treebuilder, const hubbub_token *token)
Process a button start tag as if in "in body".
Definition: in_body.c:978
Definition: internal.h:27
element_context * element_stack
Stack of open elements.
Definition: internal.h:79
void clear_active_formatting_list_to_marker(hubbub_treebuilder *treebuilder)
Clear the list of active formatting elements up to the last marker.
Definition: treebuilder.c:717
Definition: internal.h:18
uint32_t n_attributes
Count of attributes.
Definition: types.h:111
uint32_t current_node
Index of current node in stack.
Definition: internal.h:81
Definition: internal.h:19
static hubbub_error aa_find_bookmark_location_reparenting_misnested(hubbub_treebuilder *treebuilder, uint32_t formatting_element, uint32_t *furthest_block, bookmark *bookmark, uint32_t *last_node)
Adoption agency: this is step 6.
Definition: in_body.c:2014
hubbub_error parse_generic_rcdata(hubbub_treebuilder *treebuilder, const hubbub_token *token, bool rcdata)
Trigger parsing of generic (R)CDATA.
Definition: treebuilder.c:464