api-ms-win-core-comm-l1-1-0: Add dll.
[wine.git] / dlls / mshtml / mutation.c
blob6508270d35f6837ba4ea03e7906a4a365a08d656
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 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 doc->document_mode = document_mode;
388 if(lock)
389 lock_document_mode(doc);
392 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
394 int v = 0;
396 static const WCHAR ie_eqW[] = {'I','E','='};
397 static const WCHAR edgeW[] = {'e','d','g','e',0};
399 TRACE("%s\n", debugstr_w(p));
401 if(strncmpiW(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
402 return FALSE;
403 p += 3;
405 if(!strcmpiW(p, edgeW)) {
406 *r = COMPAT_MODE_IE11;
407 return TRUE;
410 while('0' <= *p && *p <= '9')
411 v = v*10 + *(p++)-'0';
412 if(*p || !v)
413 return FALSE;
415 switch(v){
416 case 5:
417 case 6:
418 *r = COMPAT_MODE_IE5;
419 break;
420 case 7:
421 *r = COMPAT_MODE_IE7;
422 break;
423 case 8:
424 *r = COMPAT_MODE_IE8;
425 break;
426 case 9:
427 *r = COMPAT_MODE_IE9;
428 break;
429 case 10:
430 *r = COMPAT_MODE_IE10;
431 break;
432 default:
433 *r = v < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
436 return TRUE;
439 void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
441 IWinInetHttpInfo *http_info;
442 char buf[1024];
443 DWORD size;
444 HRESULT hres;
446 hres = IBinding_QueryInterface(binding, &IID_IWinInetHttpInfo, (void**)&http_info);
447 if(FAILED(hres)) {
448 TRACE("No IWinInetHttpInfo\n");
449 return;
452 size = sizeof(buf);
453 strcpy(buf, "X-UA-Compatible");
454 hres = IWinInetHttpInfo_QueryInfo(http_info, HTTP_QUERY_CUSTOM, buf, &size, NULL, NULL);
455 if(hres == S_OK && size) {
456 compat_mode_t document_mode;
457 WCHAR *header;
459 TRACE("size %u\n", size);
461 header = heap_strdupAtoW(buf);
462 if(header && parse_ua_compatible(header, &document_mode)) {
463 TRACE("setting document mode %d\n", document_mode);
464 doc->document_mode = document_mode;
466 heap_free(header);
469 IWinInetHttpInfo_Release(http_info);
472 static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
474 nsAString http_equiv_str, content_str;
475 nsresult nsres;
477 static const WCHAR x_ua_compatibleW[] = {'x','-','u','a','-','c','o','m','p','a','t','i','b','l','e',0};
479 nsAString_Init(&http_equiv_str, NULL);
480 nsAString_Init(&content_str, NULL);
481 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
482 if(NS_SUCCEEDED(nsres))
483 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
485 if(NS_SUCCEEDED(nsres)) {
486 const PRUnichar *http_equiv, *content;
488 nsAString_GetData(&http_equiv_str, &http_equiv);
489 nsAString_GetData(&content_str, &content);
491 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
493 if(!strcmpiW(http_equiv, x_ua_compatibleW)) {
494 compat_mode_t document_mode;
495 if(parse_ua_compatible(content, &document_mode))
496 set_document_mode(doc, document_mode, TRUE);
497 else
498 FIXME("Unsupported document mode %s\n", debugstr_w(content));
502 nsAString_Finish(&http_equiv_str);
503 nsAString_Finish(&content_str);
506 typedef struct nsRunnable nsRunnable;
508 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
510 struct nsRunnable {
511 nsIRunnable nsIRunnable_iface;
513 LONG ref;
515 runnable_proc_t proc;
517 HTMLDocumentNode *doc;
518 nsISupports *arg1;
519 nsISupports *arg2;
522 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
524 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
527 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
528 nsIIDRef riid, void **result)
530 nsRunnable *This = impl_from_nsIRunnable(iface);
532 if(IsEqualGUID(riid, &IID_nsISupports)) {
533 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
534 *result = &This->nsIRunnable_iface;
535 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
536 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
537 *result = &This->nsIRunnable_iface;
538 }else {
539 *result = NULL;
540 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
541 return NS_NOINTERFACE;
544 nsISupports_AddRef((nsISupports*)*result);
545 return NS_OK;
548 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
550 nsRunnable *This = impl_from_nsIRunnable(iface);
551 LONG ref = InterlockedIncrement(&This->ref);
553 TRACE("(%p) ref=%d\n", This, ref);
555 return ref;
558 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
560 nsRunnable *This = impl_from_nsIRunnable(iface);
561 LONG ref = InterlockedDecrement(&This->ref);
563 TRACE("(%p) ref=%d\n", This, ref);
565 if(!ref) {
566 htmldoc_release(&This->doc->basedoc);
567 if(This->arg1)
568 nsISupports_Release(This->arg1);
569 if(This->arg2)
570 nsISupports_Release(This->arg2);
571 heap_free(This);
574 return ref;
577 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
579 nsRunnable *This = impl_from_nsIRunnable(iface);
581 return This->proc(This->doc, This->arg1, This->arg2);
584 static const nsIRunnableVtbl nsRunnableVtbl = {
585 nsRunnable_QueryInterface,
586 nsRunnable_AddRef,
587 nsRunnable_Release,
588 nsRunnable_Run
591 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
593 nsRunnable *runnable;
595 runnable = heap_alloc_zero(sizeof(*runnable));
596 if(!runnable)
597 return;
599 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
600 runnable->ref = 1;
602 htmldoc_addref(&This->basedoc);
603 runnable->doc = This;
604 runnable->proc = proc;
606 if(arg1)
607 nsISupports_AddRef(arg1);
608 runnable->arg1 = arg1;
610 if(arg2)
611 nsISupports_AddRef(arg2);
612 runnable->arg2 = arg2;
614 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
616 nsIRunnable_Release(&runnable->nsIRunnable_iface);
619 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
621 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
624 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
625 nsIIDRef riid, void **result)
627 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
629 if(IsEqualGUID(&IID_nsISupports, riid)) {
630 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
631 *result = &This->nsIDocumentObserver_iface;
632 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
633 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
634 *result = &This->nsIDocumentObserver_iface;
635 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
636 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
637 *result = &This->nsIDocumentObserver_iface;
638 }else {
639 *result = NULL;
640 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
641 return NS_NOINTERFACE;
644 htmldoc_addref(&This->basedoc);
645 return NS_OK;
648 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
650 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
651 return htmldoc_addref(&This->basedoc);
654 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
656 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
657 return htmldoc_release(&This->basedoc);
660 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
661 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
665 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
666 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
670 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
671 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
675 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
676 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
680 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
681 nsIContent *aContent, cpp_bool aIsRemove)
685 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
686 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
690 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
691 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
695 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
696 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
700 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
701 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
702 nsIContent *aProviousSibling)
706 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
710 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
714 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
715 nsUpdateType aUpdateType)
719 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
720 nsUpdateType aUpdateType)
724 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
728 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
730 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
732 TRACE("(%p)\n", This);
734 if(This->skip_mutation_notif)
735 return;
737 This->content_ready = TRUE;
738 add_script_runner(This, run_end_load, NULL, NULL);
741 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
742 nsIContent *aContent, EventStates aStateMask)
746 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
747 EventStates aStateMask)
751 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
752 cpp_bool aDocumentSheet)
756 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
757 cpp_bool aDocumentSheet)
761 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
762 mozilla_StyleSheetHandle aStyleSheet)
766 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
770 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
774 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
778 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
779 nsIContent *aContent)
781 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
782 nsIDOMHTMLIFrameElement *nsiframe;
783 nsIDOMHTMLFrameElement *nsframe;
784 nsIDOMHTMLScriptElement *nsscript;
785 nsIDOMHTMLMetaElement *nsmeta;
786 nsIDOMElement *nselem;
787 nsIDOMComment *nscomment;
788 nsresult nsres;
790 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
792 if(This->document_mode < COMPAT_MODE_IE10) {
793 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
794 if(NS_SUCCEEDED(nsres)) {
795 TRACE("comment node\n");
797 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
798 nsIDOMComment_Release(nscomment);
799 return;
803 if(This->document_mode == COMPAT_MODE_QUIRKS) {
804 nsIDOMDocumentType *nsdoctype;
805 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMDocumentType, (void**)&nsdoctype);
806 if(NS_SUCCEEDED(nsres)) {
807 compat_mode_t mode = COMPAT_MODE_IE7;
809 TRACE("doctype node\n");
811 if(This->window && This->window->base.outer_window) {
812 HTMLOuterWindow *window = This->window->base.outer_window;
813 DWORD zone;
814 HRESULT hres;
817 * Internet URL zone is treated differently. Native defaults to latest supported
818 * mode. We default to IE8. Ideally, we'd sync that with version used for IE=edge
819 * X-UA-Compatible version, allow configuration and default to higher version
820 * (once it's well supported).
822 hres = IInternetSecurityManager_MapUrlToZone(window->secmgr, window->url, &zone, 0);
823 if(SUCCEEDED(hres) && zone == URLZONE_INTERNET)
824 mode = COMPAT_MODE_IE8;
827 set_document_mode(This, mode, FALSE);
828 nsIDOMDocumentType_Release(nsdoctype);
832 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMElement, (void**)&nselem);
833 if(NS_FAILED(nsres))
834 return;
836 check_event_attr(This, nselem);
837 nsIDOMElement_Release(nselem);
839 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
840 if(NS_SUCCEEDED(nsres)) {
841 TRACE("iframe node\n");
843 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
844 nsIDOMHTMLIFrameElement_Release(nsiframe);
845 return;
848 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
849 if(NS_SUCCEEDED(nsres)) {
850 TRACE("frame node\n");
852 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
853 nsIDOMHTMLFrameElement_Release(nsframe);
854 return;
857 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
858 if(NS_SUCCEEDED(nsres)) {
859 TRACE("script element\n");
861 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsscript, NULL);
862 nsIDOMHTMLScriptElement_Release(nsscript);
863 return;
866 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
867 if(NS_SUCCEEDED(nsres)) {
868 process_meta_element(This, nsmeta);
869 nsIDOMHTMLMetaElement_Release(nsmeta);
873 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
874 nsIParser *aParser, cpp_bool *aBlock)
876 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
877 nsIDOMHTMLScriptElement *nsscript;
878 nsresult nsres;
880 TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
882 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
883 if(NS_SUCCEEDED(nsres)) {
884 TRACE("script node\n");
886 lock_document_mode(This);
887 add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
888 nsIDOMHTMLScriptElement_Release(nsscript);
892 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
893 nsDocumentObserver_QueryInterface,
894 nsDocumentObserver_AddRef,
895 nsDocumentObserver_Release,
896 nsDocumentObserver_CharacterDataWillChange,
897 nsDocumentObserver_CharacterDataChanged,
898 nsDocumentObserver_AttributeWillChange,
899 nsDocumentObserver_AttributeChanged,
900 nsDocumentObserver_NativeAnonymousChildListChange,
901 nsDocumentObserver_AttributeSetToCurrentValue,
902 nsDocumentObserver_ContentAppended,
903 nsDocumentObserver_ContentInserted,
904 nsDocumentObserver_ContentRemoved,
905 nsDocumentObserver_NodeWillBeDestroyed,
906 nsDocumentObserver_ParentChainChanged,
907 nsDocumentObserver_BeginUpdate,
908 nsDocumentObserver_EndUpdate,
909 nsDocumentObserver_BeginLoad,
910 nsDocumentObserver_EndLoad,
911 nsDocumentObserver_ContentStatesChanged,
912 nsDocumentObserver_DocumentStatesChanged,
913 nsDocumentObserver_StyleSheetAdded,
914 nsDocumentObserver_StyleSheetRemoved,
915 nsDocumentObserver_StyleSheetApplicableStateChanged,
916 nsDocumentObserver_StyleRuleChanged,
917 nsDocumentObserver_StyleRuleAdded,
918 nsDocumentObserver_StyleRuleRemoved,
919 nsDocumentObserver_BindToDocument,
920 nsDocumentObserver_AttemptToExecuteScript
923 void init_document_mutation(HTMLDocumentNode *doc)
925 nsIDocument *nsdoc;
926 nsresult nsres;
928 doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
930 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
931 if(NS_FAILED(nsres)) {
932 ERR("Could not get nsIDocument: %08x\n", nsres);
933 return;
936 nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
937 nsIDocument_Release(nsdoc);
940 void release_document_mutation(HTMLDocumentNode *doc)
942 nsIDocument *nsdoc;
943 nsresult nsres;
945 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
946 if(NS_FAILED(nsres)) {
947 ERR("Could not get nsIDocument: %08x\n", nsres);
948 return;
951 nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
952 nsIDocument_Release(nsdoc);
955 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
957 nsIDocument *doc;
958 JSContext *ctx;
959 nsresult nsres;
961 nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
962 assert(nsres == NS_OK);
964 ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
965 nsIDocument_Release(doc);
967 TRACE("ret %p\n", ctx);
968 return ctx;
971 void init_mutation(nsIComponentManager *component_manager)
973 nsIFactory *factory;
974 nsresult nsres;
976 if(!component_manager) {
977 if(content_utils) {
978 nsIContentUtils_Release(content_utils);
979 content_utils = NULL;
981 return;
984 nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
985 &IID_nsIFactory, (void**)&factory);
986 if(NS_FAILED(nsres)) {
987 ERR("Could not create nsIContentUtils service: %08x\n", nsres);
988 return;
991 nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
992 nsIFactory_Release(factory);
993 if(NS_FAILED(nsres))
994 ERR("Could not create nsIContentUtils instance: %08x\n", nsres);