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