mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / mshtml / mutation.c
blob247a3277927ddcc8c0d560313746c5f811eeaea7
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 <stdarg.h>
20 #include <assert.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "ole2.h"
29 #include "shlguid.h"
30 #include "wininet.h"
32 #include "mshtml_private.h"
33 #include "htmlscript.h"
34 #include "htmlevent.h"
35 #include "binding.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41 const compat_mode_info_t compat_mode_info[] = {
42 { 5, 7 }, /* DOCMODE_QUIRKS */
43 { 5, 5 }, /* DOCMODE_IE5 */
44 { 7, 7 }, /* DOCMODE_IE7 */
45 { 8, 8 }, /* DOCMODE_IE8 */
46 { 9, 9 }, /* DOCMODE_IE8 */
47 { 10, 10 }, /* DOCMODE_IE10 */
48 { 11, 11 } /* DOCMODE_IE11 */
51 static const IID NS_ICONTENTUTILS_CID =
52 {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
54 static nsIContentUtils *content_utils;
56 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
58 unsigned majorv = 0, minorv = 0, compat_version;
59 const PRUnichar *ptr, *end;
60 PRUnichar *buf;
61 DWORD len;
63 enum {
64 CMP_EQ,
65 CMP_LT,
66 CMP_LTE,
67 CMP_GT,
68 CMP_GTE
69 } cmpt = CMP_EQ;
71 static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
73 if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
74 return NULL;
76 ptr = comment+3;
77 while(iswspace(*ptr))
78 ptr++;
80 if(ptr[0] == 'l' && ptr[1] == 't') {
81 ptr += 2;
82 if(*ptr == 'e') {
83 cmpt = CMP_LTE;
84 ptr++;
85 }else {
86 cmpt = CMP_LT;
88 }else if(ptr[0] == 'g' && ptr[1] == 't') {
89 ptr += 2;
90 if(*ptr == 'e') {
91 cmpt = CMP_GTE;
92 ptr++;
93 }else {
94 cmpt = CMP_GT;
98 if(!iswspace(*ptr++))
99 return NULL;
100 while(iswspace(*ptr))
101 ptr++;
103 if(ptr[0] != 'I' || ptr[1] != 'E')
104 return NULL;
106 ptr +=2;
107 if(!iswspace(*ptr++))
108 return NULL;
109 while(iswspace(*ptr))
110 ptr++;
112 if(!is_digit(*ptr))
113 return NULL;
114 while(is_digit(*ptr))
115 majorv = majorv*10 + (*ptr++ - '0');
117 if(*ptr == '.') {
118 ptr++;
119 if(!is_digit(*ptr))
120 return NULL;
121 while(is_digit(*ptr))
122 minorv = minorv*10 + (*ptr++ - '0');
125 while(iswspace(*ptr))
126 ptr++;
127 if(ptr[0] != ']' || ptr[1] != '>')
128 return NULL;
129 ptr += 2;
131 len = lstrlenW(ptr);
132 if(len < ARRAY_SIZE(endifW))
133 return NULL;
135 end = ptr + len - ARRAY_SIZE(endifW);
136 if(memcmp(end, endifW, sizeof(endifW)))
137 return NULL;
139 compat_version = compat_mode_info[doc->document_mode].ie_version;
141 switch(cmpt) {
142 case CMP_EQ:
143 if(compat_version == majorv && !minorv)
144 break;
145 return NULL;
146 case CMP_LT:
147 if(compat_version < majorv || (compat_version == majorv && minorv))
148 break;
149 return NULL;
150 case CMP_LTE:
151 if(compat_version <= majorv)
152 break;
153 return NULL;
154 case CMP_GT:
155 if(compat_version > majorv)
156 break;
157 return NULL;
158 case CMP_GTE:
159 if(compat_version >= majorv || (compat_version == majorv && !minorv))
160 break;
161 return NULL;
164 buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
165 if(!buf)
166 return NULL;
168 memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
169 buf[end-ptr] = 0;
171 return buf;
174 static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
176 const PRUnichar *comment;
177 nsIDOMComment *nscomment;
178 PRUnichar *replace_html;
179 nsAString comment_str;
180 nsresult nsres;
182 nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
183 if(NS_FAILED(nsres)) {
184 ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
185 return nsres;
188 nsAString_Init(&comment_str, NULL);
189 nsres = nsIDOMComment_GetData(nscomment, &comment_str);
190 if(NS_FAILED(nsres))
191 return nsres;
193 nsAString_GetData(&comment_str, &comment);
194 replace_html = handle_insert_comment(doc, comment);
195 nsAString_Finish(&comment_str);
197 if(replace_html) {
198 HRESULT hres;
200 hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
201 heap_free(replace_html);
202 if(FAILED(hres))
203 nsres = NS_ERROR_FAILURE;
207 nsIDOMComment_Release(nscomment);
208 return nsres;
211 static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
213 nsIDOMNode *nsnode;
214 HTMLDOMNode *node;
215 nsresult nsres;
216 HRESULT hres;
218 TRACE("(%p)->(%p)\n", doc, nsiface);
220 nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
221 if(NS_FAILED(nsres))
222 return nsres;
224 hres = get_node(nsnode, TRUE, &node);
225 nsIDOMNode_Release(nsnode);
226 if(FAILED(hres)) {
227 ERR("Could not get node\n");
228 return nsres;
231 if(node->vtbl->bind_to_tree)
232 node->vtbl->bind_to_tree(node);
234 node_release(node);
235 return nsres;
238 /* Calls undocumented 69 cmd of CGID_Explorer */
239 static void call_explorer_69(HTMLDocumentObj *doc)
241 IOleCommandTarget *olecmd;
242 VARIANT var;
243 HRESULT hres;
245 if(!doc->client)
246 return;
248 hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
249 if(FAILED(hres))
250 return;
252 VariantInit(&var);
253 hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
254 IOleCommandTarget_Release(olecmd);
255 if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
256 FIXME("handle result\n");
259 static void parse_complete(HTMLDocumentObj *doc)
261 TRACE("(%p)\n", doc);
263 if(doc->nscontainer->usermode == EDITMODE)
264 init_editor(doc->basedoc.doc_node);
266 call_explorer_69(doc);
267 if(doc->view_sink)
268 IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
269 call_property_onchanged(&doc->basedoc.cp_container, 1005);
270 call_explorer_69(doc);
272 if(doc->webbrowser && doc->nscontainer->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
273 IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
275 /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
278 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
280 TRACE("(%p)\n", This);
282 if(!This->basedoc.doc_obj)
283 return NS_OK;
285 if(This == This->basedoc.doc_obj->basedoc.doc_node) {
287 * This should be done in the worker thread that parses HTML,
288 * but we don't have such thread (Gecko parses HTML for us).
290 parse_complete(This->basedoc.doc_obj);
293 bind_event_scripts(This);
294 set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
295 return NS_OK;
298 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
300 nsIDOMHTMLScriptElement *nsscript;
301 HTMLScriptElement *script_elem;
302 nsIParser *nsparser = NULL;
303 script_queue_entry_t *iter;
304 HTMLInnerWindow *window;
305 nsresult nsres;
306 HRESULT hres;
308 TRACE("(%p)->(%p)\n", doc, script_iface);
310 window = doc->window;
311 if(!window)
312 return NS_OK;
314 nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
315 if(NS_FAILED(nsres)) {
316 ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
317 return nsres;
320 if(parser_iface) {
321 nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
322 if(NS_FAILED(nsres)) {
323 ERR("Could not get nsIParser iface: %08x\n", nsres);
324 nsparser = NULL;
328 hres = script_elem_from_nsscript(nsscript, &script_elem);
329 nsIDOMHTMLScriptElement_Release(nsscript);
330 if(FAILED(hres))
331 return NS_ERROR_FAILURE;
333 if(nsparser) {
334 nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
335 window->parser_callback_cnt++;
338 IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
340 doc_insert_script(window, script_elem, TRUE);
342 while(!list_empty(&window->script_queue)) {
343 iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
344 list_remove(&iter->entry);
345 if(!iter->script->parsed)
346 doc_insert_script(window, iter->script, TRUE);
347 IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
348 heap_free(iter);
351 IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
353 if(nsparser) {
354 window->parser_callback_cnt--;
355 nsIParser_EndEvaluatingParserInsertedScript(nsparser);
356 nsIParser_Release(nsparser);
359 IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
361 return NS_OK;
365 * We may change document mode only in early stage of document lifetime.
366 * Later attempts will not have an effect.
368 compat_mode_t lock_document_mode(HTMLDocumentNode *doc)
370 TRACE("%p: %d\n", doc, doc->document_mode);
372 doc->document_mode_locked = TRUE;
373 return doc->document_mode;
376 static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode, BOOL lock)
378 compat_mode_t max_compat_mode;
380 if(doc->document_mode_locked) {
381 WARN("attempting to set document mode %d on locked document %p\n", document_mode, doc);
382 return;
385 TRACE("%p: %d\n", doc, document_mode);
387 max_compat_mode = doc->window && doc->window->base.outer_window
388 ? get_max_compat_mode(doc->window->base.outer_window->uri)
389 : COMPAT_MODE_IE11;
390 if(max_compat_mode < document_mode) {
391 WARN("Tried to set compat mode %u higher than maximal configured %u\n",
392 document_mode, max_compat_mode);
393 document_mode = max_compat_mode;
396 doc->document_mode = document_mode;
397 if(lock)
398 lock_document_mode(doc);
401 BOOL parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
403 DWORD version = 0;
404 const WCHAR *p;
406 for(p = version_string; '0' <= *p && *p <= '9'; p++)
407 version = version * 10 + *p-'0';
408 if((*p && *p != ';') || p == version_string)
409 return FALSE;
411 switch(version){
412 case 5:
413 case 6:
414 *r = COMPAT_MODE_IE5;
415 break;
416 case 7:
417 *r = COMPAT_MODE_IE7;
418 break;
419 case 8:
420 *r = COMPAT_MODE_IE8;
421 break;
422 case 9:
423 *r = COMPAT_MODE_IE9;
424 break;
425 case 10:
426 *r = COMPAT_MODE_IE10;
427 break;
428 default:
429 *r = version < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
431 return TRUE;
434 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
436 static const WCHAR ie_eqW[] = {'I','E','='};
437 static const WCHAR edgeW[] = {'e','d','g','e'};
439 TRACE("%s\n", debugstr_w(p));
441 if(wcsnicmp(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
442 return FALSE;
443 p += 3;
445 if(!wcsnicmp(p, edgeW, ARRAY_SIZE(edgeW))) {
446 p += ARRAY_SIZE(edgeW);
447 if(*p && *p != ';')
448 return FALSE;
449 *r = COMPAT_MODE_IE11;
450 return TRUE;
453 return parse_compat_version(p, r);
456 void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
458 IWinInetHttpInfo *http_info;
459 char buf[1024];
460 DWORD size;
461 HRESULT hres;
463 hres = IBinding_QueryInterface(binding, &IID_IWinInetHttpInfo, (void**)&http_info);
464 if(FAILED(hres)) {
465 TRACE("No IWinInetHttpInfo\n");
466 return;
469 size = sizeof(buf);
470 strcpy(buf, "X-UA-Compatible");
471 hres = IWinInetHttpInfo_QueryInfo(http_info, HTTP_QUERY_CUSTOM, buf, &size, NULL, NULL);
472 if(hres == S_OK && size) {
473 compat_mode_t document_mode;
474 WCHAR *header;
476 TRACE("size %u\n", size);
478 header = heap_strdupAtoW(buf);
479 if(header && parse_ua_compatible(header, &document_mode)) {
480 TRACE("setting document mode %d\n", document_mode);
481 set_document_mode(doc, document_mode, FALSE);
483 heap_free(header);
486 IWinInetHttpInfo_Release(http_info);
489 static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
491 nsAString http_equiv_str, content_str;
492 nsresult nsres;
494 nsAString_Init(&http_equiv_str, NULL);
495 nsAString_Init(&content_str, NULL);
496 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
497 if(NS_SUCCEEDED(nsres))
498 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
500 if(NS_SUCCEEDED(nsres)) {
501 const PRUnichar *http_equiv, *content;
503 nsAString_GetData(&http_equiv_str, &http_equiv);
504 nsAString_GetData(&content_str, &content);
506 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
508 if(!wcsicmp(http_equiv, L"x-ua-compatible")) {
509 compat_mode_t document_mode;
510 if(parse_ua_compatible(content, &document_mode))
511 set_document_mode(doc, document_mode, TRUE);
512 else
513 FIXME("Unsupported document mode %s\n", debugstr_w(content));
517 nsAString_Finish(&http_equiv_str);
518 nsAString_Finish(&content_str);
521 typedef struct nsRunnable nsRunnable;
523 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
525 struct nsRunnable {
526 nsIRunnable nsIRunnable_iface;
528 LONG ref;
530 runnable_proc_t proc;
532 HTMLDocumentNode *doc;
533 nsISupports *arg1;
534 nsISupports *arg2;
537 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
539 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
542 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
543 nsIIDRef riid, void **result)
545 nsRunnable *This = impl_from_nsIRunnable(iface);
547 if(IsEqualGUID(riid, &IID_nsISupports)) {
548 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
549 *result = &This->nsIRunnable_iface;
550 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
551 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
552 *result = &This->nsIRunnable_iface;
553 }else {
554 *result = NULL;
555 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
556 return NS_NOINTERFACE;
559 nsISupports_AddRef((nsISupports*)*result);
560 return NS_OK;
563 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
565 nsRunnable *This = impl_from_nsIRunnable(iface);
566 LONG ref = InterlockedIncrement(&This->ref);
568 TRACE("(%p) ref=%d\n", This, ref);
570 return ref;
573 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
575 nsRunnable *This = impl_from_nsIRunnable(iface);
576 LONG ref = InterlockedDecrement(&This->ref);
578 TRACE("(%p) ref=%d\n", This, ref);
580 if(!ref) {
581 htmldoc_release(&This->doc->basedoc);
582 if(This->arg1)
583 nsISupports_Release(This->arg1);
584 if(This->arg2)
585 nsISupports_Release(This->arg2);
586 heap_free(This);
589 return ref;
592 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
594 nsRunnable *This = impl_from_nsIRunnable(iface);
596 return This->proc(This->doc, This->arg1, This->arg2);
599 static const nsIRunnableVtbl nsRunnableVtbl = {
600 nsRunnable_QueryInterface,
601 nsRunnable_AddRef,
602 nsRunnable_Release,
603 nsRunnable_Run
606 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
608 nsRunnable *runnable;
610 runnable = heap_alloc_zero(sizeof(*runnable));
611 if(!runnable)
612 return;
614 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
615 runnable->ref = 1;
617 htmldoc_addref(&This->basedoc);
618 runnable->doc = This;
619 runnable->proc = proc;
621 if(arg1)
622 nsISupports_AddRef(arg1);
623 runnable->arg1 = arg1;
625 if(arg2)
626 nsISupports_AddRef(arg2);
627 runnable->arg2 = arg2;
629 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
631 nsIRunnable_Release(&runnable->nsIRunnable_iface);
634 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
636 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
639 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
640 nsIIDRef riid, void **result)
642 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
644 if(IsEqualGUID(&IID_nsISupports, riid)) {
645 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
646 *result = &This->nsIDocumentObserver_iface;
647 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
648 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
649 *result = &This->nsIDocumentObserver_iface;
650 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
651 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
652 *result = &This->nsIDocumentObserver_iface;
653 }else {
654 *result = NULL;
655 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
656 return NS_NOINTERFACE;
659 htmldoc_addref(&This->basedoc);
660 return NS_OK;
663 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
665 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
666 return htmldoc_addref(&This->basedoc);
669 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
671 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
672 return htmldoc_release(&This->basedoc);
675 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
676 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
680 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
681 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
685 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
686 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
690 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
691 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
695 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
696 nsIContent *aContent, cpp_bool aIsRemove)
700 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
701 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
705 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
706 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
710 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
711 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
715 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
716 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
717 nsIContent *aProviousSibling)
721 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
725 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
729 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
730 nsUpdateType aUpdateType)
734 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
735 nsUpdateType aUpdateType)
739 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
743 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
745 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
747 TRACE("(%p)\n", This);
749 if(This->skip_mutation_notif)
750 return;
752 This->content_ready = TRUE;
753 add_script_runner(This, run_end_load, NULL, NULL);
756 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
757 nsIContent *aContent, EventStates aStateMask)
761 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
762 EventStates aStateMask)
766 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
767 cpp_bool aDocumentSheet)
771 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
772 cpp_bool aDocumentSheet)
776 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
777 mozilla_StyleSheetHandle aStyleSheet)
781 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
785 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
789 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
793 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
794 nsIContent *aContent)
796 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
797 nsIDOMHTMLIFrameElement *nsiframe;
798 nsIDOMHTMLFrameElement *nsframe;
799 nsIDOMHTMLScriptElement *nsscript;
800 nsIDOMHTMLMetaElement *nsmeta;
801 nsIDOMElement *nselem;
802 nsIDOMComment *nscomment;
803 nsresult nsres;
805 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
807 if(This->document_mode < COMPAT_MODE_IE10) {
808 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
809 if(NS_SUCCEEDED(nsres)) {
810 TRACE("comment node\n");
812 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
813 nsIDOMComment_Release(nscomment);
814 return;
818 if(This->document_mode == COMPAT_MODE_QUIRKS) {
819 nsIDOMDocumentType *nsdoctype;
821 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMDocumentType, (void**)&nsdoctype);
822 if(NS_SUCCEEDED(nsres)) {
823 compat_mode_t mode = COMPAT_MODE_IE7;
825 TRACE("doctype node\n");
827 if(This->window && This->window->base.outer_window) {
828 HTMLOuterWindow *window = This->window->base.outer_window;
829 DWORD zone;
830 HRESULT hres;
833 * Internet URL zone is treated differently. Native defaults to latest supported
834 * mode. We default to IE8. Ideally, we'd sync that with version used for IE=edge
835 * X-UA-Compatible version, allow configuration and default to higher version
836 * (once it's well supported).
838 hres = IInternetSecurityManager_MapUrlToZone(get_security_manager(), window->url, &zone, 0);
839 if(SUCCEEDED(hres) && zone == URLZONE_INTERNET)
840 mode = COMPAT_MODE_IE8;
843 set_document_mode(This, mode, FALSE);
844 nsIDOMDocumentType_Release(nsdoctype);
848 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
849 if(NS_FAILED(nsres))
850 return;
852 check_event_attr(This, nselem);
853 nsIDOMElement_Release(nselem);
855 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
856 if(NS_SUCCEEDED(nsres)) {
857 TRACE("iframe node\n");
859 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
860 nsIDOMHTMLIFrameElement_Release(nsiframe);
861 return;
864 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
865 if(NS_SUCCEEDED(nsres)) {
866 TRACE("frame node\n");
868 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
869 nsIDOMHTMLFrameElement_Release(nsframe);
870 return;
873 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
874 if(NS_SUCCEEDED(nsres)) {
875 TRACE("script element\n");
877 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsscript, NULL);
878 nsIDOMHTMLScriptElement_Release(nsscript);
879 return;
882 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
883 if(NS_SUCCEEDED(nsres)) {
884 process_meta_element(This, nsmeta);
885 nsIDOMHTMLMetaElement_Release(nsmeta);
889 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
890 nsIParser *aParser, cpp_bool *aBlock)
892 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
893 nsIDOMHTMLScriptElement *nsscript;
894 nsresult nsres;
896 TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
898 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
899 if(NS_SUCCEEDED(nsres)) {
900 TRACE("script node\n");
902 lock_document_mode(This);
903 add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
904 nsIDOMHTMLScriptElement_Release(nsscript);
908 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
909 nsDocumentObserver_QueryInterface,
910 nsDocumentObserver_AddRef,
911 nsDocumentObserver_Release,
912 nsDocumentObserver_CharacterDataWillChange,
913 nsDocumentObserver_CharacterDataChanged,
914 nsDocumentObserver_AttributeWillChange,
915 nsDocumentObserver_AttributeChanged,
916 nsDocumentObserver_NativeAnonymousChildListChange,
917 nsDocumentObserver_AttributeSetToCurrentValue,
918 nsDocumentObserver_ContentAppended,
919 nsDocumentObserver_ContentInserted,
920 nsDocumentObserver_ContentRemoved,
921 nsDocumentObserver_NodeWillBeDestroyed,
922 nsDocumentObserver_ParentChainChanged,
923 nsDocumentObserver_BeginUpdate,
924 nsDocumentObserver_EndUpdate,
925 nsDocumentObserver_BeginLoad,
926 nsDocumentObserver_EndLoad,
927 nsDocumentObserver_ContentStatesChanged,
928 nsDocumentObserver_DocumentStatesChanged,
929 nsDocumentObserver_StyleSheetAdded,
930 nsDocumentObserver_StyleSheetRemoved,
931 nsDocumentObserver_StyleSheetApplicableStateChanged,
932 nsDocumentObserver_StyleRuleChanged,
933 nsDocumentObserver_StyleRuleAdded,
934 nsDocumentObserver_StyleRuleRemoved,
935 nsDocumentObserver_BindToDocument,
936 nsDocumentObserver_AttemptToExecuteScript
939 void init_document_mutation(HTMLDocumentNode *doc)
941 nsIDocument *nsdoc;
942 nsresult nsres;
944 doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
946 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
947 if(NS_FAILED(nsres)) {
948 ERR("Could not get nsIDocument: %08x\n", nsres);
949 return;
952 nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
953 nsIDocument_Release(nsdoc);
956 void release_document_mutation(HTMLDocumentNode *doc)
958 nsIDocument *nsdoc;
959 nsresult nsres;
961 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
962 if(NS_FAILED(nsres)) {
963 ERR("Could not get nsIDocument: %08x\n", nsres);
964 return;
967 nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
968 nsIDocument_Release(nsdoc);
971 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
973 nsIDocument *doc;
974 JSContext *ctx;
975 nsresult nsres;
977 nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
978 assert(nsres == NS_OK);
980 ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
981 nsIDocument_Release(doc);
983 TRACE("ret %p\n", ctx);
984 return ctx;
987 void init_mutation(nsIComponentManager *component_manager)
989 nsIFactory *factory;
990 nsresult nsres;
992 if(!component_manager) {
993 if(content_utils) {
994 nsIContentUtils_Release(content_utils);
995 content_utils = NULL;
997 return;
1000 nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
1001 &IID_nsIFactory, (void**)&factory);
1002 if(NS_FAILED(nsres)) {
1003 ERR("Could not create nsIContentUtils service: %08x\n", nsres);
1004 return;
1007 nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
1008 nsIFactory_Release(factory);
1009 if(NS_FAILED(nsres))
1010 ERR("Could not create nsIContentUtils instance: %08x\n", nsres);