mshtml: Added noscript tag handling tests.
[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     node_release(node);
232     return nsres;
233 }
234
235 /* Calls undocumented 69 cmd of CGID_Explorer */
236 static void call_explorer_69(HTMLDocumentObj *doc)
237 {
238     IOleCommandTarget *olecmd;
239     VARIANT var;
240     HRESULT hres;
241
242     if(!doc->client)
243         return;
244
245     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
246     if(FAILED(hres))
247         return;
248
249     VariantInit(&var);
250     hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
251     IOleCommandTarget_Release(olecmd);
252     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
253         FIXME("handle result\n");
254 }
255
256 static void parse_complete(HTMLDocumentObj *doc)
257 {
258     TRACE("(%p)\n", doc);
259
260     if(doc->usermode == EDITMODE)
261         init_editor(&doc->basedoc);
262
263     call_explorer_69(doc);
264     if(doc->view_sink)
265         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
266     call_property_onchanged(&doc->basedoc.cp_propnotif, 1005);
267     call_explorer_69(doc);
268
269     if(doc->is_webbrowser && doc->usermode != EDITMODE)
270         IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
271
272     /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
273 }
274
275 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
276 {
277     TRACE("(%p)\n", This);
278
279     if(!This->basedoc.doc_obj)
280         return NS_OK;
281
282     if(This == This->basedoc.doc_obj->basedoc.doc_node) {
283         /*
284          * This should be done in the worker thread that parses HTML,
285          * but we don't have such thread (Gecko parses HTML for us).
286          */
287         parse_complete(This->basedoc.doc_obj);
288     }
289
290     bind_event_scripts(This);
291     set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
292     return NS_OK;
293 }
294
295 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
296 {
297     nsIDOMHTMLScriptElement *nsscript;
298     HTMLScriptElement *script_elem;
299     nsIParser *nsparser = NULL;
300     nsresult nsres;
301     HRESULT hres;
302
303     TRACE("(%p)->(%p)\n", doc, script_iface);
304
305     nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
306     if(NS_FAILED(nsres)) {
307         ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
308         return nsres;
309     }
310
311     if(parser_iface) {
312         nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
313         if(NS_FAILED(nsres)) {
314             ERR("Could not get nsIParser iface: %08x\n", nsres);
315             nsparser = NULL;
316         }
317     }
318
319     hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
320     nsIDOMHTMLScriptElement_Release(nsscript);
321     if(FAILED(hres))
322         return NS_ERROR_FAILURE;
323
324     if(nsparser)
325         nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
326
327     doc_insert_script(doc->window, script_elem);
328
329     if(nsparser) {
330         nsIParser_EndEvaluatingParserInsertedScript(nsparser);
331         nsIParser_Release(nsparser);
332     }
333
334     IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
335     return NS_OK;
336 }
337
338 typedef struct nsRunnable nsRunnable;
339
340 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
341
342 struct nsRunnable {
343     nsIRunnable  nsIRunnable_iface;
344
345     LONG ref;
346
347     runnable_proc_t proc;
348
349     HTMLDocumentNode *doc;
350     nsISupports *arg1;
351     nsISupports *arg2;
352 };
353
354 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
355 {
356     return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
357 }
358
359 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
360         nsIIDRef riid, void **result)
361 {
362     nsRunnable *This = impl_from_nsIRunnable(iface);
363
364     if(IsEqualGUID(riid, &IID_nsISupports)) {
365         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
366         *result = &This->nsIRunnable_iface;
367     }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
368         TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
369         *result = &This->nsIRunnable_iface;
370     }else {
371         *result = NULL;
372         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
373         return NS_NOINTERFACE;
374     }
375
376     nsISupports_AddRef((nsISupports*)*result);
377     return NS_OK;
378 }
379
380 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
381 {
382     nsRunnable *This = impl_from_nsIRunnable(iface);
383     LONG ref = InterlockedIncrement(&This->ref);
384
385     TRACE("(%p) ref=%d\n", This, ref);
386
387     return ref;
388 }
389
390 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
391 {
392     nsRunnable *This = impl_from_nsIRunnable(iface);
393     LONG ref = InterlockedDecrement(&This->ref);
394
395     TRACE("(%p) ref=%d\n", This, ref);
396
397     if(!ref) {
398         htmldoc_release(&This->doc->basedoc);
399         if(This->arg1)
400             nsISupports_Release(This->arg1);
401         if(This->arg2)
402             nsISupports_Release(This->arg2);
403         heap_free(This);
404     }
405
406     return ref;
407 }
408
409 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
410 {
411     nsRunnable *This = impl_from_nsIRunnable(iface);
412
413     return This->proc(This->doc, This->arg1, This->arg2);
414 }
415
416 static const nsIRunnableVtbl nsRunnableVtbl = {
417     nsRunnable_QueryInterface,
418     nsRunnable_AddRef,
419     nsRunnable_Release,
420     nsRunnable_Run
421 };
422
423 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
424 {
425     nsRunnable *runnable;
426
427     runnable = heap_alloc_zero(sizeof(*runnable));
428     if(!runnable)
429         return;
430
431     runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
432     runnable->ref = 1;
433
434     htmldoc_addref(&This->basedoc);
435     runnable->doc = This;
436     runnable->proc = proc;
437
438     if(arg1)
439         nsISupports_AddRef(arg1);
440     runnable->arg1 = arg1;
441
442     if(arg2)
443         nsISupports_AddRef(arg2);
444     runnable->arg2 = arg2;
445
446     nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
447
448     nsIRunnable_Release(&runnable->nsIRunnable_iface);
449 }
450
451 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
452 {
453     return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
454 }
455
456 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
457         nsIIDRef riid, void **result)
458 {
459     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
460
461     if(IsEqualGUID(&IID_nsISupports, riid)) {
462         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
463         *result = &This->nsIDocumentObserver_iface;
464     }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
465         TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
466         *result = &This->nsIDocumentObserver_iface;
467     }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
468         TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
469         *result = &This->nsIDocumentObserver_iface;
470     }else {
471         *result = NULL;
472         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
473         return NS_NOINTERFACE;
474     }
475
476     htmldoc_addref(&This->basedoc);
477     return NS_OK;
478 }
479
480 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
481 {
482     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
483     return htmldoc_addref(&This->basedoc);
484 }
485
486 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
487 {
488     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
489     return htmldoc_release(&This->basedoc);
490 }
491
492 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
493         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
494 {
495 }
496
497 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
498         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
499 {
500 }
501
502 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
503         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
504 {
505 }
506
507 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
508         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
509 {
510 }
511
512 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
513         nsIContent *aContainer, nsIContent *aFirstNewContent, PRInt32 aNewIndexInContainer)
514 {
515 }
516
517 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
518         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
519 {
520 }
521
522 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
523         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer,
524         nsIContent *aProviousSibling)
525 {
526 }
527
528 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
529 {
530 }
531
532 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
533 {
534 }
535
536 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
537         nsUpdateType aUpdateType)
538 {
539 }
540
541 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
542         nsUpdateType aUpdateType)
543 {
544 }
545
546 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
547 {
548 }
549
550 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
551 {
552     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
553
554     TRACE("(%p)\n", This);
555
556     if(This->skip_mutation_notif)
557         return;
558
559     This->content_ready = TRUE;
560     add_script_runner(This, run_end_load, NULL, NULL);
561 }
562
563 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
564         nsIContent *aContent, nsEventStates *aStateMask)
565 {
566 }
567
568 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
569         nsEventStates *aStateMask)
570 {
571 }
572
573 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
574         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
575 {
576 }
577
578 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
579         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
580 {
581 }
582
583 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
584         nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, cpp_bool aApplicable)
585 {
586 }
587
588 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
589         nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
590 {
591 }
592
593 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
594         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
595 {
596 }
597
598 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
599         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
600 {
601 }
602
603 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
604         nsIContent *aContent)
605 {
606     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
607     nsIDOMHTMLIFrameElement *nsiframe;
608     nsIDOMHTMLFrameElement *nsframe;
609     nsIDOMComment *nscomment;
610     nsIDOMElement *nselem;
611     nsresult nsres;
612
613     TRACE("(%p)\n", This);
614
615     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
616     if(NS_SUCCEEDED(nsres)) {
617         check_event_attr(This, nselem);
618         nsIDOMElement_Release(nselem);
619     }
620
621     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
622     if(NS_SUCCEEDED(nsres)) {
623         TRACE("comment node\n");
624
625         add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
626         nsIDOMComment_Release(nscomment);
627     }
628
629     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
630     if(NS_SUCCEEDED(nsres)) {
631         TRACE("iframe node\n");
632
633         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
634         nsIDOMHTMLIFrameElement_Release(nsiframe);
635     }
636
637     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
638     if(NS_SUCCEEDED(nsres)) {
639         TRACE("frame node\n");
640
641         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
642         nsIDOMHTMLFrameElement_Release(nsframe);
643     }
644 }
645
646 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
647         nsIParser *aParser, cpp_bool *aBlock)
648 {
649     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
650     nsIDOMHTMLScriptElement *nsscript;
651     nsresult nsres;
652
653     TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
654
655     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
656     if(NS_SUCCEEDED(nsres)) {
657         TRACE("script node\n");
658
659         add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
660         nsIDOMHTMLScriptElement_Release(nsscript);
661     }
662 }
663
664 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
665     nsDocumentObserver_QueryInterface,
666     nsDocumentObserver_AddRef,
667     nsDocumentObserver_Release,
668     nsDocumentObserver_CharacterDataWillChange,
669     nsDocumentObserver_CharacterDataChanged,
670     nsDocumentObserver_AttributeWillChange,
671     nsDocumentObserver_AttributeChanged,
672     nsDocumentObserver_ContentAppended,
673     nsDocumentObserver_ContentInserted,
674     nsDocumentObserver_ContentRemoved,
675     nsDocumentObserver_NodeWillBeDestroyed,
676     nsDocumentObserver_ParentChainChanged,
677     nsDocumentObserver_BeginUpdate,
678     nsDocumentObserver_EndUpdate,
679     nsDocumentObserver_BeginLoad,
680     nsDocumentObserver_EndLoad,
681     nsDocumentObserver_ContentStatesChanged,
682     nsDocumentObserver_DocumentStatesChanged,
683     nsDocumentObserver_StyleSheetAdded,
684     nsDocumentObserver_StyleSheetRemoved,
685     nsDocumentObserver_StyleSheetApplicableStateChanged,
686     nsDocumentObserver_StyleRuleChanged,
687     nsDocumentObserver_StyleRuleAdded,
688     nsDocumentObserver_StyleRuleRemoved,
689     nsDocumentObserver_BindToDocument,
690     nsDocumentObserver_AttemptToExecuteScript
691 };
692
693 void init_document_mutation(HTMLDocumentNode *doc)
694 {
695     nsIDocument *nsdoc;
696     nsresult nsres;
697
698     doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
699
700     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
701     if(NS_FAILED(nsres)) {
702         ERR("Could not get nsIDocument: %08x\n", nsres);
703         return;
704     }
705
706     nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
707     nsIDocument_Release(nsdoc);
708 }
709
710 void release_document_mutation(HTMLDocumentNode *doc)
711 {
712     nsIDocument *nsdoc;
713     nsresult nsres;
714
715     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
716     if(NS_FAILED(nsres)) {
717         ERR("Could not get nsIDocument: %08x\n", nsres);
718         return;
719     }
720
721     nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
722     nsIDocument_Release(nsdoc);
723 }
724
725 void init_mutation(nsIComponentManager *component_manager)
726 {
727     nsIFactory *factory;
728     nsresult nsres;
729
730     if(!component_manager) {
731         if(content_utils) {
732             nsIContentUtils_Release(content_utils);
733             content_utils = NULL;
734         }
735         return;
736     }
737
738     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
739             &IID_nsIFactory, (void**)&factory);
740     if(NS_FAILED(nsres)) {
741         ERR("Could not create nsIContentUtils service: %08x\n", nsres);
742         return;
743     }
744
745     nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
746     nsIFactory_Release(factory);
747     if(NS_FAILED(nsres))
748         ERR("Could not create nsIContentUtils instance: %08x\n", nsres);
749 }