mshtml: Don't check if script element was already parsed in doc_insert_script.
[wine] / dlls / mshtml / mutation.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "ole2.h"
30 #include "shlguid.h"
31
32 #include "mshtml_private.h"
33 #include "htmlscript.h"
34 #include "htmlevent.h"
35 #include "binding.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 #define IE_MAJOR_VERSION 7
42 #define IE_MINOR_VERSION 0
43
44 static const IID NS_ICONTENTUTILS_CID =
45     {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
46
47 static nsIContentUtils *content_utils;
48
49 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
50 {
51     int majorv = 0, minorv = 0;
52     const PRUnichar *ptr, *end;
53     PRUnichar *buf;
54     DWORD len;
55
56     enum {
57         CMP_EQ,
58         CMP_LT,
59         CMP_LTE,
60         CMP_GT,
61         CMP_GTE
62     } cmpt = CMP_EQ;
63
64     static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
65
66     if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
67         return NULL;
68
69     ptr = comment+3;
70     while(isspaceW(*ptr))
71         ptr++;
72
73     if(ptr[0] == 'l' && ptr[1] == 't') {
74         ptr += 2;
75         if(*ptr == 'e') {
76             cmpt = CMP_LTE;
77             ptr++;
78         }else {
79             cmpt = CMP_LT;
80         }
81     }else if(ptr[0] == 'g' && ptr[1] == 't') {
82         ptr += 2;
83         if(*ptr == 'e') {
84             cmpt = CMP_GTE;
85             ptr++;
86         }else {
87             cmpt = CMP_GT;
88         }
89     }
90
91     if(!isspaceW(*ptr++))
92         return NULL;
93     while(isspaceW(*ptr))
94         ptr++;
95
96     if(ptr[0] != 'I' || ptr[1] != 'E')
97         return NULL;
98
99     ptr +=2;
100     if(!isspaceW(*ptr++))
101         return NULL;
102     while(isspaceW(*ptr))
103         ptr++;
104
105     if(!isdigitW(*ptr))
106         return NULL;
107     while(isdigitW(*ptr))
108         majorv = majorv*10 + (*ptr++ - '0');
109
110     if(*ptr == '.') {
111         ptr++;
112         if(!isdigitW(*ptr))
113             return NULL;
114         while(isdigitW(*ptr))
115             minorv = minorv*10 + (*ptr++ - '0');
116     }
117
118     while(isspaceW(*ptr))
119         ptr++;
120     if(ptr[0] != ']' || ptr[1] != '>')
121         return NULL;
122     ptr += 2;
123
124     len = strlenW(ptr);
125     if(len < sizeof(endifW)/sizeof(WCHAR))
126         return NULL;
127
128     end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
129     if(memcmp(end, endifW, sizeof(endifW)))
130         return NULL;
131
132     switch(cmpt) {
133     case CMP_EQ:
134         if(majorv == IE_MAJOR_VERSION && minorv == IE_MINOR_VERSION)
135             break;
136         return NULL;
137     case CMP_LT:
138         if(majorv > IE_MAJOR_VERSION)
139             break;
140         if(majorv == IE_MAJOR_VERSION && minorv > IE_MINOR_VERSION)
141             break;
142         return NULL;
143     case CMP_LTE:
144         if(majorv > IE_MAJOR_VERSION)
145             break;
146         if(majorv == IE_MAJOR_VERSION && minorv >= IE_MINOR_VERSION)
147             break;
148         return NULL;
149     case CMP_GT:
150         if(majorv < IE_MAJOR_VERSION)
151             break;
152         if(majorv == IE_MAJOR_VERSION && minorv < IE_MINOR_VERSION)
153             break;
154         return NULL;
155     case CMP_GTE:
156         if(majorv < IE_MAJOR_VERSION)
157             break;
158         if(majorv == IE_MAJOR_VERSION && minorv <= IE_MINOR_VERSION)
159             break;
160         return NULL;
161     }
162
163     buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
164     if(!buf)
165         return NULL;
166
167     memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
168     buf[end-ptr] = 0;
169
170     return buf;
171 }
172
173 static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
174 {
175     const PRUnichar *comment;
176     nsIDOMComment *nscomment;
177     PRUnichar *replace_html;
178     nsAString comment_str;
179     nsresult nsres;
180
181     nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
182     if(NS_FAILED(nsres)) {
183         ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
184         return nsres;
185     }
186
187     nsAString_Init(&comment_str, NULL);
188     nsres = nsIDOMComment_GetData(nscomment, &comment_str);
189     if(NS_FAILED(nsres))
190         return nsres;
191
192     nsAString_GetData(&comment_str, &comment);
193     replace_html = handle_insert_comment(doc, comment);
194     nsAString_Finish(&comment_str);
195
196     if(replace_html) {
197         HRESULT hres;
198
199         hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
200         heap_free(replace_html);
201         if(FAILED(hres))
202             nsres = NS_ERROR_FAILURE;
203     }
204
205
206     nsIDOMComment_Release(nscomment);
207     return nsres;
208 }
209
210 static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
211 {
212     nsIDOMNode *nsnode;
213     HTMLDOMNode *node;
214     nsresult nsres;
215     HRESULT hres;
216
217     TRACE("(%p)->(%p)\n", doc, nsiface);
218
219     nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
220     if(NS_FAILED(nsres))
221         return nsres;
222
223     hres = get_node(doc, nsnode, TRUE, &node);
224     nsIDOMNode_Release(nsnode);
225     if(FAILED(hres)) {
226         ERR("Could not get node\n");
227         return nsres;
228     }
229
230     if(node->vtbl->bind_to_tree)
231         node->vtbl->bind_to_tree(node);
232
233     node_release(node);
234     return nsres;
235 }
236
237 /* Calls undocumented 69 cmd of CGID_Explorer */
238 static void call_explorer_69(HTMLDocumentObj *doc)
239 {
240     IOleCommandTarget *olecmd;
241     VARIANT var;
242     HRESULT hres;
243
244     if(!doc->client)
245         return;
246
247     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
248     if(FAILED(hres))
249         return;
250
251     VariantInit(&var);
252     hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
253     IOleCommandTarget_Release(olecmd);
254     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
255         FIXME("handle result\n");
256 }
257
258 static void parse_complete(HTMLDocumentObj *doc)
259 {
260     TRACE("(%p)\n", doc);
261
262     if(doc->usermode == EDITMODE)
263         init_editor(&doc->basedoc);
264
265     call_explorer_69(doc);
266     if(doc->view_sink)
267         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
268     call_property_onchanged(&doc->basedoc.cp_propnotif, 1005);
269     call_explorer_69(doc);
270
271     if(doc->is_webbrowser && doc->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
272         IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
273
274     /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
275 }
276
277 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
278 {
279     TRACE("(%p)\n", This);
280
281     if(!This->basedoc.doc_obj)
282         return NS_OK;
283
284     if(This == This->basedoc.doc_obj->basedoc.doc_node) {
285         /*
286          * This should be done in the worker thread that parses HTML,
287          * but we don't have such thread (Gecko parses HTML for us).
288          */
289         parse_complete(This->basedoc.doc_obj);
290     }
291
292     bind_event_scripts(This);
293     set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
294     return NS_OK;
295 }
296
297 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
298 {
299     nsIDOMHTMLScriptElement *nsscript;
300     HTMLScriptElement *script_elem;
301     nsIParser *nsparser = NULL;
302     script_queue_entry_t *iter;
303     HTMLInnerWindow *window;
304     nsresult nsres;
305     HRESULT hres;
306
307     TRACE("(%p)->(%p)\n", doc, script_iface);
308
309     window = doc->window;
310     if(!window)
311         return NS_OK;
312
313     nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
314     if(NS_FAILED(nsres)) {
315         ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
316         return nsres;
317     }
318
319     if(parser_iface) {
320         nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
321         if(NS_FAILED(nsres)) {
322             ERR("Could not get nsIParser iface: %08x\n", nsres);
323             nsparser = NULL;
324         }
325     }
326
327     hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
328     nsIDOMHTMLScriptElement_Release(nsscript);
329     if(FAILED(hres))
330         return NS_ERROR_FAILURE;
331
332     if(nsparser) {
333         nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
334         window->parser_callback_cnt++;
335     }
336
337     IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
338
339     doc_insert_script(window, script_elem);
340
341     while(!list_empty(&window->script_queue)) {
342         iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
343         list_remove(&iter->entry);
344         if(!iter->script->parsed)
345             doc_insert_script(window, iter->script);
346         IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
347         heap_free(iter);
348     }
349
350     IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
351
352     if(nsparser) {
353         window->parser_callback_cnt--;
354         nsIParser_EndEvaluatingParserInsertedScript(nsparser);
355         nsIParser_Release(nsparser);
356     }
357
358     IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
359
360     return NS_OK;
361 }
362
363 typedef struct nsRunnable nsRunnable;
364
365 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
366
367 struct nsRunnable {
368     nsIRunnable  nsIRunnable_iface;
369
370     LONG ref;
371
372     runnable_proc_t proc;
373
374     HTMLDocumentNode *doc;
375     nsISupports *arg1;
376     nsISupports *arg2;
377 };
378
379 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
380 {
381     return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
382 }
383
384 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
385         nsIIDRef riid, void **result)
386 {
387     nsRunnable *This = impl_from_nsIRunnable(iface);
388
389     if(IsEqualGUID(riid, &IID_nsISupports)) {
390         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
391         *result = &This->nsIRunnable_iface;
392     }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
393         TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
394         *result = &This->nsIRunnable_iface;
395     }else {
396         *result = NULL;
397         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
398         return NS_NOINTERFACE;
399     }
400
401     nsISupports_AddRef((nsISupports*)*result);
402     return NS_OK;
403 }
404
405 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
406 {
407     nsRunnable *This = impl_from_nsIRunnable(iface);
408     LONG ref = InterlockedIncrement(&This->ref);
409
410     TRACE("(%p) ref=%d\n", This, ref);
411
412     return ref;
413 }
414
415 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
416 {
417     nsRunnable *This = impl_from_nsIRunnable(iface);
418     LONG ref = InterlockedDecrement(&This->ref);
419
420     TRACE("(%p) ref=%d\n", This, ref);
421
422     if(!ref) {
423         htmldoc_release(&This->doc->basedoc);
424         if(This->arg1)
425             nsISupports_Release(This->arg1);
426         if(This->arg2)
427             nsISupports_Release(This->arg2);
428         heap_free(This);
429     }
430
431     return ref;
432 }
433
434 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
435 {
436     nsRunnable *This = impl_from_nsIRunnable(iface);
437
438     return This->proc(This->doc, This->arg1, This->arg2);
439 }
440
441 static const nsIRunnableVtbl nsRunnableVtbl = {
442     nsRunnable_QueryInterface,
443     nsRunnable_AddRef,
444     nsRunnable_Release,
445     nsRunnable_Run
446 };
447
448 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
449 {
450     nsRunnable *runnable;
451
452     runnable = heap_alloc_zero(sizeof(*runnable));
453     if(!runnable)
454         return;
455
456     runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
457     runnable->ref = 1;
458
459     htmldoc_addref(&This->basedoc);
460     runnable->doc = This;
461     runnable->proc = proc;
462
463     if(arg1)
464         nsISupports_AddRef(arg1);
465     runnable->arg1 = arg1;
466
467     if(arg2)
468         nsISupports_AddRef(arg2);
469     runnable->arg2 = arg2;
470
471     nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
472
473     nsIRunnable_Release(&runnable->nsIRunnable_iface);
474 }
475
476 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
477 {
478     return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
479 }
480
481 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
482         nsIIDRef riid, void **result)
483 {
484     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
485
486     if(IsEqualGUID(&IID_nsISupports, riid)) {
487         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
488         *result = &This->nsIDocumentObserver_iface;
489     }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
490         TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
491         *result = &This->nsIDocumentObserver_iface;
492     }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
493         TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
494         *result = &This->nsIDocumentObserver_iface;
495     }else {
496         *result = NULL;
497         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
498         return NS_NOINTERFACE;
499     }
500
501     htmldoc_addref(&This->basedoc);
502     return NS_OK;
503 }
504
505 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
506 {
507     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
508     return htmldoc_addref(&This->basedoc);
509 }
510
511 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
512 {
513     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
514     return htmldoc_release(&This->basedoc);
515 }
516
517 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
518         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
519 {
520 }
521
522 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
523         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
524 {
525 }
526
527 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
528         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
529 {
530 }
531
532 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
533         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
534 {
535 }
536
537 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
538         void *aElement, PRInt32 aNameSpaceID, nsIAtom *aAttribute)
539 {
540 }
541
542 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
543         nsIContent *aContainer, nsIContent *aFirstNewContent, PRInt32 aNewIndexInContainer)
544 {
545 }
546
547 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
548         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
549 {
550 }
551
552 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
553         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer,
554         nsIContent *aProviousSibling)
555 {
556 }
557
558 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
559 {
560 }
561
562 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
563 {
564 }
565
566 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
567         nsUpdateType aUpdateType)
568 {
569 }
570
571 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
572         nsUpdateType aUpdateType)
573 {
574 }
575
576 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
577 {
578 }
579
580 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
581 {
582     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
583
584     TRACE("(%p)\n", This);
585
586     if(This->skip_mutation_notif)
587         return;
588
589     This->content_ready = TRUE;
590     add_script_runner(This, run_end_load, NULL, NULL);
591 }
592
593 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
594         nsIContent *aContent, nsEventStates *aStateMask)
595 {
596 }
597
598 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
599         nsEventStates *aStateMask)
600 {
601 }
602
603 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
604         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
605 {
606 }
607
608 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
609         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
610 {
611 }
612
613 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
614         nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, cpp_bool aApplicable)
615 {
616 }
617
618 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
619         nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
620 {
621 }
622
623 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
624         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
625 {
626 }
627
628 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
629         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
630 {
631 }
632
633 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
634         nsIContent *aContent)
635 {
636     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
637     nsIDOMHTMLIFrameElement *nsiframe;
638     nsIDOMHTMLFrameElement *nsframe;
639     nsIDOMHTMLScriptElement *nsscript;
640     nsIDOMComment *nscomment;
641     nsIDOMElement *nselem;
642     nsresult nsres;
643
644     TRACE("(%p)\n", This);
645
646     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
647     if(NS_SUCCEEDED(nsres)) {
648         check_event_attr(This, nselem);
649         nsIDOMElement_Release(nselem);
650     }
651
652     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
653     if(NS_SUCCEEDED(nsres)) {
654         TRACE("comment node\n");
655
656         add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
657         nsIDOMComment_Release(nscomment);
658         return;
659     }
660
661     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
662     if(NS_SUCCEEDED(nsres)) {
663         TRACE("iframe node\n");
664
665         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
666         nsIDOMHTMLIFrameElement_Release(nsiframe);
667         return;
668     }
669
670     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
671     if(NS_SUCCEEDED(nsres)) {
672         TRACE("frame node\n");
673
674         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
675         nsIDOMHTMLFrameElement_Release(nsframe);
676         return;
677     }
678
679     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
680     if(NS_SUCCEEDED(nsres)) {
681         HTMLScriptElement *script_elem;
682         HRESULT hres;
683
684         TRACE("script element\n");
685
686         hres = script_elem_from_nsscript(This, nsscript, &script_elem);
687         nsIDOMHTMLScriptElement_Release(nsscript);
688         if(FAILED(hres))
689             return;
690
691         if(script_elem->parse_on_bind)
692             add_script_runner(This, run_insert_script, (nsISupports*)nsscript, NULL);
693
694         IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
695     }
696 }
697
698 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
699         nsIParser *aParser, cpp_bool *aBlock)
700 {
701     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
702     nsIDOMHTMLScriptElement *nsscript;
703     nsresult nsres;
704
705     TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
706
707     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
708     if(NS_SUCCEEDED(nsres)) {
709         TRACE("script node\n");
710
711         add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
712         nsIDOMHTMLScriptElement_Release(nsscript);
713     }
714 }
715
716 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
717     nsDocumentObserver_QueryInterface,
718     nsDocumentObserver_AddRef,
719     nsDocumentObserver_Release,
720     nsDocumentObserver_CharacterDataWillChange,
721     nsDocumentObserver_CharacterDataChanged,
722     nsDocumentObserver_AttributeWillChange,
723     nsDocumentObserver_AttributeChanged,
724     nsDocumentObserver_AttributeSetToCurrentValue,
725     nsDocumentObserver_ContentAppended,
726     nsDocumentObserver_ContentInserted,
727     nsDocumentObserver_ContentRemoved,
728     nsDocumentObserver_NodeWillBeDestroyed,
729     nsDocumentObserver_ParentChainChanged,
730     nsDocumentObserver_BeginUpdate,
731     nsDocumentObserver_EndUpdate,
732     nsDocumentObserver_BeginLoad,
733     nsDocumentObserver_EndLoad,
734     nsDocumentObserver_ContentStatesChanged,
735     nsDocumentObserver_DocumentStatesChanged,
736     nsDocumentObserver_StyleSheetAdded,
737     nsDocumentObserver_StyleSheetRemoved,
738     nsDocumentObserver_StyleSheetApplicableStateChanged,
739     nsDocumentObserver_StyleRuleChanged,
740     nsDocumentObserver_StyleRuleAdded,
741     nsDocumentObserver_StyleRuleRemoved,
742     nsDocumentObserver_BindToDocument,
743     nsDocumentObserver_AttemptToExecuteScript
744 };
745
746 void init_document_mutation(HTMLDocumentNode *doc)
747 {
748     nsIDocument *nsdoc;
749     nsresult nsres;
750
751     doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
752
753     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
754     if(NS_FAILED(nsres)) {
755         ERR("Could not get nsIDocument: %08x\n", nsres);
756         return;
757     }
758
759     nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
760     nsIDocument_Release(nsdoc);
761 }
762
763 void release_document_mutation(HTMLDocumentNode *doc)
764 {
765     nsIDocument *nsdoc;
766     nsresult nsres;
767
768     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
769     if(NS_FAILED(nsres)) {
770         ERR("Could not get nsIDocument: %08x\n", nsres);
771         return;
772     }
773
774     nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
775     nsIDocument_Release(nsdoc);
776 }
777
778 void init_mutation(nsIComponentManager *component_manager)
779 {
780     nsIFactory *factory;
781     nsresult nsres;
782
783     if(!component_manager) {
784         if(content_utils) {
785             nsIContentUtils_Release(content_utils);
786             content_utils = NULL;
787         }
788         return;
789     }
790
791     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
792             &IID_nsIFactory, (void**)&factory);
793     if(NS_FAILED(nsres)) {
794         ERR("Could not create nsIContentUtils service: %08x\n", nsres);
795         return;
796     }
797
798     nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
799     nsIFactory_Release(factory);
800     if(NS_FAILED(nsres))
801         ERR("Could not create nsIContentUtils instance: %08x\n", nsres);
802 }