mshtml: Store current IHTMLEventObj in DOMEvent and create it in fire_event_obj if...
[wine.git] / dlls / mshtml / mutation.c
blob3c2ca08db65f7b702afcf44d9c435c8424d1f53d
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "config.h"
21 #include <stdarg.h>
22 #include <assert.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shlguid.h"
33 #include "mshtml_private.h"
34 #include "htmlscript.h"
35 #include "htmlevent.h"
36 #include "binding.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
42 const compat_mode_info_t compat_mode_info[] = {
43 { 5, 7 }, /* DOCMODE_QUIRKS */
44 { 5, 5 }, /* DOCMODE_IE5 */
45 { 7, 7 }, /* DOCMODE_IE7 */
46 { 8, 8 }, /* DOCMODE_IE8 */
47 { 9, 9 }, /* DOCMODE_IE8 */
48 { 10, 10 }, /* DOCMODE_IE10 */
49 { 11, 11 } /* DOCMODE_IE11 */
52 static const IID NS_ICONTENTUTILS_CID =
53 {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
55 static nsIContentUtils *content_utils;
57 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
59 unsigned majorv = 0, minorv = 0, compat_version;
60 const PRUnichar *ptr, *end;
61 PRUnichar *buf;
62 DWORD len;
64 enum {
65 CMP_EQ,
66 CMP_LT,
67 CMP_LTE,
68 CMP_GT,
69 CMP_GTE
70 } cmpt = CMP_EQ;
72 static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
74 if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
75 return NULL;
77 ptr = comment+3;
78 while(isspaceW(*ptr))
79 ptr++;
81 if(ptr[0] == 'l' && ptr[1] == 't') {
82 ptr += 2;
83 if(*ptr == 'e') {
84 cmpt = CMP_LTE;
85 ptr++;
86 }else {
87 cmpt = CMP_LT;
89 }else if(ptr[0] == 'g' && ptr[1] == 't') {
90 ptr += 2;
91 if(*ptr == 'e') {
92 cmpt = CMP_GTE;
93 ptr++;
94 }else {
95 cmpt = CMP_GT;
99 if(!isspaceW(*ptr++))
100 return NULL;
101 while(isspaceW(*ptr))
102 ptr++;
104 if(ptr[0] != 'I' || ptr[1] != 'E')
105 return NULL;
107 ptr +=2;
108 if(!isspaceW(*ptr++))
109 return NULL;
110 while(isspaceW(*ptr))
111 ptr++;
113 if(!isdigitW(*ptr))
114 return NULL;
115 while(isdigitW(*ptr))
116 majorv = majorv*10 + (*ptr++ - '0');
118 if(*ptr == '.') {
119 ptr++;
120 if(!isdigitW(*ptr))
121 return NULL;
122 while(isdigitW(*ptr))
123 minorv = minorv*10 + (*ptr++ - '0');
126 while(isspaceW(*ptr))
127 ptr++;
128 if(ptr[0] != ']' || ptr[1] != '>')
129 return NULL;
130 ptr += 2;
132 len = strlenW(ptr);
133 if(len < sizeof(endifW)/sizeof(WCHAR))
134 return NULL;
136 end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
137 if(memcmp(end, endifW, sizeof(endifW)))
138 return NULL;
140 compat_version = compat_mode_info[doc->document_mode].ie_version;
141 if(compat_version > 8) {
143 * Ideally we should handle higher versions, but right now it would cause more problems than it's worth.
144 * We should revisit that once more IE9 features are implemented, most notably new events APIs.
146 WARN("Using compat version 8\n");
147 compat_version = 8;
150 switch(cmpt) {
151 case CMP_EQ:
152 if(compat_version == majorv && !minorv)
153 break;
154 return NULL;
155 case CMP_LT:
156 if(compat_version < majorv || (compat_version == majorv && minorv))
157 break;
158 return NULL;
159 case CMP_LTE:
160 if(compat_version <= majorv)
161 break;
162 return NULL;
163 case CMP_GT:
164 if(compat_version > majorv)
165 break;
166 return NULL;
167 case CMP_GTE:
168 if(compat_version >= majorv || (compat_version == majorv && !minorv))
169 break;
170 return NULL;
173 buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
174 if(!buf)
175 return NULL;
177 memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
178 buf[end-ptr] = 0;
180 return buf;
183 static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
185 const PRUnichar *comment;
186 nsIDOMComment *nscomment;
187 PRUnichar *replace_html;
188 nsAString comment_str;
189 nsresult nsres;
191 nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
192 if(NS_FAILED(nsres)) {
193 ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
194 return nsres;
197 nsAString_Init(&comment_str, NULL);
198 nsres = nsIDOMComment_GetData(nscomment, &comment_str);
199 if(NS_FAILED(nsres))
200 return nsres;
202 nsAString_GetData(&comment_str, &comment);
203 replace_html = handle_insert_comment(doc, comment);
204 nsAString_Finish(&comment_str);
206 if(replace_html) {
207 HRESULT hres;
209 hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
210 heap_free(replace_html);
211 if(FAILED(hres))
212 nsres = NS_ERROR_FAILURE;
216 nsIDOMComment_Release(nscomment);
217 return nsres;
220 static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
222 nsIDOMNode *nsnode;
223 HTMLDOMNode *node;
224 nsresult nsres;
225 HRESULT hres;
227 TRACE("(%p)->(%p)\n", doc, nsiface);
229 nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
230 if(NS_FAILED(nsres))
231 return nsres;
233 hres = get_node(doc, nsnode, TRUE, &node);
234 nsIDOMNode_Release(nsnode);
235 if(FAILED(hres)) {
236 ERR("Could not get node\n");
237 return nsres;
240 if(node->vtbl->bind_to_tree)
241 node->vtbl->bind_to_tree(node);
243 node_release(node);
244 return nsres;
247 /* Calls undocumented 69 cmd of CGID_Explorer */
248 static void call_explorer_69(HTMLDocumentObj *doc)
250 IOleCommandTarget *olecmd;
251 VARIANT var;
252 HRESULT hres;
254 if(!doc->client)
255 return;
257 hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
258 if(FAILED(hres))
259 return;
261 VariantInit(&var);
262 hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
263 IOleCommandTarget_Release(olecmd);
264 if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
265 FIXME("handle result\n");
268 static void parse_complete(HTMLDocumentObj *doc)
270 TRACE("(%p)\n", doc);
272 if(doc->usermode == EDITMODE)
273 init_editor(&doc->basedoc);
275 call_explorer_69(doc);
276 if(doc->view_sink)
277 IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
278 call_property_onchanged(&doc->basedoc.cp_container, 1005);
279 call_explorer_69(doc);
281 if(doc->webbrowser && doc->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
282 IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
284 /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
287 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
289 TRACE("(%p)\n", This);
291 if(!This->basedoc.doc_obj)
292 return NS_OK;
294 if(This == This->basedoc.doc_obj->basedoc.doc_node) {
296 * This should be done in the worker thread that parses HTML,
297 * but we don't have such thread (Gecko parses HTML for us).
299 parse_complete(This->basedoc.doc_obj);
302 bind_event_scripts(This);
303 set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
304 return NS_OK;
307 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
309 nsIDOMHTMLScriptElement *nsscript;
310 HTMLScriptElement *script_elem;
311 nsIParser *nsparser = NULL;
312 script_queue_entry_t *iter;
313 HTMLInnerWindow *window;
314 nsresult nsres;
315 HRESULT hres;
317 TRACE("(%p)->(%p)\n", doc, script_iface);
319 window = doc->window;
320 if(!window)
321 return NS_OK;
323 nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
324 if(NS_FAILED(nsres)) {
325 ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
326 return nsres;
329 if(parser_iface) {
330 nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
331 if(NS_FAILED(nsres)) {
332 ERR("Could not get nsIParser iface: %08x\n", nsres);
333 nsparser = NULL;
337 hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
338 nsIDOMHTMLScriptElement_Release(nsscript);
339 if(FAILED(hres))
340 return NS_ERROR_FAILURE;
342 if(nsparser) {
343 nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
344 window->parser_callback_cnt++;
347 IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
349 doc_insert_script(window, script_elem, TRUE);
351 while(!list_empty(&window->script_queue)) {
352 iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
353 list_remove(&iter->entry);
354 if(!iter->script->parsed)
355 doc_insert_script(window, iter->script, TRUE);
356 IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
357 heap_free(iter);
360 IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
362 if(nsparser) {
363 window->parser_callback_cnt--;
364 nsIParser_EndEvaluatingParserInsertedScript(nsparser);
365 nsIParser_Release(nsparser);
368 IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
370 return NS_OK;
373 static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode, BOOL lock)
375 if(doc->document_mode_locked) {
376 WARN("attempting to set document mode %d on locked document %p\n", document_mode, doc);
377 return;
380 TRACE("%p: %d\n", doc, document_mode);
382 if(lock)
383 doc->document_mode_locked = TRUE;
384 doc->document_mode = document_mode;
387 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
389 int v = 0;
391 static const WCHAR edgeW[] = {'e','d','g','e',0};
393 if(p[0] != 'I' || p[1] != 'E' || p[2] != '=')
394 return FALSE;
395 p += 3;
397 if(!strcmpiW(p, edgeW)) {
398 *r = COMPAT_MODE_IE11;
399 return TRUE;
402 while('0' <= *p && *p <= '9')
403 v = v*10 + *(p++)-'0';
404 if(*p || !v)
405 return FALSE;
407 switch(v){
408 case 5:
409 case 6:
410 *r = COMPAT_MODE_IE5;
411 break;
412 case 7:
413 *r = COMPAT_MODE_IE7;
414 break;
415 case 8:
416 *r = COMPAT_MODE_IE8;
417 break;
418 case 9:
419 *r = COMPAT_MODE_IE9;
420 break;
421 case 10:
422 *r = COMPAT_MODE_IE10;
423 break;
424 default:
425 *r = v < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
428 return TRUE;
431 static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
433 nsAString http_equiv_str, content_str;
434 nsresult nsres;
436 static const WCHAR x_ua_compatibleW[] = {'x','-','u','a','-','c','o','m','p','a','t','i','b','l','e',0};
438 nsAString_Init(&http_equiv_str, NULL);
439 nsAString_Init(&content_str, NULL);
440 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
441 if(NS_SUCCEEDED(nsres))
442 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
444 if(NS_SUCCEEDED(nsres)) {
445 const PRUnichar *http_equiv, *content;
447 nsAString_GetData(&http_equiv_str, &http_equiv);
448 nsAString_GetData(&content_str, &content);
450 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
452 if(!strcmpiW(http_equiv, x_ua_compatibleW)) {
453 compat_mode_t document_mode;
454 if(parse_ua_compatible(content, &document_mode))
455 set_document_mode(doc, document_mode, TRUE);
456 else
457 FIXME("Unsupported document mode %s\n", debugstr_w(content));
461 nsAString_Finish(&http_equiv_str);
462 nsAString_Finish(&content_str);
465 typedef struct nsRunnable nsRunnable;
467 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
469 struct nsRunnable {
470 nsIRunnable nsIRunnable_iface;
472 LONG ref;
474 runnable_proc_t proc;
476 HTMLDocumentNode *doc;
477 nsISupports *arg1;
478 nsISupports *arg2;
481 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
483 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
486 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
487 nsIIDRef riid, void **result)
489 nsRunnable *This = impl_from_nsIRunnable(iface);
491 if(IsEqualGUID(riid, &IID_nsISupports)) {
492 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
493 *result = &This->nsIRunnable_iface;
494 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
495 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
496 *result = &This->nsIRunnable_iface;
497 }else {
498 *result = NULL;
499 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
500 return NS_NOINTERFACE;
503 nsISupports_AddRef((nsISupports*)*result);
504 return NS_OK;
507 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
509 nsRunnable *This = impl_from_nsIRunnable(iface);
510 LONG ref = InterlockedIncrement(&This->ref);
512 TRACE("(%p) ref=%d\n", This, ref);
514 return ref;
517 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
519 nsRunnable *This = impl_from_nsIRunnable(iface);
520 LONG ref = InterlockedDecrement(&This->ref);
522 TRACE("(%p) ref=%d\n", This, ref);
524 if(!ref) {
525 htmldoc_release(&This->doc->basedoc);
526 if(This->arg1)
527 nsISupports_Release(This->arg1);
528 if(This->arg2)
529 nsISupports_Release(This->arg2);
530 heap_free(This);
533 return ref;
536 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
538 nsRunnable *This = impl_from_nsIRunnable(iface);
540 return This->proc(This->doc, This->arg1, This->arg2);
543 static const nsIRunnableVtbl nsRunnableVtbl = {
544 nsRunnable_QueryInterface,
545 nsRunnable_AddRef,
546 nsRunnable_Release,
547 nsRunnable_Run
550 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
552 nsRunnable *runnable;
554 runnable = heap_alloc_zero(sizeof(*runnable));
555 if(!runnable)
556 return;
558 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
559 runnable->ref = 1;
561 htmldoc_addref(&This->basedoc);
562 runnable->doc = This;
563 runnable->proc = proc;
565 if(arg1)
566 nsISupports_AddRef(arg1);
567 runnable->arg1 = arg1;
569 if(arg2)
570 nsISupports_AddRef(arg2);
571 runnable->arg2 = arg2;
573 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
575 nsIRunnable_Release(&runnable->nsIRunnable_iface);
578 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
580 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
583 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
584 nsIIDRef riid, void **result)
586 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
588 if(IsEqualGUID(&IID_nsISupports, riid)) {
589 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
590 *result = &This->nsIDocumentObserver_iface;
591 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
592 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
593 *result = &This->nsIDocumentObserver_iface;
594 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
595 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
596 *result = &This->nsIDocumentObserver_iface;
597 }else {
598 *result = NULL;
599 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
600 return NS_NOINTERFACE;
603 htmldoc_addref(&This->basedoc);
604 return NS_OK;
607 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
609 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
610 return htmldoc_addref(&This->basedoc);
613 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
615 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
616 return htmldoc_release(&This->basedoc);
619 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
620 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
624 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
625 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
629 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
630 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
634 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
635 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
639 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
640 nsIContent *aContent, cpp_bool aIsRemove)
644 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
645 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
649 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
650 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
654 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
655 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
659 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
660 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
661 nsIContent *aProviousSibling)
665 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
669 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
673 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
674 nsUpdateType aUpdateType)
678 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
679 nsUpdateType aUpdateType)
683 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
687 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
689 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
691 TRACE("(%p)\n", This);
693 if(This->skip_mutation_notif)
694 return;
696 This->content_ready = TRUE;
697 add_script_runner(This, run_end_load, NULL, NULL);
700 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
701 nsIContent *aContent, EventStates aStateMask)
705 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
706 EventStates aStateMask)
710 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
711 cpp_bool aDocumentSheet)
715 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
716 cpp_bool aDocumentSheet)
720 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
721 mozilla_StyleSheetHandle aStyleSheet)
725 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
729 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
733 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
737 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
738 nsIContent *aContent)
740 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
741 nsIDOMHTMLIFrameElement *nsiframe;
742 nsIDOMHTMLFrameElement *nsframe;
743 nsIDOMHTMLScriptElement *nsscript;
744 nsIDOMHTMLMetaElement *nsmeta;
745 nsIDOMHTMLElement *nselem;
746 nsIDOMComment *nscomment;
747 nsresult nsres;
749 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
751 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
752 if(NS_SUCCEEDED(nsres)) {
753 TRACE("comment node\n");
755 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
756 nsIDOMComment_Release(nscomment);
757 return;
760 if(This->document_mode == COMPAT_MODE_QUIRKS) {
761 nsIDOMDocumentType *nsdoctype;
762 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMDocumentType, (void**)&nsdoctype);
763 if(NS_SUCCEEDED(nsres)) {
764 TRACE("doctype node\n");
765 /* FIXME: We should set it to something higher for internet zone. */
766 set_document_mode(This, COMPAT_MODE_IE7, FALSE);
767 nsIDOMDocumentType_Release(nsdoctype);
771 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLElement, (void**)&nselem);
772 if(NS_FAILED(nsres))
773 return;
775 check_event_attr(This, nselem);
776 nsIDOMHTMLElement_Release(nselem);
778 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
779 if(NS_SUCCEEDED(nsres)) {
780 TRACE("iframe node\n");
782 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
783 nsIDOMHTMLIFrameElement_Release(nsiframe);
784 return;
787 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
788 if(NS_SUCCEEDED(nsres)) {
789 TRACE("frame node\n");
791 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
792 nsIDOMHTMLFrameElement_Release(nsframe);
793 return;
796 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
797 if(NS_SUCCEEDED(nsres)) {
798 TRACE("script element\n");
800 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsscript, NULL);
801 nsIDOMHTMLScriptElement_Release(nsscript);
802 return;
805 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
806 if(NS_SUCCEEDED(nsres)) {
807 process_meta_element(This, nsmeta);
808 nsIDOMHTMLMetaElement_Release(nsmeta);
812 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
813 nsIParser *aParser, cpp_bool *aBlock)
815 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
816 nsIDOMHTMLScriptElement *nsscript;
817 nsresult nsres;
819 TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
821 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
822 if(NS_SUCCEEDED(nsres)) {
823 TRACE("script node\n");
825 This->document_mode_locked = TRUE;
827 add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
828 nsIDOMHTMLScriptElement_Release(nsscript);
832 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
833 nsDocumentObserver_QueryInterface,
834 nsDocumentObserver_AddRef,
835 nsDocumentObserver_Release,
836 nsDocumentObserver_CharacterDataWillChange,
837 nsDocumentObserver_CharacterDataChanged,
838 nsDocumentObserver_AttributeWillChange,
839 nsDocumentObserver_AttributeChanged,
840 nsDocumentObserver_NativeAnonymousChildListChange,
841 nsDocumentObserver_AttributeSetToCurrentValue,
842 nsDocumentObserver_ContentAppended,
843 nsDocumentObserver_ContentInserted,
844 nsDocumentObserver_ContentRemoved,
845 nsDocumentObserver_NodeWillBeDestroyed,
846 nsDocumentObserver_ParentChainChanged,
847 nsDocumentObserver_BeginUpdate,
848 nsDocumentObserver_EndUpdate,
849 nsDocumentObserver_BeginLoad,
850 nsDocumentObserver_EndLoad,
851 nsDocumentObserver_ContentStatesChanged,
852 nsDocumentObserver_DocumentStatesChanged,
853 nsDocumentObserver_StyleSheetAdded,
854 nsDocumentObserver_StyleSheetRemoved,
855 nsDocumentObserver_StyleSheetApplicableStateChanged,
856 nsDocumentObserver_StyleRuleChanged,
857 nsDocumentObserver_StyleRuleAdded,
858 nsDocumentObserver_StyleRuleRemoved,
859 nsDocumentObserver_BindToDocument,
860 nsDocumentObserver_AttemptToExecuteScript
863 void init_document_mutation(HTMLDocumentNode *doc)
865 nsIDocument *nsdoc;
866 nsresult nsres;
868 doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
870 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
871 if(NS_FAILED(nsres)) {
872 ERR("Could not get nsIDocument: %08x\n", nsres);
873 return;
876 nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
877 nsIDocument_Release(nsdoc);
880 void release_document_mutation(HTMLDocumentNode *doc)
882 nsIDocument *nsdoc;
883 nsresult nsres;
885 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
886 if(NS_FAILED(nsres)) {
887 ERR("Could not get nsIDocument: %08x\n", nsres);
888 return;
891 nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
892 nsIDocument_Release(nsdoc);
895 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
897 nsIDocument *doc;
898 JSContext *ctx;
899 nsresult nsres;
901 nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
902 assert(nsres == NS_OK);
904 ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
905 nsIDocument_Release(doc);
907 TRACE("ret %p\n", ctx);
908 return ctx;
911 void init_mutation(nsIComponentManager *component_manager)
913 nsIFactory *factory;
914 nsresult nsres;
916 if(!component_manager) {
917 if(content_utils) {
918 nsIContentUtils_Release(content_utils);
919 content_utils = NULL;
921 return;
924 nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
925 &IID_nsIFactory, (void**)&factory);
926 if(NS_FAILED(nsres)) {
927 ERR("Could not create nsIContentUtils service: %08x\n", nsres);
928 return;
931 nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
932 nsIFactory_Release(factory);
933 if(NS_FAILED(nsres))
934 ERR("Could not create nsIContentUtils instance: %08x\n", nsres);