winspool: Revise EnumPrinterDriversW to fix the incorrect handling of 'all'. EnumPrin...
[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 enum {
40     MUTATION_COMMENT,
41     MUTATION_ENDLOAD,
42     MUTATION_FRAME,
43     MUTATION_IFRAME,
44     MUTATION_SCRIPT
45 };
46
47 #define IE_MAJOR_VERSION 7
48 #define IE_MINOR_VERSION 0
49
50 static BOOL handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
51 {
52     DWORD len;
53     int majorv = 0, minorv = 0;
54     const PRUnichar *ptr, *end;
55     nsAString nsstr;
56     PRUnichar *buf;
57     nsresult nsres;
58
59     enum {
60         CMP_EQ,
61         CMP_LT,
62         CMP_LTE,
63         CMP_GT,
64         CMP_GTE
65     } cmpt = CMP_EQ;
66
67     static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
68
69     if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
70         return FALSE;
71
72     ptr = comment+3;
73     while(isspaceW(*ptr))
74         ptr++;
75
76     if(ptr[0] == 'l' && ptr[1] == 't') {
77         ptr += 2;
78         if(*ptr == 'e') {
79             cmpt = CMP_LTE;
80             ptr++;
81         }else {
82             cmpt = CMP_LT;
83         }
84     }else if(ptr[0] == 'g' && ptr[1] == 't') {
85         ptr += 2;
86         if(*ptr == 'e') {
87             cmpt = CMP_GTE;
88             ptr++;
89         }else {
90             cmpt = CMP_GT;
91         }
92     }
93
94     if(!isspaceW(*ptr++))
95         return FALSE;
96     while(isspaceW(*ptr))
97         ptr++;
98
99     if(ptr[0] != 'I' || ptr[1] != 'E')
100         return FALSE;
101
102     ptr +=2;
103     if(!isspaceW(*ptr++))
104         return FALSE;
105     while(isspaceW(*ptr))
106         ptr++;
107
108     if(!isdigitW(*ptr))
109         return FALSE;
110     while(isdigitW(*ptr))
111         majorv = majorv*10 + (*ptr++ - '0');
112
113     if(*ptr == '.') {
114         ptr++;
115         if(!isdigitW(*ptr))
116             return FALSE;
117         while(isdigitW(*ptr))
118             minorv = minorv*10 + (*ptr++ - '0');
119     }
120
121     while(isspaceW(*ptr))
122         ptr++;
123     if(ptr[0] != ']' || ptr[1] != '>')
124         return FALSE;
125     ptr += 2;
126
127     len = strlenW(ptr);
128     if(len < sizeof(endifW)/sizeof(WCHAR))
129         return FALSE;
130
131     end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
132     if(memcmp(end, endifW, sizeof(endifW)))
133         return FALSE;
134
135     switch(cmpt) {
136     case CMP_EQ:
137         if(majorv == IE_MAJOR_VERSION && minorv == IE_MINOR_VERSION)
138             break;
139         return FALSE;
140     case CMP_LT:
141         if(majorv > IE_MAJOR_VERSION)
142             break;
143         if(majorv == IE_MAJOR_VERSION && minorv > IE_MINOR_VERSION)
144             break;
145         return FALSE;
146     case CMP_LTE:
147         if(majorv > IE_MAJOR_VERSION)
148             break;
149         if(majorv == IE_MAJOR_VERSION && minorv >= IE_MINOR_VERSION)
150             break;
151         return FALSE;
152     case CMP_GT:
153         if(majorv < IE_MAJOR_VERSION)
154             break;
155         if(majorv == IE_MAJOR_VERSION && minorv < IE_MINOR_VERSION)
156             break;
157         return FALSE;
158     case CMP_GTE:
159         if(majorv < IE_MAJOR_VERSION)
160             break;
161         if(majorv == IE_MAJOR_VERSION && minorv <= IE_MINOR_VERSION)
162             break;
163         return FALSE;
164     }
165
166     buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
167     if(!buf)
168         return FALSE;
169
170     memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
171     buf[end-ptr] = 0;
172     nsAString_Init(&nsstr, buf);
173     heap_free(buf);
174
175     /* FIXME: Find better way to insert HTML to document. */
176     nsres = nsIDOMHTMLDocument_Write(doc->nsdoc, &nsstr);
177     nsAString_Finish(&nsstr);
178     if(NS_FAILED(nsres)) {
179         ERR("Write failed: %08x\n", nsres);
180         return FALSE;
181     }
182
183     return TRUE;
184 }
185
186 static void add_script_runner(HTMLDocumentNode *This)
187 {
188     nsIDOMNSDocument *nsdoc;
189     nsresult nsres;
190
191     nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
192     if(NS_FAILED(nsres)) {
193         ERR("Could not get nsIDOMNSDocument: %08x\n", nsres);
194         return;
195     }
196
197     nsIDOMNSDocument_WineAddScriptRunner(nsdoc, NSRUNNABLE(This));
198     nsIDOMNSDocument_Release(nsdoc);
199 }
200
201 #define NSRUNNABLE_THIS(iface) DEFINE_THIS(HTMLDocumentNode, IRunnable, iface)
202
203 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
204         nsIIDRef riid, nsQIResult result)
205 {
206     HTMLDocumentNode *This = NSRUNNABLE_THIS(iface);
207
208     if(IsEqualGUID(riid, &IID_nsISupports)) {
209         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
210         *result = NSRUNNABLE(This);
211     }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
212         TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
213         *result = NSRUNNABLE(This);
214     }else {
215         *result = NULL;
216         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
217         return NS_NOINTERFACE;
218     }
219
220     nsISupports_AddRef((nsISupports*)*result);
221     return NS_OK;
222 }
223
224 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
225 {
226     HTMLDocumentNode *This = NSRUNNABLE_THIS(iface);
227     return htmldoc_addref(&This->basedoc);
228 }
229
230 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
231 {
232     HTMLDocumentNode *This = NSRUNNABLE_THIS(iface);
233     return htmldoc_release(&This->basedoc);
234 }
235
236 static void push_mutation_queue(HTMLDocumentNode *doc, DWORD type, nsISupports *nsiface)
237 {
238     mutation_queue_t *elem;
239
240     elem = heap_alloc(sizeof(mutation_queue_t));
241     if(!elem)
242         return;
243
244     elem->next = NULL;
245     elem->type = type;
246     elem->nsiface = nsiface;
247     if(nsiface)
248         nsISupports_AddRef(nsiface);
249
250     if(doc->mutation_queue_tail) {
251         doc->mutation_queue_tail = doc->mutation_queue_tail->next = elem;
252     }else {
253         doc->mutation_queue = doc->mutation_queue_tail = elem;
254         add_script_runner(doc);
255     }
256 }
257
258 static void pop_mutation_queue(HTMLDocumentNode *doc)
259 {
260     mutation_queue_t *tmp = doc->mutation_queue;
261
262     if(!tmp)
263         return;
264
265     doc->mutation_queue = tmp->next;
266     if(!tmp->next)
267         doc->mutation_queue_tail = NULL;
268
269     if(tmp->nsiface)
270         nsISupports_Release(tmp->nsiface);
271     heap_free(tmp);
272 }
273
274 static nsresult init_nsdoc_window(HTMLDocumentNode *doc, nsIDOMDocument *nsdoc, HTMLWindow **ret)
275 {
276     nsIDOMWindow *nswindow;
277
278     nswindow = get_nsdoc_window(nsdoc);
279     if(!nswindow)
280         return NS_ERROR_FAILURE;
281
282     if(!nswindow_to_window(nswindow)) {
283         HTMLWindow *window;
284         HRESULT hres;
285
286         hres = HTMLWindow_Create(doc->basedoc.doc_obj, nswindow, doc->basedoc.window, &window);
287         if(SUCCEEDED(hres))
288             *ret = window;
289     }
290
291     nsIDOMWindow_Release(nswindow);
292     return NS_OK;
293 }
294
295 static nsresult init_iframe_window(HTMLDocumentNode *doc, nsISupports *nsunk)
296 {
297     nsIDOMHTMLIFrameElement *nsiframe;
298     HTMLWindow *window = NULL;
299     nsIDOMDocument *nsdoc;
300     nsresult nsres;
301
302     nsres = nsISupports_QueryInterface(nsunk, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
303     if(NS_FAILED(nsres)) {
304         ERR("Could not get nsIDOMHTMLIFrameElement: %08x\n", nsres);
305         return nsres;
306     }
307
308     nsres = nsIDOMHTMLIFrameElement_GetContentDocument(nsiframe, &nsdoc);
309     nsIDOMHTMLIFrameElement_Release(nsiframe);
310     if(NS_FAILED(nsres) || !nsdoc) {
311         ERR("GetContentDocument failed: %08x\n", nsres);
312         return nsres;
313     }
314
315     nsres = init_nsdoc_window(doc, nsdoc, &window);
316
317     if(window) {
318         HTMLIFrame_Create(doc, (nsIDOMHTMLElement*)nsiframe, window);
319         IHTMLWindow2_Release(HTMLWINDOW2(window));
320     }
321
322     nsIDOMDocument_Release(nsdoc);
323     return nsres;
324 }
325
326 static nsresult init_frame_window(HTMLDocumentNode *doc, nsISupports *nsunk)
327 {
328     nsIDOMHTMLFrameElement *nsframe;
329     HTMLWindow *window = NULL;
330     nsIDOMDocument *nsdoc;
331     nsresult nsres;
332
333     nsres = nsISupports_QueryInterface(nsunk, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
334     if(NS_FAILED(nsres)) {
335         ERR("Could not get nsIDOMHTMLFrameElement: %08x\n", nsres);
336         return nsres;
337     }
338
339     nsres = nsIDOMHTMLFrameElement_GetContentDocument(nsframe, &nsdoc);
340     nsIDOMHTMLFrameElement_Release(nsframe);
341     if(NS_FAILED(nsres) || !nsdoc) {
342         ERR("GetContentDocument failed: %08x\n", nsres);
343         return nsres;
344     }
345
346     nsres = init_nsdoc_window(doc, nsdoc, &window);
347
348     if(window) {
349         HTMLFrameElement_Create(doc, (nsIDOMHTMLElement*)nsframe, window);
350         IHTMLWindow2_Release(HTMLWINDOW2(window));
351     }
352
353     nsIDOMDocument_Release(nsdoc);
354     return nsres;
355 }
356
357 /* Calls undocumented 69 cmd of CGID_Explorer */
358 static void call_explorer_69(HTMLDocumentObj *doc)
359 {
360     IOleCommandTarget *olecmd;
361     VARIANT var;
362     HRESULT hres;
363
364     if(!doc->client)
365         return;
366
367     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
368     if(FAILED(hres))
369         return;
370
371     VariantInit(&var);
372     hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
373     IOleCommandTarget_Release(olecmd);
374     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
375         FIXME("handle result\n");
376 }
377
378 static void parse_complete_proc(task_t *task)
379 {
380     HTMLDocumentObj *doc = ((docobj_task_t*)task)->doc;
381
382     TRACE("(%p)\n", doc);
383
384     if(doc->usermode == EDITMODE)
385         init_editor(&doc->basedoc);
386
387     call_explorer_69(doc);
388     call_property_onchanged(&doc->basedoc.cp_propnotif, 1005);
389     call_explorer_69(doc);
390
391     /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
392
393     set_ready_state(doc->basedoc.window, READYSTATE_INTERACTIVE);
394 }
395
396 static void handle_end_load(HTMLDocumentNode *This)
397 {
398     docobj_task_t *task;
399
400     TRACE("\n");
401
402     if(This != This->basedoc.doc_obj->basedoc.doc_node) {
403         set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
404         return;
405     }
406
407     task = heap_alloc(sizeof(docobj_task_t));
408     if(!task)
409         return;
410
411     task->doc = This->basedoc.doc_obj;
412
413     /*
414      * This should be done in the worker thread that parses HTML,
415      * but we don't have such thread (Gecko parses HTML for us).
416      */
417     push_task(&task->header, &parse_complete_proc, This->basedoc.doc_obj->basedoc.task_magic);
418 }
419
420 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
421 {
422     HTMLDocumentNode *This = NSRUNNABLE_THIS(iface);
423     nsresult nsres;
424
425     TRACE("(%p)\n", This);
426
427     while(This->mutation_queue) {
428         switch(This->mutation_queue->type) {
429         case MUTATION_COMMENT: {
430             nsIDOMComment *nscomment;
431             nsAString comment_str;
432             BOOL remove_comment = FALSE;
433
434             nsres = nsISupports_QueryInterface(This->mutation_queue->nsiface, &IID_nsIDOMComment, (void**)&nscomment);
435             if(NS_FAILED(nsres)) {
436                 ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
437                 return NS_OK;
438             }
439
440             nsAString_Init(&comment_str, NULL);
441             nsres = nsIDOMComment_GetData(nscomment, &comment_str);
442             if(NS_SUCCEEDED(nsres)) {
443                 const PRUnichar *comment;
444
445                 nsAString_GetData(&comment_str, &comment);
446                 remove_comment = handle_insert_comment(This, comment);
447             }
448
449             nsAString_Finish(&comment_str);
450
451             if(remove_comment) {
452                 nsIDOMNode *nsparent, *tmp;
453                 nsAString magic_str;
454
455                 static const PRUnichar remove_comment_magicW[] =
456                     {'#','!','w','i','n','e', 'r','e','m','o','v','e','!','#',0};
457
458                 nsAString_Init(&magic_str, remove_comment_magicW);
459                 nsres = nsIDOMComment_SetData(nscomment, &magic_str);
460                 nsAString_Finish(&magic_str);
461                 if(NS_FAILED(nsres))
462                     ERR("SetData failed: %08x\n", nsres);
463
464                 nsIDOMComment_GetParentNode(nscomment, &nsparent);
465                 if(nsparent) {
466                     nsIDOMNode_RemoveChild(nsparent, (nsIDOMNode*)nscomment, &tmp);
467                     nsIDOMNode_Release(nsparent);
468                     nsIDOMNode_Release(tmp);
469                 }
470             }
471
472             nsIDOMComment_Release(nscomment);
473             break;
474         }
475
476         case MUTATION_ENDLOAD:
477             handle_end_load(This);
478             break;
479
480         case MUTATION_FRAME:
481             init_frame_window(This, This->mutation_queue->nsiface);
482             break;
483
484         case MUTATION_IFRAME:
485             init_iframe_window(This, This->mutation_queue->nsiface);
486             break;
487
488         case MUTATION_SCRIPT: {
489             nsIDOMHTMLScriptElement *nsscript;
490
491             nsres = nsISupports_QueryInterface(This->mutation_queue->nsiface, &IID_nsIDOMHTMLScriptElement,
492                                                (void**)&nsscript);
493             if(NS_FAILED(nsres)) {
494                 ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
495                 break;
496             }
497
498             doc_insert_script(This->basedoc.window, nsscript);
499             nsIDOMHTMLScriptElement_Release(nsscript);
500             break;
501         }
502
503         default:
504             ERR("invalid type %d\n", This->mutation_queue->type);
505         }
506
507         pop_mutation_queue(This);
508     }
509
510     return S_OK;
511 }
512
513 #undef NSRUNNABLE_THIS
514
515 static const nsIRunnableVtbl nsRunnableVtbl = {
516     nsRunnable_QueryInterface,
517     nsRunnable_AddRef,
518     nsRunnable_Release,
519     nsRunnable_Run
520 };
521
522 #define NSDOCOBS_THIS(iface) DEFINE_THIS(HTMLDocumentNode, IDocumentObserver, iface)
523
524 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
525         nsIIDRef riid, nsQIResult result)
526 {
527     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
528
529     if(IsEqualGUID(&IID_nsISupports, riid)) {
530         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
531         *result = NSDOCOBS(This);
532     }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
533         TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
534         *result = NSDOCOBS(This);
535     }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
536         TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
537         *result = NSDOCOBS(This);
538     }else {
539         *result = NULL;
540         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
541         return NS_NOINTERFACE;
542     }
543
544     htmldoc_addref(&This->basedoc);
545     return NS_OK;
546 }
547
548 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
549 {
550     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
551     return htmldoc_addref(&This->basedoc);
552 }
553
554 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
555 {
556     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
557     return htmldoc_release(&This->basedoc);
558 }
559
560 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
561         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
562 {
563 }
564
565 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
566         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
567 {
568 }
569
570 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
571         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType)
572 {
573 }
574
575 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
576         nsIContent *aContent, PRInt32 aNameSpaceID, nsIAtom *aAttribute, PRInt32 aModType, PRUint32 aStateMask)
577 {
578 }
579
580 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
581         nsIContent *aContainer, PRInt32 aNewIndexInContainer)
582 {
583 }
584
585 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
586         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
587 {
588 }
589
590 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
591         nsIContent *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
592 {
593 }
594
595 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
596 {
597 }
598
599 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
600 {
601 }
602
603 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
604         nsUpdateType aUpdateType)
605 {
606 }
607
608 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
609         nsUpdateType aUpdateType)
610 {
611 }
612
613 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
614 {
615 }
616
617 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
618 {
619     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
620
621     TRACE("\n");
622
623     This->content_ready = TRUE;
624     push_mutation_queue(This, MUTATION_ENDLOAD, NULL);
625 }
626
627 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
628         nsIContent *aContent1, nsIContent *aContent2, PRInt32 aStateMask)
629 {
630 }
631
632 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
633         nsIStyleSheet *aStyleSheet, PRBool aDocumentSheet)
634 {
635 }
636
637 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
638         nsIStyleSheet *aStyleSheet, PRBool aDocumentSheet)
639 {
640 }
641
642 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
643         nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, PRBool aApplicable)
644 {
645 }
646
647 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
648         nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
649 {
650 }
651
652 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
653         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
654 {
655 }
656
657 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
658         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
659 {
660 }
661
662 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
663         nsIContent *aContent)
664 {
665     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
666     nsIDOMHTMLIFrameElement *nsiframe;
667     nsIDOMHTMLFrameElement *nsframe;
668     nsIDOMComment *nscomment;
669     nsIDOMElement *nselem;
670     nsresult nsres;
671
672     TRACE("(%p)\n", This);
673
674     nsres = nsISupports_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
675     if(NS_SUCCEEDED(nsres)) {
676         check_event_attr(This, nselem);
677         nsIDOMElement_Release(nselem);
678     }
679
680     nsres = nsISupports_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
681     if(NS_SUCCEEDED(nsres)) {
682         TRACE("comment node\n");
683
684         push_mutation_queue(This, MUTATION_COMMENT, (nsISupports*)nscomment);
685         nsIDOMComment_Release(nscomment);
686     }
687
688     nsres = nsISupports_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
689     if(NS_SUCCEEDED(nsres)) {
690         TRACE("iframe node\n");
691
692         push_mutation_queue(This, MUTATION_IFRAME, (nsISupports*)nsiframe);
693         nsIDOMHTMLIFrameElement_Release(nsiframe);
694     }
695
696     nsres = nsISupports_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
697     if(NS_SUCCEEDED(nsres)) {
698         TRACE("frame node\n");
699
700         push_mutation_queue(This, MUTATION_FRAME, (nsISupports*)nsframe);
701         nsIDOMHTMLFrameElement_Release(nsframe);
702     }
703 }
704
705 static void NSAPI nsDocumentObserver_DoneAddingChildren(nsIDocumentObserver *iface, nsIContent *aContent,
706         PRBool aHaveNotified)
707 {
708     HTMLDocumentNode *This = NSDOCOBS_THIS(iface);
709     nsIDOMHTMLScriptElement *nsscript;
710     nsresult nsres;
711
712     TRACE("(%p)->(%p %x)\n", This, aContent, aHaveNotified);
713
714     nsres = nsISupports_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
715     if(NS_SUCCEEDED(nsres)) {
716         TRACE("script node\n");
717
718         push_mutation_queue(This, MUTATION_SCRIPT, (nsISupports*)nsscript);
719         nsIDOMHTMLScriptElement_Release(nsscript);
720     }
721 }
722
723 #undef NSMUTATIONOBS_THIS
724
725 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
726     nsDocumentObserver_QueryInterface,
727     nsDocumentObserver_AddRef,
728     nsDocumentObserver_Release,
729     nsDocumentObserver_CharacterDataWillChange,
730     nsDocumentObserver_CharacterDataChanged,
731     nsDocumentObserver_AttributeWillChange,
732     nsDocumentObserver_AttributeChanged,
733     nsDocumentObserver_ContentAppended,
734     nsDocumentObserver_ContentInserted,
735     nsDocumentObserver_ContentRemoved,
736     nsDocumentObserver_NodeWillBeDestroyed,
737     nsDocumentObserver_ParentChainChanged,
738     nsDocumentObserver_BeginUpdate,
739     nsDocumentObserver_EndUpdate,
740     nsDocumentObserver_BeginLoad,
741     nsDocumentObserver_EndLoad,
742     nsDocumentObserver_ContentStatesChanged,
743     nsDocumentObserver_StyleSheetAdded,
744     nsDocumentObserver_StyleSheetRemoved,
745     nsDocumentObserver_StyleSheetApplicableStateChanged,
746     nsDocumentObserver_StyleRuleChanged,
747     nsDocumentObserver_StyleRuleAdded,
748     nsDocumentObserver_StyleRuleRemoved,
749     nsDocumentObserver_BindToDocument,
750     nsDocumentObserver_DoneAddingChildren
751 };
752
753 void init_mutation(HTMLDocumentNode *doc)
754 {
755     nsIDOMNSDocument *nsdoc;
756     nsresult nsres;
757
758     doc->lpIDocumentObserverVtbl  = &nsDocumentObserverVtbl;
759     doc->lpIRunnableVtbl          = &nsRunnableVtbl;
760
761     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
762     if(NS_FAILED(nsres)) {
763         ERR("Could not get nsIDOMNSDocument: %08x\n", nsres);
764         return;
765     }
766
767     nsIDOMNSDocument_WineAddObserver(nsdoc, NSDOCOBS(doc));
768     nsIDOMNSDocument_Release(nsdoc);
769 }
770
771 void release_mutation(HTMLDocumentNode *doc)
772 {
773     nsIDOMNSDocument *nsdoc;
774     nsresult nsres;
775
776     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
777     if(NS_FAILED(nsres)) {
778         ERR("Could not get nsIDOMNSDocument: %08x\n", nsres);
779         return;
780     }
781
782     nsIDOMNSDocument_WineRemoveObserver(nsdoc, NSDOCOBS(doc));
783     nsIDOMNSDocument_Release(nsdoc);
784 }