dwrite: Partially implement GetGlyphImageFormats().
[wine.git] / dlls / mshtml / mutation.c
blob8c4fc67535078b624bac53948c1b12dcc29cb0a8
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
22 #include <assert.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shlguid.h"
33 #include "mshtml_private.h"
34 #include "htmlscript.h"
35 #include "htmlevent.h"
36 #include "binding.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
42 #define IE_MAJOR_VERSION 7
43 #define IE_MINOR_VERSION 0
45 static const IID NS_ICONTENTUTILS_CID =
46 {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
48 static nsIContentUtils *content_utils;
50 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
52 int majorv = 0, minorv = 0;
53 const PRUnichar *ptr, *end;
54 PRUnichar *buf;
55 DWORD len;
57 enum {
58 CMP_EQ,
59 CMP_LT,
60 CMP_LTE,
61 CMP_GT,
62 CMP_GTE
63 } cmpt = CMP_EQ;
65 static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
67 if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
68 return NULL;
70 ptr = comment+3;
71 while(isspaceW(*ptr))
72 ptr++;
74 if(ptr[0] == 'l' && ptr[1] == 't') {
75 ptr += 2;
76 if(*ptr == 'e') {
77 cmpt = CMP_LTE;
78 ptr++;
79 }else {
80 cmpt = CMP_LT;
82 }else if(ptr[0] == 'g' && ptr[1] == 't') {
83 ptr += 2;
84 if(*ptr == 'e') {
85 cmpt = CMP_GTE;
86 ptr++;
87 }else {
88 cmpt = CMP_GT;
92 if(!isspaceW(*ptr++))
93 return NULL;
94 while(isspaceW(*ptr))
95 ptr++;
97 if(ptr[0] != 'I' || ptr[1] != 'E')
98 return NULL;
100 ptr +=2;
101 if(!isspaceW(*ptr++))
102 return NULL;
103 while(isspaceW(*ptr))
104 ptr++;
106 if(!isdigitW(*ptr))
107 return NULL;
108 while(isdigitW(*ptr))
109 majorv = majorv*10 + (*ptr++ - '0');
111 if(*ptr == '.') {
112 ptr++;
113 if(!isdigitW(*ptr))
114 return NULL;
115 while(isdigitW(*ptr))
116 minorv = minorv*10 + (*ptr++ - '0');
119 while(isspaceW(*ptr))
120 ptr++;
121 if(ptr[0] != ']' || ptr[1] != '>')
122 return NULL;
123 ptr += 2;
125 len = strlenW(ptr);
126 if(len < sizeof(endifW)/sizeof(WCHAR))
127 return NULL;
129 end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
130 if(memcmp(end, endifW, sizeof(endifW)))
131 return NULL;
133 switch(cmpt) {
134 case CMP_EQ:
135 if(majorv == IE_MAJOR_VERSION && minorv == IE_MINOR_VERSION)
136 break;
137 return NULL;
138 case CMP_LT:
139 if(majorv > IE_MAJOR_VERSION)
140 break;
141 if(majorv == IE_MAJOR_VERSION && minorv > IE_MINOR_VERSION)
142 break;
143 return NULL;
144 case CMP_LTE:
145 if(majorv > IE_MAJOR_VERSION)
146 break;
147 if(majorv == IE_MAJOR_VERSION && minorv >= IE_MINOR_VERSION)
148 break;
149 return NULL;
150 case CMP_GT:
151 if(majorv < IE_MAJOR_VERSION)
152 break;
153 if(majorv == IE_MAJOR_VERSION && minorv < IE_MINOR_VERSION)
154 break;
155 return NULL;
156 case CMP_GTE:
157 if(majorv < IE_MAJOR_VERSION)
158 break;
159 if(majorv == IE_MAJOR_VERSION && minorv <= IE_MINOR_VERSION)
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(doc, 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->usermode == EDITMODE)
264 init_editor(&doc->basedoc);
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->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(doc, 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;
364 static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode)
366 TRACE("%p: %d\n", doc, document_mode);
367 doc->document_mode = document_mode;
370 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
372 int v = 0;
374 if(p[0] != 'I' || p[1] != 'E' || p[2] != '=')
375 return FALSE;
377 p += 3;
378 while('0' <= *p && *p <= '9')
379 v = v*10 + *(p++)-'0';
380 if(*p || !v)
381 return FALSE;
383 switch(v){
384 case 7:
385 *r = COMPAT_MODE_IE7;
386 break;
387 case 8:
388 *r = COMPAT_MODE_IE8;
389 break;
390 case 9:
391 *r = COMPAT_MODE_IE9;
392 break;
393 case 10:
394 *r = COMPAT_MODE_IE10;
395 break;
396 default:
397 *r = v < 7 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
400 return TRUE;
403 static void process_meta_element(HTMLDocumentNode *doc, nsIDOMHTMLMetaElement *meta_element)
405 nsAString http_equiv_str, content_str;
406 nsresult nsres;
408 static const WCHAR x_ua_compatibleW[] = {'x','-','u','a','-','c','o','m','p','a','t','i','b','l','e',0};
410 nsAString_Init(&http_equiv_str, NULL);
411 nsAString_Init(&content_str, NULL);
412 nsres = nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element, &http_equiv_str);
413 if(NS_SUCCEEDED(nsres))
414 nsres = nsIDOMHTMLMetaElement_GetContent(meta_element, &content_str);
416 if(NS_SUCCEEDED(nsres)) {
417 const PRUnichar *http_equiv, *content;
419 nsAString_GetData(&http_equiv_str, &http_equiv);
420 nsAString_GetData(&content_str, &content);
422 TRACE("%s: %s\n", debugstr_w(http_equiv), debugstr_w(content));
424 if(!strcmpiW(http_equiv, x_ua_compatibleW)) {
425 compat_mode_t document_mode;
426 if(parse_ua_compatible(content, &document_mode))
427 set_document_mode(doc, document_mode);
428 else
429 FIXME("Unsupported document mode %s\n", debugstr_w(content));
433 nsAString_Finish(&http_equiv_str);
434 nsAString_Finish(&content_str);
437 typedef struct nsRunnable nsRunnable;
439 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
441 struct nsRunnable {
442 nsIRunnable nsIRunnable_iface;
444 LONG ref;
446 runnable_proc_t proc;
448 HTMLDocumentNode *doc;
449 nsISupports *arg1;
450 nsISupports *arg2;
453 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
455 return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
458 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
459 nsIIDRef riid, void **result)
461 nsRunnable *This = impl_from_nsIRunnable(iface);
463 if(IsEqualGUID(riid, &IID_nsISupports)) {
464 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
465 *result = &This->nsIRunnable_iface;
466 }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
467 TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
468 *result = &This->nsIRunnable_iface;
469 }else {
470 *result = NULL;
471 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
472 return NS_NOINTERFACE;
475 nsISupports_AddRef((nsISupports*)*result);
476 return NS_OK;
479 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
481 nsRunnable *This = impl_from_nsIRunnable(iface);
482 LONG ref = InterlockedIncrement(&This->ref);
484 TRACE("(%p) ref=%d\n", This, ref);
486 return ref;
489 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
491 nsRunnable *This = impl_from_nsIRunnable(iface);
492 LONG ref = InterlockedDecrement(&This->ref);
494 TRACE("(%p) ref=%d\n", This, ref);
496 if(!ref) {
497 htmldoc_release(&This->doc->basedoc);
498 if(This->arg1)
499 nsISupports_Release(This->arg1);
500 if(This->arg2)
501 nsISupports_Release(This->arg2);
502 heap_free(This);
505 return ref;
508 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
510 nsRunnable *This = impl_from_nsIRunnable(iface);
512 return This->proc(This->doc, This->arg1, This->arg2);
515 static const nsIRunnableVtbl nsRunnableVtbl = {
516 nsRunnable_QueryInterface,
517 nsRunnable_AddRef,
518 nsRunnable_Release,
519 nsRunnable_Run
522 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
524 nsRunnable *runnable;
526 runnable = heap_alloc_zero(sizeof(*runnable));
527 if(!runnable)
528 return;
530 runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
531 runnable->ref = 1;
533 htmldoc_addref(&This->basedoc);
534 runnable->doc = This;
535 runnable->proc = proc;
537 if(arg1)
538 nsISupports_AddRef(arg1);
539 runnable->arg1 = arg1;
541 if(arg2)
542 nsISupports_AddRef(arg2);
543 runnable->arg2 = arg2;
545 nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
547 nsIRunnable_Release(&runnable->nsIRunnable_iface);
550 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
552 return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
555 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
556 nsIIDRef riid, void **result)
558 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
560 if(IsEqualGUID(&IID_nsISupports, riid)) {
561 TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
562 *result = &This->nsIDocumentObserver_iface;
563 }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
564 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
565 *result = &This->nsIDocumentObserver_iface;
566 }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
567 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
568 *result = &This->nsIDocumentObserver_iface;
569 }else {
570 *result = NULL;
571 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
572 return NS_NOINTERFACE;
575 htmldoc_addref(&This->basedoc);
576 return NS_OK;
579 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
581 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
582 return htmldoc_addref(&This->basedoc);
585 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
587 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
588 return htmldoc_release(&This->basedoc);
591 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
592 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
596 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
597 nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
601 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
602 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aNewValue)
606 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
607 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType, const nsAttrValue *aOldValue)
611 static void NSAPI nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
612 nsIContent *aContent, cpp_bool aIsRemove)
616 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
617 void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
621 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
622 nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
626 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
627 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
631 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
632 nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
633 nsIContent *aProviousSibling)
637 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
641 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
645 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
646 nsUpdateType aUpdateType)
650 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
651 nsUpdateType aUpdateType)
655 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
659 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
661 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
663 TRACE("(%p)\n", This);
665 if(This->skip_mutation_notif)
666 return;
668 This->content_ready = TRUE;
669 add_script_runner(This, run_end_load, NULL, NULL);
672 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
673 nsIContent *aContent, EventStates aStateMask)
677 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
678 EventStates aStateMask)
682 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
683 cpp_bool aDocumentSheet)
687 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet,
688 cpp_bool aDocumentSheet)
692 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
693 mozilla_StyleSheetHandle aStyleSheet)
697 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
701 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
705 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, mozilla_StyleSheetHandle aStyleSheet)
709 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
710 nsIContent *aContent)
712 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
713 nsIDOMHTMLIFrameElement *nsiframe;
714 nsIDOMHTMLFrameElement *nsframe;
715 nsIDOMHTMLScriptElement *nsscript;
716 nsIDOMHTMLMetaElement *nsmeta;
717 nsIDOMHTMLElement *nselem;
718 nsIDOMComment *nscomment;
719 nsresult nsres;
721 TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
723 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
724 if(NS_SUCCEEDED(nsres)) {
725 TRACE("comment node\n");
727 add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
728 nsIDOMComment_Release(nscomment);
729 return;
732 if(This->document_mode == COMPAT_MODE_QUIRKS) {
733 nsIDOMDocumentType *nsdoctype;
734 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMDocumentType, (void**)&nsdoctype);
735 if(NS_SUCCEEDED(nsres)) {
736 TRACE("doctype node\n");
737 /* FIXME: We should set it to something higher for internet zone. */
738 set_document_mode(This, COMPAT_MODE_IE7);
739 nsIDOMDocumentType_Release(nsdoctype);
743 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLElement, (void**)&nselem);
744 if(NS_FAILED(nsres))
745 return;
747 check_event_attr(This, nselem);
748 nsIDOMHTMLElement_Release(nselem);
750 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
751 if(NS_SUCCEEDED(nsres)) {
752 TRACE("iframe node\n");
754 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
755 nsIDOMHTMLIFrameElement_Release(nsiframe);
756 return;
759 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
760 if(NS_SUCCEEDED(nsres)) {
761 TRACE("frame node\n");
763 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
764 nsIDOMHTMLFrameElement_Release(nsframe);
765 return;
768 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
769 if(NS_SUCCEEDED(nsres)) {
770 TRACE("script element\n");
772 add_script_runner(This, run_bind_to_tree, (nsISupports*)nsscript, NULL);
773 nsIDOMHTMLScriptElement_Release(nsscript);
774 return;
777 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLMetaElement, (void**)&nsmeta);
778 if(NS_SUCCEEDED(nsres)) {
779 process_meta_element(This, nsmeta);
780 nsIDOMHTMLMetaElement_Release(nsmeta);
784 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
785 nsIParser *aParser, cpp_bool *aBlock)
787 HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
788 nsIDOMHTMLScriptElement *nsscript;
789 nsresult nsres;
791 TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
793 nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
794 if(NS_SUCCEEDED(nsres)) {
795 TRACE("script node\n");
797 add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
798 nsIDOMHTMLScriptElement_Release(nsscript);
802 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
803 nsDocumentObserver_QueryInterface,
804 nsDocumentObserver_AddRef,
805 nsDocumentObserver_Release,
806 nsDocumentObserver_CharacterDataWillChange,
807 nsDocumentObserver_CharacterDataChanged,
808 nsDocumentObserver_AttributeWillChange,
809 nsDocumentObserver_AttributeChanged,
810 nsDocumentObserver_NativeAnonymousChildListChange,
811 nsDocumentObserver_AttributeSetToCurrentValue,
812 nsDocumentObserver_ContentAppended,
813 nsDocumentObserver_ContentInserted,
814 nsDocumentObserver_ContentRemoved,
815 nsDocumentObserver_NodeWillBeDestroyed,
816 nsDocumentObserver_ParentChainChanged,
817 nsDocumentObserver_BeginUpdate,
818 nsDocumentObserver_EndUpdate,
819 nsDocumentObserver_BeginLoad,
820 nsDocumentObserver_EndLoad,
821 nsDocumentObserver_ContentStatesChanged,
822 nsDocumentObserver_DocumentStatesChanged,
823 nsDocumentObserver_StyleSheetAdded,
824 nsDocumentObserver_StyleSheetRemoved,
825 nsDocumentObserver_StyleSheetApplicableStateChanged,
826 nsDocumentObserver_StyleRuleChanged,
827 nsDocumentObserver_StyleRuleAdded,
828 nsDocumentObserver_StyleRuleRemoved,
829 nsDocumentObserver_BindToDocument,
830 nsDocumentObserver_AttemptToExecuteScript
833 void init_document_mutation(HTMLDocumentNode *doc)
835 nsIDocument *nsdoc;
836 nsresult nsres;
838 doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
840 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
841 if(NS_FAILED(nsres)) {
842 ERR("Could not get nsIDocument: %08x\n", nsres);
843 return;
846 nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
847 nsIDocument_Release(nsdoc);
850 void release_document_mutation(HTMLDocumentNode *doc)
852 nsIDocument *nsdoc;
853 nsresult nsres;
855 nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
856 if(NS_FAILED(nsres)) {
857 ERR("Could not get nsIDocument: %08x\n", nsres);
858 return;
861 nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
862 nsIDocument_Release(nsdoc);
865 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
867 nsIDocument *doc;
868 JSContext *ctx;
869 nsresult nsres;
871 nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
872 assert(nsres == NS_OK);
874 ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
875 nsIDocument_Release(doc);
877 TRACE("ret %p\n", ctx);
878 return ctx;
881 void init_mutation(nsIComponentManager *component_manager)
883 nsIFactory *factory;
884 nsresult nsres;
886 if(!component_manager) {
887 if(content_utils) {
888 nsIContentUtils_Release(content_utils);
889 content_utils = NULL;
891 return;
894 nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
895 &IID_nsIFactory, (void**)&factory);
896 if(NS_FAILED(nsres)) {
897 ERR("Could not create nsIContentUtils service: %08x\n", nsres);
898 return;
901 nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
902 nsIFactory_Release(factory);
903 if(NS_FAILED(nsres))
904 ERR("Could not create nsIContentUtils instance: %08x\n", nsres);