widl: Use for_each_iface in get_size_procformatstring.
[wine.git] / dlls / mshtml / mutation.c
blob1a1cfe358cd0c89a8716f8ecbf02f68d7ddc6c66
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"
32 #include "wininet.h"
34 #include "mshtml_private.h"
35 #include "htmlscript.h"
36 #include "htmlevent.h"
37 #include "binding.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43 const compat_mode_info_t compat_mode_info[] = {
44 { 5, 7 }, /* DOCMODE_QUIRKS */
45 { 5, 5 }, /* DOCMODE_IE5 */
46 { 7, 7 }, /* DOCMODE_IE7 */
47 { 8, 8 }, /* DOCMODE_IE8 */
48 { 9, 9 }, /* DOCMODE_IE8 */
49 { 10, 10 }, /* DOCMODE_IE10 */
50 { 11, 11 } /* DOCMODE_IE11 */
53 static const IID NS_ICONTENTUTILS_CID =
54 {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
56 static nsIContentUtils *content_utils;
58 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
60 unsigned majorv = 0, minorv = 0, compat_version;
61 const PRUnichar *ptr, *end;
62 PRUnichar *buf;
63 DWORD len;
65 enum {
66 CMP_EQ,
67 CMP_LT,
68 CMP_LTE,
69 CMP_GT,
70 CMP_GTE
71 } cmpt = CMP_EQ;
73 static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
75 if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
76 return NULL;
78 ptr = comment+3;
79 while(isspaceW(*ptr))
80 ptr++;
82 if(ptr[0] == 'l' && ptr[1] == 't') {
83 ptr += 2;
84 if(*ptr == 'e') {
85 cmpt = CMP_LTE;
86 ptr++;
87 }else {
88 cmpt = CMP_LT;
90 }else if(ptr[0] == 'g' && ptr[1] == 't') {
91 ptr += 2;
92 if(*ptr == 'e') {
93 cmpt = CMP_GTE;
94 ptr++;
95 }else {
96 cmpt = CMP_GT;
100 if(!isspaceW(*ptr++))
101 return NULL;
102 while(isspaceW(*ptr))
103 ptr++;
105 if(ptr[0] != 'I' || ptr[1] != 'E')
106 return NULL;
108 ptr +=2;
109 if(!isspaceW(*ptr++))
110 return NULL;
111 while(isspaceW(*ptr))
112 ptr++;
114 if(!isdigitW(*ptr))
115 return NULL;
116 while(isdigitW(*ptr))
117 majorv = majorv*10 + (*ptr++ - '0');
119 if(*ptr == '.') {
120 ptr++;
121 if(!isdigitW(*ptr))
122 return NULL;
123 while(isdigitW(*ptr))
124 minorv = minorv*10 + (*ptr++ - '0');
127 while(isspaceW(*ptr))
128 ptr++;
129 if(ptr[0] != ']' || ptr[1] != '>')
130 return NULL;
131 ptr += 2;
133 len = strlenW(ptr);
134 if(len < ARRAY_SIZE(endifW))
135 return NULL;
137 end = ptr + len - ARRAY_SIZE(endifW);
138 if(memcmp(end, endifW, sizeof(endifW)))
139 return NULL;
141 compat_version = compat_mode_info[doc->document_mode].ie_version;
143 switch(cmpt) {
144 case CMP_EQ:
145 if(compat_version == majorv && !minorv)
146 break;
147 return NULL;
148 case CMP_LT:
149 if(compat_version < majorv || (compat_version == majorv && minorv))
150 break;
151 return NULL;
152 case CMP_LTE:
153 if(compat_version <= majorv)
154 break;
155 return NULL;
156 case CMP_GT:
157 if(compat_version > majorv)
158 break;
159 return NULL;
160 case CMP_GTE:
161 if(compat_version >= majorv || (compat_version == majorv && !minorv))
162 break;
163 return NULL;
166 buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
167 if(!buf)
168 return NULL;
170 memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
171 buf[end-ptr] = 0;
173 return buf;
176 static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
178 const PRUnichar *comment;
179 nsIDOMComment *nscomment;
180 PRUnichar *replace_html;
181 nsAString comment_str;
182 nsresult nsres;
184 nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
185 if(NS_FAILED(nsres)) {
186 ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
187 return nsres;
190 nsAString_Init(&comment_str, NULL);
191 nsres = nsIDOMComment_GetData(nscomment, &comment_str);
192 if(NS_FAILED(nsres))
193 return nsres;
195 nsAString_GetData(&comment_str, &comment);
196 replace_html = handle_insert_comment(doc, comment);
197 nsAString_Finish(&comment_str);
199 if(replace_html) {
200 HRESULT hres;
202 hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
203 heap_free(replace_html);
204 if(FAILED(hres))
205 nsres = NS_ERROR_FAILURE;
209 nsIDOMComment_Release(nscomment);
210 return nsres;
213 static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
215 nsIDOMNode *nsnode;
216 HTMLDOMNode *node;
217 nsresult nsres;
218 HRESULT hres;
220 TRACE("(%p)->(%p)\n", doc, nsiface);
222 nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
223 if(NS_FAILED(nsres))
224 return nsres;
226 hres = get_node(nsnode, TRUE, &node);
227 nsIDOMNode_Release(nsnode);
228 if(FAILED(hres)) {
229 ERR("Could not get node\n");
230 return nsres;
233 if(node->vtbl->bind_to_tree)
234 node->vtbl->bind_to_tree(node);
236 node_release(node);
237 return nsres;
240 /* Calls undocumented 69 cmd of CGID_Explorer */
241 static void call_explorer_69(HTMLDocumentObj *doc)
243 IOleCommandTarget *olecmd;
244 VARIANT var;
245 HRESULT hres;
247 if(!doc->client)
248 return;
250 hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
251 if(FAILED(hres))
252 return;
254 VariantInit(&var);
255 hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
256 IOleCommandTarget_Release(olecmd);
257 if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
258 FIXME("handle result\n");
261 static void parse_complete(HTMLDocumentObj *doc)
263 TRACE("(%p)\n", doc);
265 if(doc->usermode == EDITMODE)
266 init_editor(&doc->basedoc);
268 call_explorer_69(doc);
269 if(doc->view_sink)
270 IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
271 call_property_onchanged(&doc->basedoc.cp_container, 1005);
272 call_explorer_69(doc);
274 if(doc->webbrowser && doc->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
275 IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
277 /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
280 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
282 TRACE("(%p)\n", This);
284 if(!This->basedoc.doc_obj)
285 return NS_OK;
287 if(This == This->basedoc.doc_obj->basedoc.doc_node) {
289 * This should be done in the worker thread that parses HTML,
290 * but we don't have such thread (Gecko parses HTML for us).
292 parse_complete(This->basedoc.doc_obj);
295 bind_event_scripts(This);
296 set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
297 return NS_OK;
300 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
302 nsIDOMHTMLScriptElement *nsscript;
303 HTMLScriptElement *script_elem;
304 nsIParser *nsparser = NULL;
305 script_queue_entry_t *iter;
306 HTMLInnerWindow *window;
307 nsresult nsres;
308 HRESULT hres;
310 TRACE("(%p)->(%p)\n", doc, script_iface);
312 window = doc->window;
313 if(!window)
314 return NS_OK;
316 nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
317 if(NS_FAILED(nsres)) {
318 ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
319 return nsres;
322 if(parser_iface) {
323 nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
324 if(NS_FAILED(nsres)) {
325 ERR("Could not get nsIParser iface: %08x\n", nsres);
326 nsparser = NULL;
330 hres = script_elem_from_nsscript(nsscript, &script_elem);
331 nsIDOMHTMLScriptElement_Release(nsscript);
332 if(FAILED(hres))
333 return NS_ERROR_FAILURE;
335 if(nsparser) {
336 nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
337 window->parser_callback_cnt++;
340 IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
342 doc_insert_script(window, script_elem, TRUE);
344 while(!list_empty(&window->script_queue)) {
345 iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
346 list_remove(&iter->entry);
347 if(!iter->script->parsed)
348 doc_insert_script(window, iter->script, TRUE);
349 IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
350 heap_free(iter);
353 IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
355 if(nsparser) {
356 window->parser_callback_cnt--;
357 nsIParser_EndEvaluatingParserInsertedScript(nsparser);
358 nsIParser_Release(nsparser);
361 IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
363 return NS_OK;
367 * We may change document mode only in early stage of document lifetime.
368 * Later attempts will not have an effect.
370 compat_mode_t lock_document_mode(HTMLDocumentNode *doc)
372 TRACE("%p: %d\n", doc, doc->document_mode);
374 doc->document_mode_locked = TRUE;
375 return doc->document_mode;
378 static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode, BOOL lock)
380 compat_mode_t max_compat_mode;
382 if(doc->document_mode_locked) {
383 WARN("attempting to set document mode %d on locked document %p\n", document_mode, doc);
384 return;
387 TRACE("%p: %d\n", doc, document_mode);
389 max_compat_mode = doc->window && doc->window->base.outer_window
390 ? get_max_compat_mode(doc->window->base.outer_window->uri)
391 : COMPAT_MODE_IE11;
392 if(max_compat_mode < document_mode) {
393 WARN("Tried to set compat mode %u higher than maximal configured %u\n",
394 document_mode, max_compat_mode);
395 document_mode = max_compat_mode;
398 doc->document_mode = document_mode;
399 if(lock)
400 lock_document_mode(doc);
403 BOOL parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
405 DWORD version = 0;
406 const WCHAR *p;
408 for(p = version_string; '0' <= *p && *p <= '9'; p++)
409 version = version * 10 + *p-'0';
410 if(*p || p == version_string)
411 return FALSE;
413 switch(version){
414 case 5:
415 case 6:
416 *r = COMPAT_MODE_IE5;
417 break;
418 case 7:
419 *r = COMPAT_MODE_IE7;
420 break;
421 case 8:
422 *r = COMPAT_MODE_IE8;
423 break;
424 case 9:
425 *r = COMPAT_MODE_IE9;
426 break;
427 case 10:
428 *r = COMPAT_MODE_IE10;
429 break;
430 default:
431 *r = version < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
433 return TRUE;
436 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
438 static const WCHAR ie_eqW[] = {'I','E','='};
439 static const WCHAR edgeW[] = {'e','d','g','e',0};
441 TRACE("%s\n", debugstr_w(p));
443 if(strncmpiW(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
444 return FALSE;
445 p += 3;
447 if(!strcmpiW(p, edgeW)) {
448 *r = COMPAT_MODE_IE11;
449 return TRUE;
452 return parse_compat_version(p, r);
455 void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
457 IWinInetHttpInfo *http_info;
458 char buf[1024];
459 DWORD size;
460 HRESULT hres;
462 hres = IBinding_QueryInterface(binding, &IID_IWinInetHttpInfo, (void**)&http_info);
463 if(FAILED(hres)) {
464 TRACE("No IWinInetHttpInfo\n");
465 return;
468 size = sizeof(buf);
469 strcpy(buf, "X-UA-Compatible");
470 hres = IWinInetHttpInfo_QueryInfo(http_info, HTTP_QUERY_CUSTOM, buf, &size, NULL, NULL);
471 if(hres == S_OK && size) {
472 compat_mode_t document_mode;
473 WCHAR *header;
475 TRACE("size %u\n", size);
477 header = heap_strdupAtoW(buf);
478 if(header && parse_ua_compatible(header, &document_mode)) {
479 TRACE("setting document mode %d\n", document_mode);
480 set_document_mode(doc, document_mode, FALSE);
482 heap_free(header);
485 IWinInetHttpInfo_Release(http_info);
488 static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
490 nsAString http_equiv_str, content_str;
491 nsresult nsres;
493 static const WCHAR x_ua_compatibleW[] = {'x','-','u','a','-','c','o','m','p','a','t','i','b','l','e',0};
495 nsAString_Init(&http_equiv_str, NULL);
496 nsAString_Init(&content_str, NULL);
497 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
498 if(NS_SUCCEEDED(nsres))
499 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
501 if(NS_SUCCEEDED(nsres)) {
502 const PRUnichar *http_equiv, *content;
504 nsAString_GetData(&http_equiv_str, &http_equiv);
505 nsAString_GetData(&content_str, &content);
507 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
509 if(!strcmpiW(http_equiv, x_ua_compatibleW)) {
510 compat_mode_t document_mode;
511 if(parse_ua_compatible(content, &document_mode))
512 set_document_mode(doc, document_mode, TRUE);
513 else
514 FIXME("Unsupported document mode %s\n", debugstr_w(content));
518 nsAString_Finish(&http_equiv_str);
519 nsAString_Finish(&content_str);
522 typedef struct nsRunnable nsRunnable;
524 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
526 struct nsRunnable {
527 nsIRunnable nsIRunnable_iface;
529 LONG ref;
531 runnable_proc_t proc;
533 HTMLDocumentNode *doc;
534 nsISupports *arg1;
535 nsISupports *arg2;
538 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
540 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
543 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
544 nsIIDRef riid, void **result)
546 nsRunnable *This = impl_from_nsIRunnable(iface);
548 if(IsEqualGUID(riid, &IID_nsISupports)) {
549 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
550 *result = &This->nsIRunnable_iface;
551 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
552 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
553 *result = &This->nsIRunnable_iface;
554 }else {
555 *result = NULL;
556 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
557 return NS_NOINTERFACE;
560 nsISupports_AddRef((nsISupports*)*result);
561 return NS_OK;
564 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
566 nsRunnable *This = impl_from_nsIRunnable(iface);
567 LONG ref = InterlockedIncrement(&This->ref);
569 TRACE("(%p) ref=%d\n", This, ref);
571 return ref;
574 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
576 nsRunnable *This = impl_from_nsIRunnable(iface);
577 LONG ref = InterlockedDecrement(&This->ref);
579 TRACE("(%p) ref=%d\n", This, ref);
581 if(!ref) {
582 htmldoc_release(&This->doc->basedoc);
583 if(This->arg1)
584 nsISupports_Release(This->arg1);
585 if(This->arg2)
586 nsISupports_Release(This->arg2);
587 heap_free(This);
590 return ref;
593 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
595 nsRunnable *This = impl_from_nsIRunnable(iface);
597 return This->proc(This->doc, This->arg1, This->arg2);
600 static const nsIRunnableVtbl nsRunnableVtbl = {
601 nsRunnable_QueryInterface,
602 nsRunnable_AddRef,
603 nsRunnable_Release,
604 nsRunnable_Run
607 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
609 nsRunnable *runnable;
611 runnable = heap_alloc_zero(sizeof(*runnable));
612 if(!runnable)
613 return;
615 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
616 runnable->ref = 1;
618 htmldoc_addref(&This->basedoc);
619 runnable->doc = This;
620 runnable->proc = proc;
622 if(arg1)
623 nsISupports_AddRef(arg1);
624 runnable->arg1 = arg1;
626 if(arg2)
627 nsISupports_AddRef(arg2);
628 runnable->arg2 = arg2;
630 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
632 nsIRunnable_Release(&runnable->nsIRunnable_iface);
635 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
637 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
640 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
641 nsIIDRef riid, void **result)
643 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
645 if(IsEqualGUID(&IID_nsISupports, riid)) {
646 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
647 *result = &This->nsIDocumentObserver_iface;
648 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
649 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
650 *result = &This->nsIDocumentObserver_iface;
651 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
652 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
653 *result = &This->nsIDocumentObserver_iface;
654 }else {
655 *result = NULL;
656 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
657 return NS_NOINTERFACE;
660 htmldoc_addref(&This->basedoc);
661 return NS_OK;
664 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
666 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
667 return htmldoc_addref(&This->basedoc);
670 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
672 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
673 return htmldoc_release(&This->basedoc);
676 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
677 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
681 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
682 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
686 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
687 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
691 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
692 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
696 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
697 nsIContent *aContent, cpp_bool aIsRemove)
701 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
702 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
706 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
707 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
711 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
712 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
716 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
717 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
718 nsIContent *aProviousSibling)
722 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
726 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
730 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
731 nsUpdateType aUpdateType)
735 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
736 nsUpdateType aUpdateType)
740 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
744 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
746 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
748 TRACE("(%p)\n", This);
750 if(This->skip_mutation_notif)
751 return;
753 This->content_ready = TRUE;
754 add_script_runner(This, run_end_load, NULL, NULL);
757 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
758 nsIContent *aContent, EventStates aStateMask)
762 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
763 EventStates aStateMask)
767 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
768 cpp_bool aDocumentSheet)
772 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
773 cpp_bool aDocumentSheet)
777 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
778 mozilla_StyleSheetHandle aStyleSheet)
782 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
786 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
790 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
794 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
795 nsIContent *aContent)
797 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
798 nsIDOMHTMLIFrameElement *nsiframe;
799 nsIDOMHTMLFrameElement *nsframe;
800 nsIDOMHTMLScriptElement *nsscript;
801 nsIDOMHTMLMetaElement *nsmeta;
802 nsIDOMElement *nselem;
803 nsIDOMComment *nscomment;
804 nsresult nsres;
806 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
808 if(This->document_mode < COMPAT_MODE_IE10) {
809 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
810 if(NS_SUCCEEDED(nsres)) {
811 TRACE("comment node\n");
813 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
814 nsIDOMComment_Release(nscomment);
815 return;
819 if(This->document_mode == COMPAT_MODE_QUIRKS) {
820 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(window->secmgr, 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);