1 /*
2 * Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
3 * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * \file
22 * Implementation of HTML content DOM event handling.
23 */
24
25 #include "utils/config.h"
26 #include "utils/corestrings.h"
27 #include "utils/nsoption.h"
28 #include "utils/log.h"
29 #include "utils/ascii.h"
30 #include "utils/string.h"
31 #include "utils/nsurl.h"
32 #include "content/content.h"
33 #include "javascript/js.h"
34
35 #include "desktop/gui_internal.h"
36 #include "desktop/gui_table.h"
37 #include "netsurf/bitmap.h"
38
39 #include "html/private.h"
40 #include "html/object.h"
41 #include "html/css.h"
42 #include "html/box.h"
43 #include "html/box_construct.h"
44 #include "html/form_internal.h"
45 #include "html/dom_event.h"
46
47
48 /**
49 * process a base element being inserted into the DOM
50 *
51 * \param htmlc The html content containing the DOM
52 * \param node The DOM node being inserted
53 * \return NSERROR_OK on success else appropriate error code
54 */
html_process_inserted_base(html_content * htmlc,dom_node * node)55 static bool html_process_inserted_base(html_content *htmlc, dom_node *node)
56 {
57 dom_exception exc; /* returned by libdom functions */
58 dom_string *atr_string;
59
60 /* get href attribute if present */
61 exc = dom_element_get_attribute(node, corestring_dom_href, &atr_string);
62 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
63 nsurl *url;
64 nserror error;
65
66 /* get url from string */
67 error = nsurl_create(dom_string_data(atr_string), &url);
68 dom_string_unref(atr_string);
69 if (error == NSERROR_OK) {
70 if (htmlc->base_url != NULL) {
71 nsurl_unref(htmlc->base_url);
72 }
73 htmlc->base_url = url;
74 }
75 }
76
77
78 /* get target attribute if present and not already set */
79 if (htmlc->base_target != NULL) {
80 return true;
81 }
82
83 exc = dom_element_get_attribute(node,
84 corestring_dom_target,
85 &atr_string);
86 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
87 /* Validation rules from the HTML5 spec for the base element:
88 * The target must be one of _blank, _self, _parent, or
89 * _top or any identifier which does not begin with an
90 * underscore
91 */
92 if (*dom_string_data(atr_string) != '_' ||
93 dom_string_caseless_lwc_isequal(atr_string,
94 corestring_lwc__blank) ||
95 dom_string_caseless_lwc_isequal(atr_string,
96 corestring_lwc__self) ||
97 dom_string_caseless_lwc_isequal(atr_string,
98 corestring_lwc__parent) ||
99 dom_string_caseless_lwc_isequal(atr_string,
100 corestring_lwc__top)) {
101 htmlc->base_target = strdup(dom_string_data(atr_string));
102 }
103 dom_string_unref(atr_string);
104 }
105
106 return true;
107 }
108
109
110
111 /**
112 * Process img element being inserted into the DOM.
113 *
114 * \param htmlc The html content containing the DOM
115 * \param node The DOM node being inserted
116 * \return NSERROR_OK on success else appropriate error code
117 */
html_process_inserted_img(html_content * htmlc,dom_node * node)118 static bool html_process_inserted_img(html_content *htmlc, dom_node *node)
119 {
120 dom_string *src;
121 nsurl *url;
122 nserror err;
123 dom_exception exc;
124 bool success;
125
126 /* Do nothing if foreground images are disabled */
127 if (nsoption_bool(foreground_images) == false) {
128 return true;
129 }
130
131 exc = dom_element_get_attribute(node, corestring_dom_src, &src);
132 if (exc != DOM_NO_ERR || src == NULL) {
133 return true;
134 }
135
136 err = nsurl_join(htmlc->base_url, dom_string_data(src), &url);
137 if (err != NSERROR_OK) {
138 dom_string_unref(src);
139 return false;
140 }
141 dom_string_unref(src);
142
143 /* Speculatively fetch the image */
144 success = html_fetch_object(htmlc, url, NULL, CONTENT_IMAGE, false);
145 nsurl_unref(url);
146
147 return success;
148 }
149
150
151 /**
152 * process a LINK element being inserted into the DOM
153 *
154 * \note only the http-equiv attribute for refresh is currently considered
155 *
156 * \param htmlc The html content containing the DOM
157 * \param n The DOM node being inserted
158 * \return NSERROR_OK on success else appropriate error code
159 */
html_process_inserted_link(html_content * c,dom_node * node)160 static bool html_process_inserted_link(html_content *c, dom_node *node)
161 {
162 struct content_rfc5988_link link; /* the link added to the content */
163 dom_exception exc; /* returned by libdom functions */
164 dom_string *atr_string;
165 nserror error;
166
167 /* Handle stylesheet loading */
168 html_css_process_link(c, (dom_node *)node);
169
170 /* try Generic link handling */
171
172 memset(&link, 0, sizeof(struct content_rfc5988_link));
173
174 /* check that the relation exists - w3c spec says must be present */
175 exc = dom_element_get_attribute(node, corestring_dom_rel, &atr_string);
176 if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
177 return false;
178 }
179 /* get a lwc string containing the link relation */
180 exc = dom_string_intern(atr_string, &link.rel);
181 dom_string_unref(atr_string);
182 if (exc != DOM_NO_ERR) {
183 return false;
184 }
185
186 /* check that the href exists - w3c spec says must be present */
187 exc = dom_element_get_attribute(node, corestring_dom_href, &atr_string);
188 if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
189 lwc_string_unref(link.rel);
190 return false;
191 }
192
193 /* get nsurl */
194 error = nsurl_join(c->base_url, dom_string_data(atr_string),
195 &link.href);
196 dom_string_unref(atr_string);
197 if (error != NSERROR_OK) {
198 lwc_string_unref(link.rel);
199 return false;
200 }
201
202 /* look for optional properties -- we don't care if internment fails */
203
204 exc = dom_element_get_attribute(node,
205 corestring_dom_hreflang, &atr_string);
206 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
207 /* get a lwc string containing the href lang */
208 (void)dom_string_intern(atr_string, &link.hreflang);
209 dom_string_unref(atr_string);
210 }
211
212 exc = dom_element_get_attribute(node,
213 corestring_dom_type, &atr_string);
214 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
215 /* get a lwc string containing the type */
216 (void)dom_string_intern(atr_string, &link.type);
217 dom_string_unref(atr_string);
218 }
219
220 exc = dom_element_get_attribute(node,
221 corestring_dom_media, &atr_string);
222 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
223 /* get a lwc string containing the media */
224 (void)dom_string_intern(atr_string, &link.media);
225 dom_string_unref(atr_string);
226 }
227
228 exc = dom_element_get_attribute(node,
229 corestring_dom_sizes, &atr_string);
230 if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
231 /* get a lwc string containing the sizes */
232 (void)dom_string_intern(atr_string, &link.sizes);
233 dom_string_unref(atr_string);
234 }
235
236 /* add to content */
237 content__add_rfc5988_link(&c->base, &link);
238
239 if (link.sizes != NULL)
240 lwc_string_unref(link.sizes);
241 if (link.media != NULL)
242 lwc_string_unref(link.media);
243 if (link.type != NULL)
244 lwc_string_unref(link.type);
245 if (link.hreflang != NULL)
246 lwc_string_unref(link.hreflang);
247
248 nsurl_unref(link.href);
249 lwc_string_unref(link.rel);
250
251 return true;
252 }
253
254
255 /* handler for a SCRIPT which has been added to a tree */
256 static void
dom_SCRIPT_showed_up(html_content * htmlc,dom_html_script_element * script)257 dom_SCRIPT_showed_up(html_content *htmlc, dom_html_script_element *script)
258 {
259 dom_exception exc;
260 dom_html_script_element_flags flags;
261 dom_hubbub_error res;
262 bool within;
263
264 if (!htmlc->enable_scripting) {
265 NSLOG(netsurf, INFO, "Encountered a script, but scripting is off, ignoring");
266 return;
267 }
268
269 NSLOG(netsurf, DEEPDEBUG, "Encountered a script, node %p showed up", script);
270
271 exc = dom_html_script_element_get_flags(script, &flags);
272 if (exc != DOM_NO_ERR) {
273 NSLOG(netsurf, DEEPDEBUG, "Unable to retrieve flags, giving up");
274 return;
275 }
276
277 if (flags & DOM_HTML_SCRIPT_ELEMENT_FLAG_PARSER_INSERTED) {
278 NSLOG(netsurf, DEBUG, "Script was parser inserted, skipping");
279 return;
280 }
281
282 exc = dom_node_contains(htmlc->document, script, &within);
283 if (exc != DOM_NO_ERR) {
284 NSLOG(netsurf, DEBUG, "Unable to determine if script was within document, ignoring");
285 return;
286 }
287
288 if (!within) {
289 NSLOG(netsurf, DEBUG, "Script was not within the document, ignoring for now");
290 return;
291 }
292
293 res = html_process_script(htmlc, (dom_node *) script);
294 if (res == DOM_HUBBUB_OK) {
295 NSLOG(netsurf, DEEPDEBUG, "Inserted script has finished running");
296 } else {
297 if (res == (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED)) {
298 NSLOG(netsurf, DEEPDEBUG, "Inserted script has launced asynchronously");
299 } else {
300 NSLOG(netsurf, DEEPDEBUG, "Failure starting script");
301 }
302 }
303 }
304
305
306 /**
307 * process a META element being inserted into the DOM
308 *
309 * \note only the http-equiv attribute for refresh is currently considered
310 *
311 * \param htmlc The html content containing the DOM
312 * \param n The DOM node being inserted
313 * \return NSERROR_OK on success else appropriate error code
314 */
html_process_inserted_meta(html_content * c,dom_node * n)315 static nserror html_process_inserted_meta(html_content *c, dom_node *n)
316 {
317 union content_msg_data msg_data;
318 const char *url, *end, *refresh = NULL;
319 char *new_url;
320 char quote = '\0';
321 dom_string *equiv, *content;
322 dom_exception exc;
323 nsurl *nsurl;
324 nserror error = NSERROR_OK;
325
326 if (c->refresh) {
327 /* refresh already delt with */
328 return NSERROR_OK;
329 }
330
331 exc = dom_element_get_attribute(n, corestring_dom_http_equiv, &equiv);
332 if (exc != DOM_NO_ERR) {
333 return NSERROR_DOM;
334 }
335
336 if (equiv == NULL) {
337 return NSERROR_OK;
338 }
339
340 if (!dom_string_caseless_lwc_isequal(equiv, corestring_lwc_refresh)) {
341 dom_string_unref(equiv);
342 return NSERROR_OK;
343 }
344
345 dom_string_unref(equiv);
346
347 exc = dom_element_get_attribute(n, corestring_dom_content, &content);
348 if (exc != DOM_NO_ERR) {
349 return NSERROR_DOM;
350 }
351
352 if (content == NULL) {
353 return NSERROR_OK;
354 }
355
356 end = dom_string_data(content) + dom_string_byte_length(content);
357
358 /* content := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS]
359 * intpart := 1*DIGIT
360 * fracpart := 1*('.' | DIGIT)
361 * url := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq)
362 * url-nq := *urlchar
363 * url-sq := "'" *(urlchar | '"') "'"
364 * url-dq := '"' *(urlchar | "'") '"'
365 * urlchar := [#x9#x21#x23-#x26#x28-#x7E] | nonascii
366 * nonascii := [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
367 */
368
369 url = dom_string_data(content);
370
371 /* *LWS */
372 while (url < end && ascii_is_space(*url)) {
373 url++;
374 }
375
376 /* intpart */
377 if (url == end || (*url < '0' || '9' < *url)) {
378 /* Empty content, or invalid timeval */
379 dom_string_unref(content);
380 return NSERROR_OK;
381 }
382
383 msg_data.delay = (int) strtol(url, &new_url, 10);
384 /* a very small delay and self-referencing URL can cause a loop
385 * that grinds machines to a halt. To prevent this we set a
386 * minimum refresh delay of 1s. */
387 if (msg_data.delay < 1) {
388 msg_data.delay = 1;
389 }
390
391 url = new_url;
392
393 /* fracpart? (ignored, as delay is integer only) */
394 while (url < end && (('0' <= *url && *url <= '9') ||
395 *url == '.')) {
396 url++;
397 }
398
399 /* *LWS */
400 while (url < end && ascii_is_space(*url)) {
401 url++;
402 }
403
404 /* ';' */
405 if (url < end && *url == ';')
406 url++;
407
408 /* *LWS */
409 while (url < end && ascii_is_space(*url)) {
410 url++;
411 }
412
413 if (url == end) {
414 /* Just delay specified, so refresh current page */
415 dom_string_unref(content);
416
417 c->base.refresh = nsurl_ref(content_get_url(&c->base));
418
419 content_broadcast(&c->base, CONTENT_MSG_REFRESH, &msg_data);
420
421 return NSERROR_OK;
422 }
423
424 /* "url" */
425 if (url <= end - 3) {
426 if (strncasecmp(url, "url", 3) == 0) {
427 url += 3;
428 } else {
429 /* Unexpected input, ignore this header */
430 dom_string_unref(content);
431 return NSERROR_OK;
432 }
433 } else {
434 /* Insufficient input, ignore this header */
435 dom_string_unref(content);
436 return NSERROR_OK;
437 }
438
439 /* *LWS */
440 while (url < end && ascii_is_space(*url)) {
441 url++;
442 }
443
444 /* '=' */
445 if (url < end) {
446 if (*url == '=') {
447 url++;
448 } else {
449 /* Unexpected input, ignore this header */
450 dom_string_unref(content);
451 return NSERROR_OK;
452 }
453 } else {
454 /* Insufficient input, ignore this header */
455 dom_string_unref(content);
456 return NSERROR_OK;
457 }
458
459 /* *LWS */
460 while (url < end && ascii_is_space(*url)) {
461 url++;
462 }
463
464 /* '"' or "'" */
465 if (url < end && (*url == '"' || *url == '\'')) {
466 quote = *url;
467 url++;
468 }
469
470 /* Start of URL */
471 refresh = url;
472
473 if (quote != 0) {
474 /* url-sq | url-dq */
475 while (url < end && *url != quote)
476 url++;
477 } else {
478 /* url-nq */
479 while (url < end && !ascii_is_space(*url))
480 url++;
481 }
482
483 /* '"' or "'" or *LWS (we don't care) */
484 if (url > refresh) {
485 /* There's a URL */
486 new_url = strndup(refresh, url - refresh);
487 if (new_url == NULL) {
488 dom_string_unref(content);
489 return NSERROR_NOMEM;
490 }
491
492 error = nsurl_join(c->base_url, new_url, &nsurl);
493 if (error == NSERROR_OK) {
494 /* broadcast valid refresh url */
495
496 c->base.refresh = nsurl;
497
498 content_broadcast(&c->base,
499 CONTENT_MSG_REFRESH,
500 &msg_data);
501 c->refresh = true;
502 }
503
504 free(new_url);
505
506 }
507
508 dom_string_unref(content);
509
510 return error;
511 }
512
513
514 /**
515 * Process title element being inserted into the DOM.
516 *
517 * https://html.spec.whatwg.org/multipage/semantics.html#the-title-element
518 *
519 * \param htmlc The html content containing the DOM
520 * \param node The DOM node being inserted
521 * \return NSERROR_OK on success else appropriate error code
522 */
html_process_inserted_title(html_content * htmlc,dom_node * node)523 static nserror html_process_inserted_title(html_content *htmlc, dom_node *node)
524 {
525 if (htmlc->title == NULL) {
526 /* only the first title is considered */
527 htmlc->title = dom_node_ref(node);
528 }
529 return NSERROR_OK;
530 }
531
532
533 /** process title node */
html_process_title(html_content * c,dom_node * node)534 static bool html_process_title(html_content *c, dom_node *node)
535 {
536 dom_exception exc; /* returned by libdom functions */
537 dom_string *title;
538 char *title_str;
539 bool success;
540
541 exc = dom_node_get_text_content(node, &title);
542 if ((exc != DOM_NO_ERR) || (title == NULL)) {
543 return false;
544 }
545
546 title_str = squash_whitespace(dom_string_data(title));
547 dom_string_unref(title);
548
549 if (title_str == NULL) {
550 return false;
551 }
552
553 success = content__set_title(&c->base, title_str);
554
555 free(title_str);
556
557 return success;
558 }
559
560
561 /**
562 * Deal with input elements being modified by resyncing their gadget
563 * if they have one.
564 */
html_texty_element_update(html_content * htmlc,dom_node * node)565 static void html_texty_element_update(html_content *htmlc, dom_node *node)
566 {
567 struct box *box = box_for_node(node);
568 if (box == NULL) {
569 return; /* No Box (yet?) so no gadget to update */
570 }
571 if (box->gadget == NULL) {
572 return; /* No gadget yet (under construction perhaps?) */
573 }
574 form_gadget_sync_with_dom(box->gadget);
575 /* And schedule a redraw for the box */
576 html__redraw_a_box(htmlc, box);
577 }
578
579
580 /**
581 * callback for DOMNodeInserted end type
582 */
583 static void
dom_default_action_DOMNodeInserted_cb(struct dom_event * evt,void * pw)584 dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw)
585 {
586 dom_event_target *node;
587 dom_node_type type;
588 dom_exception exc;
589 html_content *htmlc = pw;
590
591 exc = dom_event_get_target(evt, &node);
592 if ((exc != DOM_NO_ERR) || (node == NULL)) {
593 /* failed to obtain the event target node */
594 return;
595 }
596
597 exc = dom_node_get_node_type(node, &type);
598 if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
599 /* an element node has been inserted */
600 dom_html_element_type tag_type;
601
602 exc = dom_html_element_get_tag_type(node, &tag_type);
603 if (exc != DOM_NO_ERR) {
604 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
605 }
606
607 switch (tag_type) {
608 case DOM_HTML_ELEMENT_TYPE_BASE:
609 html_process_inserted_base(htmlc, (dom_node *)node);
610 break;
611
612 case DOM_HTML_ELEMENT_TYPE_IMG:
613 html_process_inserted_img(htmlc, (dom_node *)node);
614 break;
615
616 case DOM_HTML_ELEMENT_TYPE_LINK:
617 html_process_inserted_link(htmlc, (dom_node *)node);
618 break;
619
620 case DOM_HTML_ELEMENT_TYPE_META:
621 html_process_inserted_meta(htmlc, (dom_node *)node);
622 break;
623
624 case DOM_HTML_ELEMENT_TYPE_STYLE:
625 html_css_process_style(htmlc, (dom_node *)node);
626 break;
627
628 case DOM_HTML_ELEMENT_TYPE_SCRIPT:
629 dom_SCRIPT_showed_up(htmlc,
630 (dom_html_script_element *)node);
631 break;
632
633 case DOM_HTML_ELEMENT_TYPE_TITLE:
634 html_process_inserted_title(htmlc, (dom_node *)node);
635 break;
636
637 default:
638 break;
639 }
640
641 if (htmlc->enable_scripting) {
642 /* ensure javascript context is available */
643 if (htmlc->jsthread == NULL) {
644 union content_msg_data msg_data;
645
646 msg_data.jsthread = &htmlc->jsthread;
647 content_broadcast(&htmlc->base,
648 CONTENT_MSG_GETTHREAD,
649 &msg_data);
650 NSLOG(netsurf, INFO,
651 "javascript context: %p (htmlc: %p)",
652 htmlc->jsthread,
653 htmlc);
654 }
655 if (htmlc->jsthread != NULL) {
656 js_handle_new_element(htmlc->jsthread,
657 (dom_element *) node);
658 }
659 }
660 }
661 dom_node_unref(node);
662 }
663
664
665 /**
666 * callback for DOMNodeInsertedIntoDocument end type
667 */
668 static void
dom_default_action_DOMNodeInsertedIntoDocument_cb(struct dom_event * evt,void * pw)669 dom_default_action_DOMNodeInsertedIntoDocument_cb(struct dom_event *evt,
670 void *pw)
671 {
672 html_content *htmlc = pw;
673 dom_event_target *node;
674 dom_node_type type;
675 dom_exception exc;
676
677 exc = dom_event_get_target(evt, &node);
678 if ((exc == DOM_NO_ERR) && (node != NULL)) {
679 exc = dom_node_get_node_type(node, &type);
680 if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
681 /* an element node has been modified */
682 dom_html_element_type tag_type;
683
684 exc = dom_html_element_get_tag_type(node, &tag_type);
685 if (exc != DOM_NO_ERR) {
686 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
687 }
688
689 switch (tag_type) {
690 case DOM_HTML_ELEMENT_TYPE_SCRIPT:
691 dom_SCRIPT_showed_up(htmlc, (dom_html_script_element *) node);
692 default:
693 break;
694 }
695 }
696 dom_node_unref(node);
697 }
698 }
699
700
701 /**
702 * callback for DOMSubtreeModified end type
703 */
704 static void
dom_default_action_DOMSubtreeModified_cb(struct dom_event * evt,void * pw)705 dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
706 {
707 dom_event_target *node;
708 dom_node_type type;
709 dom_exception exc;
710 html_content *htmlc = pw;
711
712 exc = dom_event_get_target(evt, &node);
713 if ((exc == DOM_NO_ERR) && (node != NULL)) {
714 if (htmlc->title == (dom_node *)node) {
715 /* Node is our title node */
716 html_process_title(htmlc, (dom_node *)node);
717 dom_node_unref(node);
718 return;
719 }
720
721 exc = dom_node_get_node_type(node, &type);
722 if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
723 /* an element node has been modified */
724 dom_html_element_type tag_type;
725
726 exc = dom_html_element_get_tag_type(node, &tag_type);
727 if (exc != DOM_NO_ERR) {
728 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
729 }
730
731 switch (tag_type) {
732 case DOM_HTML_ELEMENT_TYPE_STYLE:
733 html_css_update_style(htmlc, (dom_node *)node);
734 break;
735 case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
736 case DOM_HTML_ELEMENT_TYPE_INPUT:
737 html_texty_element_update(htmlc, (dom_node *)node);
738 default:
739 break;
740 }
741 }
742 dom_node_unref(node);
743 }
744 }
745
746
747 /**
748 * callback for default action finished
749 */
750 static void
dom_default_action_finished_cb(struct dom_event * evt,void * pw)751 dom_default_action_finished_cb(struct dom_event *evt, void *pw)
752 {
753 html_content *htmlc = pw;
754
755 if (htmlc->jsthread != NULL)
756 js_event_cleanup(htmlc->jsthread, evt);
757 }
758
759
760 /* exported interface documented in html/dom_event.c */
761 dom_default_action_callback
html_dom_event_fetcher(dom_string * type,dom_default_action_phase phase,void ** pw)762 html_dom_event_fetcher(dom_string *type,
763 dom_default_action_phase phase,
764 void **pw)
765 {
766 NSLOG(netsurf, DEEPDEBUG,
767 "phase:%d type:%s", phase, dom_string_data(type));
768
769 if (phase == DOM_DEFAULT_ACTION_END) {
770 if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) {
771 return dom_default_action_DOMNodeInserted_cb;
772 } else if (dom_string_isequal(type, corestring_dom_DOMNodeInsertedIntoDocument)) {
773 return dom_default_action_DOMNodeInsertedIntoDocument_cb;
774 } else if (dom_string_isequal(type, corestring_dom_DOMSubtreeModified)) {
775 return dom_default_action_DOMSubtreeModified_cb;
776 }
777 } else if (phase == DOM_DEFAULT_ACTION_FINISHED) {
778 return dom_default_action_finished_cb;
779 }
780 return NULL;
781 }
782