makefiles: Explicitly create destination dirs when installing symlinks.
[wine/zf.git] / dlls / mshtml / mutation.c
blob96490f9abd9d40ba07fbfec0bb37893bfded1293
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 static const WCHAR x_ua_compatibleW[] = {'x','-','u','a','-','c','o','m','p','a','t','i','b','l','e',0};
496 nsAString_Init(&http_equiv_str, NULL);
497 nsAString_Init(&content_str, NULL);
498 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
499 if(NS_SUCCEEDED(nsres))
500 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
502 if(NS_SUCCEEDED(nsres)) {
503 const PRUnichar *http_equiv, *content;
505 nsAString_GetData(&http_equiv_str, &http_equiv);
506 nsAString_GetData(&content_str, &content);
508 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
510 if(!wcsicmp(http_equiv, x_ua_compatibleW)) {
511 compat_mode_t document_mode;
512 if(parse_ua_compatible(content, &document_mode))
513 set_document_mode(doc, document_mode, TRUE);
514 else
515 FIXME("Unsupported document mode %s\n", debugstr_w(content));
519 nsAString_Finish(&http_equiv_str);
520 nsAString_Finish(&content_str);
523 typedef struct nsRunnable nsRunnable;
525 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
527 struct nsRunnable {
528 nsIRunnable nsIRunnable_iface;
530 LONG ref;
532 runnable_proc_t proc;
534 HTMLDocumentNode *doc;
535 nsISupports *arg1;
536 nsISupports *arg2;
539 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
541 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
544 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
545 nsIIDRef riid, void **result)
547 nsRunnable *This = impl_from_nsIRunnable(iface);
549 if(IsEqualGUID(riid, &IID_nsISupports)) {
550 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
551 *result = &This->nsIRunnable_iface;
552 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
553 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
554 *result = &This->nsIRunnable_iface;
555 }else {
556 *result = NULL;
557 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
558 return NS_NOINTERFACE;
561 nsISupports_AddRef((nsISupports*)*result);
562 return NS_OK;
565 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
567 nsRunnable *This = impl_from_nsIRunnable(iface);
568 LONG ref = InterlockedIncrement(&This->ref);
570 TRACE("(%p) ref=%d\n", This, ref);
572 return ref;
575 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
577 nsRunnable *This = impl_from_nsIRunnable(iface);
578 LONG ref = InterlockedDecrement(&This->ref);
580 TRACE("(%p) ref=%d\n", This, ref);
582 if(!ref) {
583 htmldoc_release(&This->doc->basedoc);
584 if(This->arg1)
585 nsISupports_Release(This->arg1);
586 if(This->arg2)
587 nsISupports_Release(This->arg2);
588 heap_free(This);
591 return ref;
594 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
596 nsRunnable *This = impl_from_nsIRunnable(iface);
598 return This->proc(This->doc, This->arg1, This->arg2);
601 static const nsIRunnableVtbl nsRunnableVtbl = {
602 nsRunnable_QueryInterface,
603 nsRunnable_AddRef,
604 nsRunnable_Release,
605 nsRunnable_Run
608 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
610 nsRunnable *runnable;
612 runnable = heap_alloc_zero(sizeof(*runnable));
613 if(!runnable)
614 return;
616 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
617 runnable->ref = 1;
619 htmldoc_addref(&This->basedoc);
620 runnable->doc = This;
621 runnable->proc = proc;
623 if(arg1)
624 nsISupports_AddRef(arg1);
625 runnable->arg1 = arg1;
627 if(arg2)
628 nsISupports_AddRef(arg2);
629 runnable->arg2 = arg2;
631 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
633 nsIRunnable_Release(&runnable->nsIRunnable_iface);
636 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
638 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
641 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
642 nsIIDRef riid, void **result)
644 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
646 if(IsEqualGUID(&IID_nsISupports, riid)) {
647 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
648 *result = &This->nsIDocumentObserver_iface;
649 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
650 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
651 *result = &This->nsIDocumentObserver_iface;
652 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
653 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
654 *result = &This->nsIDocumentObserver_iface;
655 }else {
656 *result = NULL;
657 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
658 return NS_NOINTERFACE;
661 htmldoc_addref(&This->basedoc);
662 return NS_OK;
665 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
667 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
668 return htmldoc_addref(&This->basedoc);
671 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
673 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
674 return htmldoc_release(&This->basedoc);
677 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
678 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
682 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
683 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
687 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
688 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
692 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
693 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
697 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
698 nsIContent *aContent, cpp_bool aIsRemove)
702 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
703 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
707 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
708 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
712 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
713 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
717 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
718 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
719 nsIContent *aProviousSibling)
723 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
727 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
731 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
732 nsUpdateType aUpdateType)
736 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
737 nsUpdateType aUpdateType)
741 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
745 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
747 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
749 TRACE("(%p)\n", This);
751 if(This->skip_mutation_notif)
752 return;
754 This->content_ready = TRUE;
755 add_script_runner(This, run_end_load, NULL, NULL);
758 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
759 nsIContent *aContent, EventStates aStateMask)
763 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
764 EventStates aStateMask)
768 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
769 cpp_bool aDocumentSheet)
773 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
774 cpp_bool aDocumentSheet)
778 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
779 mozilla_StyleSheetHandle aStyleSheet)
783 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
787 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
791 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
795 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
796 nsIContent *aContent)
798 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
799 nsIDOMHTMLIFrameElement *nsiframe;
800 nsIDOMHTMLFrameElement *nsframe;
801 nsIDOMHTMLScriptElement *nsscript;
802 nsIDOMHTMLMetaElement *nsmeta;
803 nsIDOMElement *nselem;
804 nsIDOMComment *nscomment;
805 nsresult nsres;
807 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
809 if(This->document_mode < COMPAT_MODE_IE10) {
810 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
811 if(NS_SUCCEEDED(nsres)) {
812 TRACE("comment node\n");
814 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
815 nsIDOMComment_Release(nscomment);
816 return;
820 if(This->document_mode == COMPAT_MODE_QUIRKS) {
821 nsIDOMDocumentType *nsdoctype;
823 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMDocumentType, (void**)&nsdoctype);
824 if(NS_SUCCEEDED(nsres)) {
825 compat_mode_t mode = COMPAT_MODE_IE7;
827 TRACE("doctype node\n");
829 if(This->window && This->window->base.outer_window) {
830 HTMLOuterWindow *window = This->window->base.outer_window;
831 DWORD zone;
832 HRESULT hres;
835 * Internet URL zone is treated differently. Native defaults to latest supported
836 * mode. We default to IE8. Ideally, we'd sync that with version used for IE=edge
837 * X-UA-Compatible version, allow configuration and default to higher version
838 * (once it's well supported).
840 hres = IInternetSecurityManager_MapUrlToZone(get_security_manager(), window->url, &zone, 0);
841 if(SUCCEEDED(hres) && zone == URLZONE_INTERNET)
842 mode = COMPAT_MODE_IE8;
845 set_document_mode(This, mode, FALSE);
846 nsIDOMDocumentType_Release(nsdoctype);
850 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
851 if(NS_FAILED(nsres))
852 return;
854 check_event_attr(This, nselem);
855 nsIDOMElement_Release(nselem);
857 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
858 if(NS_SUCCEEDED(nsres)) {
859 TRACE("iframe node\n");
861 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
862 nsIDOMHTMLIFrameElement_Release(nsiframe);
863 return;
866 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
867 if(NS_SUCCEEDED(nsres)) {
868 TRACE("frame node\n");
870 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
871 nsIDOMHTMLFrameElement_Release(nsframe);
872 return;
875 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
876 if(NS_SUCCEEDED(nsres)) {
877 TRACE("script element\n");
879 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsscript, NULL);
880 nsIDOMHTMLScriptElement_Release(nsscript);
881 return;
884 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
885 if(NS_SUCCEEDED(nsres)) {
886 process_meta_element(This, nsmeta);
887 nsIDOMHTMLMetaElement_Release(nsmeta);
891 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
892 nsIParser *aParser, cpp_bool *aBlock)
894 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
895 nsIDOMHTMLScriptElement *nsscript;
896 nsresult nsres;
898 TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
900 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
901 if(NS_SUCCEEDED(nsres)) {
902 TRACE("script node\n");
904 lock_document_mode(This);
905 add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
906 nsIDOMHTMLScriptElement_Release(nsscript);
910 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
911 nsDocumentObserver_QueryInterface,
912 nsDocumentObserver_AddRef,
913 nsDocumentObserver_Release,
914 nsDocumentObserver_CharacterDataWillChange,
915 nsDocumentObserver_CharacterDataChanged,
916 nsDocumentObserver_AttributeWillChange,
917 nsDocumentObserver_AttributeChanged,
918 nsDocumentObserver_NativeAnonymousChildListChange,
919 nsDocumentObserver_AttributeSetToCurrentValue,
920 nsDocumentObserver_ContentAppended,
921 nsDocumentObserver_ContentInserted,
922 nsDocumentObserver_ContentRemoved,
923 nsDocumentObserver_NodeWillBeDestroyed,
924 nsDocumentObserver_ParentChainChanged,
925 nsDocumentObserver_BeginUpdate,
926 nsDocumentObserver_EndUpdate,
927 nsDocumentObserver_BeginLoad,
928 nsDocumentObserver_EndLoad,
929 nsDocumentObserver_ContentStatesChanged,
930 nsDocumentObserver_DocumentStatesChanged,
931 nsDocumentObserver_StyleSheetAdded,
932 nsDocumentObserver_StyleSheetRemoved,
933 nsDocumentObserver_StyleSheetApplicableStateChanged,
934 nsDocumentObserver_StyleRuleChanged,
935 nsDocumentObserver_StyleRuleAdded,
936 nsDocumentObserver_StyleRuleRemoved,
937 nsDocumentObserver_BindToDocument,
938 nsDocumentObserver_AttemptToExecuteScript
941 void init_document_mutation(HTMLDocumentNode *doc)
943 nsIDocument *nsdoc;
944 nsresult nsres;
946 doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
948 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
949 if(NS_FAILED(nsres)) {
950 ERR("Could not get nsIDocument: %08x\n", nsres);
951 return;
954 nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
955 nsIDocument_Release(nsdoc);
958 void release_document_mutation(HTMLDocumentNode *doc)
960 nsIDocument *nsdoc;
961 nsresult nsres;
963 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
964 if(NS_FAILED(nsres)) {
965 ERR("Could not get nsIDocument: %08x\n", nsres);
966 return;
969 nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
970 nsIDocument_Release(nsdoc);
973 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
975 nsIDocument *doc;
976 JSContext *ctx;
977 nsresult nsres;
979 nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
980 assert(nsres == NS_OK);
982 ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
983 nsIDocument_Release(doc);
985 TRACE("ret %p\n", ctx);
986 return ctx;
989 void init_mutation(nsIComponentManager *component_manager)
991 nsIFactory *factory;
992 nsresult nsres;
994 if(!component_manager) {
995 if(content_utils) {
996 nsIContentUtils_Release(content_utils);
997 content_utils = NULL;
999 return;
1002 nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
1003 &IID_nsIFactory, (void**)&factory);
1004 if(NS_FAILED(nsres)) {
1005 ERR("Could not create nsIContentUtils service: %08x\n", nsres);
1006 return;
1009 nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
1010 nsIFactory_Release(factory);
1011 if(NS_FAILED(nsres))
1012 ERR("Could not create nsIContentUtils instance: %08x\n", nsres);