qcap: Fix compilation on older systems.
[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         doc_insert_script(window, iter->script);
345         IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
346         heap_free(iter);
347     }
348
349     IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
350
351     if(nsparser) {
352         window->parser_callback_cnt--;
353         nsIParser_EndEvaluatingParserInsertedScript(nsparser);
354         nsIParser_Release(nsparser);
355     }
356
357     IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
358
359     return NS_OK;
360 }
361
362 typedef struct nsRunnable nsRunnable;
363
364 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
365
366 struct nsRunnable {
367     nsIRunnable  nsIRunnable_iface;
368
369     LONG ref;
370
371     runnable_proc_t proc;
372
373     HTMLDocumentNode *doc;
374     nsISupports *arg1;
375     nsISupports *arg2;
376 };
377
378 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
379 {
380     return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
381 }
382
383 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
384         nsIIDRef riid, void **result)
385 {
386     nsRunnable *This = impl_from_nsIRunnable(iface);
387
388     if(IsEqualGUID(riid, &IID_nsISupports)) {
389         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
390         *result = &This->nsIRunnable_iface;
391     }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
392         TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
393         *result = &This->nsIRunnable_iface;
394     }else {
395         *result = NULL;
396         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
397         return NS_NOINTERFACE;
398     }
399
400     nsISupports_AddRef((nsISupports*)*result);
401     return NS_OK;
402 }
403
404 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
405 {
406     nsRunnable *This = impl_from_nsIRunnable(iface);
407     LONG ref = InterlockedIncrement(&This->ref);
408
409     TRACE("(%p) ref=%d\n", This, ref);
410
411     return ref;
412 }
413
414 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
415 {
416     nsRunnable *This = impl_from_nsIRunnable(iface);
417     LONG ref = InterlockedDecrement(&This->ref);
418
419     TRACE("(%p) ref=%d\n", This, ref);
420
421     if(!ref) {
422         htmldoc_release(&This->doc->basedoc);
423         if(This->arg1)
424             nsISupports_Release(This->arg1);
425         if(This->arg2)
426             nsISupports_Release(This->arg2);
427         heap_free(This);
428     }
429
430     return ref;
431 }
432
433 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
434 {
435     nsRunnable *This = impl_from_nsIRunnable(iface);
436
437     return This->proc(This->doc, This->arg1, This->arg2);
438 }
439
440 static const nsIRunnableVtbl nsRunnableVtbl = {
441     nsRunnable_QueryInterface,
442     nsRunnable_AddRef,
443     nsRunnable_Release,
444     nsRunnable_Run
445 };
446
447 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
448 {
449     nsRunnable *runnable;
450
451     runnable = heap_alloc_zero(sizeof(*runnable));
452     if(!runnable)
453         return;
454
455     runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
456     runnable->ref = 1;
457
458     htmldoc_addref(&This->basedoc);
459     runnable->doc = This;
460     runnable->proc = proc;
461
462     if(arg1)
463         nsISupports_AddRef(arg1);
464     runnable->arg1 = arg1;
465
466     if(arg2)
467         nsISupports_AddRef(arg2);
468     runnable->arg2 = arg2;
469
470     nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
471
472     nsIRunnable_Release(&runnable->nsIRunnable_iface);
473 }
474
475 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
476 {
477     return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
478 }
479
480 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
481         nsIIDRef riid, void **result)
482 {
483     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
484
485     if(IsEqualGUID(&IID_nsISupports, riid)) {
486         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
487         *result = &This->nsIDocumentObserver_iface;
488     }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
489         TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
490         *result = &This->nsIDocumentObserver_iface;
491     }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
492         TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
493         *result = &This->nsIDocumentObserver_iface;
494     }else {
495         *result = NULL;
496         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
497         return NS_NOINTERFACE;
498     }
499
500     htmldoc_addref(&This->basedoc);
501     return NS_OK;
502 }
503
504 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
505 {
506     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
507     return htmldoc_addref(&This->basedoc);
508 }
509
510 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
511 {
512     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
513     return htmldoc_release(&This->basedoc);
514 }
515
516 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
517         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
518 {
519 }
520
521 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
522         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
523 {
524 }
525
526 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
527         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
528 {
529 }
530
531 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
532         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
533 {
534 }
535
536 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
537         void *aElement, PRInt32 aNameSpaceID, nsIAtom *aAttribute)
538 {
539 }
540
541 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
542         nsIContent *aContainer, nsIContent *aFirstNewContent, PRInt32 aNewIndexInContainer)
543 {
544 }
545
546 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
547         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
548 {
549 }
550
551 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
552         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer,
553         nsIContent *aProviousSibling)
554 {
555 }
556
557 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
558 {
559 }
560
561 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
562 {
563 }
564
565 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
566         nsUpdateType aUpdateType)
567 {
568 }
569
570 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
571         nsUpdateType aUpdateType)
572 {
573 }
574
575 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
576 {
577 }
578
579 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
580 {
581     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
582
583     TRACE("(%p)\n", This);
584
585     if(This->skip_mutation_notif)
586         return;
587
588     This->content_ready = TRUE;
589     add_script_runner(This, run_end_load, NULL, NULL);
590 }
591
592 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
593         nsIContent *aContent, nsEventStates *aStateMask)
594 {
595 }
596
597 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
598         nsEventStates *aStateMask)
599 {
600 }
601
602 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
603         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
604 {
605 }
606
607 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
608         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
609 {
610 }
611
612 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
613         nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, cpp_bool aApplicable)
614 {
615 }
616
617 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
618         nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
619 {
620 }
621
622 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
623         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
624 {
625 }
626
627 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
628         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
629 {
630 }
631
632 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
633         nsIContent *aContent)
634 {
635     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
636     nsIDOMHTMLIFrameElement *nsiframe;
637     nsIDOMHTMLFrameElement *nsframe;
638     nsIDOMHTMLScriptElement *nsscript;
639     nsIDOMComment *nscomment;
640     nsIDOMElement *nselem;
641     nsresult nsres;
642
643     TRACE("(%p)\n", This);
644
645     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
646     if(NS_SUCCEEDED(nsres)) {
647         check_event_attr(This, nselem);
648         nsIDOMElement_Release(nselem);
649     }
650
651     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
652     if(NS_SUCCEEDED(nsres)) {
653         TRACE("comment node\n");
654
655         add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
656         nsIDOMComment_Release(nscomment);
657         return;
658     }
659
660     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
661     if(NS_SUCCEEDED(nsres)) {
662         TRACE("iframe node\n");
663
664         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
665         nsIDOMHTMLIFrameElement_Release(nsiframe);
666         return;
667     }
668
669     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
670     if(NS_SUCCEEDED(nsres)) {
671         TRACE("frame node\n");
672
673         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
674         nsIDOMHTMLFrameElement_Release(nsframe);
675         return;
676     }
677
678     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
679     if(NS_SUCCEEDED(nsres)) {
680         HTMLScriptElement *script_elem;
681         HRESULT hres;
682
683         TRACE("script element\n");
684
685         hres = script_elem_from_nsscript(This, nsscript, &script_elem);
686         nsIDOMHTMLScriptElement_Release(nsscript);
687         if(FAILED(hres))
688             return;
689
690         if(script_elem->parse_on_bind)
691             add_script_runner(This, run_insert_script, (nsISupports*)nsscript, NULL);
692
693         IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
694     }
695 }
696
697 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
698         nsIParser *aParser, cpp_bool *aBlock)
699 {
700     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
701     nsIDOMHTMLScriptElement *nsscript;
702     nsresult nsres;
703
704     TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
705
706     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
707     if(NS_SUCCEEDED(nsres)) {
708         TRACE("script node\n");
709
710         add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
711         nsIDOMHTMLScriptElement_Release(nsscript);
712     }
713 }
714
715 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
716     nsDocumentObserver_QueryInterface,
717     nsDocumentObserver_AddRef,
718     nsDocumentObserver_Release,
719     nsDocumentObserver_CharacterDataWillChange,
720     nsDocumentObserver_CharacterDataChanged,
721     nsDocumentObserver_AttributeWillChange,
722     nsDocumentObserver_AttributeChanged,
723     nsDocumentObserver_AttributeSetToCurrentValue,
724     nsDocumentObserver_ContentAppended,
725     nsDocumentObserver_ContentInserted,
726     nsDocumentObserver_ContentRemoved,
727     nsDocumentObserver_NodeWillBeDestroyed,
728     nsDocumentObserver_ParentChainChanged,
729     nsDocumentObserver_BeginUpdate,
730     nsDocumentObserver_EndUpdate,
731     nsDocumentObserver_BeginLoad,
732     nsDocumentObserver_EndLoad,
733     nsDocumentObserver_ContentStatesChanged,
734     nsDocumentObserver_DocumentStatesChanged,
735     nsDocumentObserver_StyleSheetAdded,
736     nsDocumentObserver_StyleSheetRemoved,
737     nsDocumentObserver_StyleSheetApplicableStateChanged,
738     nsDocumentObserver_StyleRuleChanged,
739     nsDocumentObserver_StyleRuleAdded,
740     nsDocumentObserver_StyleRuleRemoved,
741     nsDocumentObserver_BindToDocument,
742     nsDocumentObserver_AttemptToExecuteScript
743 };
744
745 void init_document_mutation(HTMLDocumentNode *doc)
746 {
747     nsIDocument *nsdoc;
748     nsresult nsres;
749
750     doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
751
752     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
753     if(NS_FAILED(nsres)) {
754         ERR("Could not get nsIDocument: %08x\n", nsres);
755         return;
756     }
757
758     nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
759     nsIDocument_Release(nsdoc);
760 }
761
762 void release_document_mutation(HTMLDocumentNode *doc)
763 {
764     nsIDocument *nsdoc;
765     nsresult nsres;
766
767     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
768     if(NS_FAILED(nsres)) {
769         ERR("Could not get nsIDocument: %08x\n", nsres);
770         return;
771     }
772
773     nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
774     nsIDocument_Release(nsdoc);
775 }
776
777 void init_mutation(nsIComponentManager *component_manager)
778 {
779     nsIFactory *factory;
780     nsresult nsres;
781
782     if(!component_manager) {
783         if(content_utils) {
784             nsIContentUtils_Release(content_utils);
785             content_utils = NULL;
786         }
787         return;
788     }
789
790     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
791             &IID_nsIFactory, (void**)&factory);
792     if(NS_FAILED(nsres)) {
793         ERR("Could not create nsIContentUtils service: %08x\n", nsres);
794         return;
795     }
796
797     nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
798     nsIFactory_Release(factory);
799     if(NS_FAILED(nsres))
800         ERR("Could not create nsIContentUtils instance: %08x\n", nsres);
801 }