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
32 #include "mshtml_private.h"
33 #include "htmlscript.h"
34 #include "htmlevent.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 BOOL
is_iexplore(void)
58 static volatile char cache
= -1;
61 const WCHAR
*p
, *name
= NtCurrentTeb()->Peb
->ProcessParameters
->ImagePathName
.Buffer
;
62 if((p
= wcsrchr(name
, '/'))) name
= p
+ 1;
63 if((p
= wcsrchr(name
, '\\'))) name
= p
+ 1;
64 ret
= !wcsicmp(name
, L
"iexplore.exe");
70 static PRUnichar
*handle_insert_comment(HTMLDocumentNode
*doc
, const PRUnichar
*comment
)
72 unsigned majorv
= 0, minorv
= 0, compat_version
;
73 const PRUnichar
*ptr
, *end
;
85 static const PRUnichar endifW
[] = {'<','!','[','e','n','d','i','f',']'};
87 if(comment
[0] != '[' || comment
[1] != 'i' || comment
[2] != 'f')
94 if(ptr
[0] == 'l' && ptr
[1] == 't') {
102 }else if(ptr
[0] == 'g' && ptr
[1] == 't') {
112 if(!iswspace(*ptr
++))
114 while(iswspace(*ptr
))
117 if(ptr
[0] != 'I' || ptr
[1] != 'E')
121 if(!iswspace(*ptr
++))
123 while(iswspace(*ptr
))
128 while(is_digit(*ptr
))
129 majorv
= majorv
*10 + (*ptr
++ - '0');
135 while(is_digit(*ptr
))
136 minorv
= minorv
*10 + (*ptr
++ - '0');
139 while(iswspace(*ptr
))
141 if(ptr
[0] != ']' || ptr
[1] != '>')
146 if(len
< ARRAY_SIZE(endifW
))
149 end
= ptr
+ len
- ARRAY_SIZE(endifW
);
150 if(memcmp(end
, endifW
, sizeof(endifW
)))
153 compat_version
= compat_mode_info
[doc
->document_mode
].ie_version
;
157 if(compat_version
== majorv
&& !minorv
)
161 if(compat_version
< majorv
|| (compat_version
== majorv
&& minorv
))
165 if(compat_version
<= majorv
)
169 if(compat_version
> majorv
)
173 if(compat_version
>= majorv
|| (compat_version
== majorv
&& !minorv
))
178 buf
= heap_alloc((end
-ptr
+1)*sizeof(WCHAR
));
182 memcpy(buf
, ptr
, (end
-ptr
)*sizeof(WCHAR
));
188 static nsresult
run_insert_comment(HTMLDocumentNode
*doc
, nsISupports
*comment_iface
, nsISupports
*arg2
)
190 const PRUnichar
*comment
;
191 nsIDOMComment
*nscomment
;
192 PRUnichar
*replace_html
;
193 nsAString comment_str
;
196 nsres
= nsISupports_QueryInterface(comment_iface
, &IID_nsIDOMComment
, (void**)&nscomment
);
197 if(NS_FAILED(nsres
)) {
198 ERR("Could not get nsIDOMComment iface:%08lx\n", nsres
);
202 nsAString_Init(&comment_str
, NULL
);
203 nsres
= nsIDOMComment_GetData(nscomment
, &comment_str
);
207 nsAString_GetData(&comment_str
, &comment
);
208 replace_html
= handle_insert_comment(doc
, comment
);
209 nsAString_Finish(&comment_str
);
214 hres
= replace_node_by_html(doc
->nsdoc
, (nsIDOMNode
*)nscomment
, replace_html
);
215 heap_free(replace_html
);
217 nsres
= NS_ERROR_FAILURE
;
221 nsIDOMComment_Release(nscomment
);
225 static nsresult
run_bind_to_tree(HTMLDocumentNode
*doc
, nsISupports
*nsiface
, nsISupports
*arg2
)
232 TRACE("(%p)->(%p)\n", doc
, nsiface
);
234 nsres
= nsISupports_QueryInterface(nsiface
, &IID_nsIDOMNode
, (void**)&nsnode
);
238 hres
= get_node(nsnode
, TRUE
, &node
);
239 nsIDOMNode_Release(nsnode
);
241 ERR("Could not get node\n");
245 if(node
->vtbl
->bind_to_tree
)
246 node
->vtbl
->bind_to_tree(node
);
252 /* Calls undocumented 69 cmd of CGID_Explorer */
253 static void call_explorer_69(HTMLDocumentObj
*doc
)
255 IOleCommandTarget
*olecmd
;
262 hres
= IOleClientSite_QueryInterface(doc
->client
, &IID_IOleCommandTarget
, (void**)&olecmd
);
267 hres
= IOleCommandTarget_Exec(olecmd
, &CGID_Explorer
, 69, 0, NULL
, &var
);
268 IOleCommandTarget_Release(olecmd
);
269 if(SUCCEEDED(hres
) && V_VT(&var
) != VT_NULL
)
270 FIXME("handle result\n");
273 static void parse_complete(HTMLDocumentObj
*doc
)
275 TRACE("(%p)\n", doc
);
277 if(doc
->nscontainer
->usermode
== EDITMODE
)
278 init_editor(doc
->basedoc
.doc_node
);
280 call_explorer_69(doc
);
282 IAdviseSink_OnViewChange(doc
->view_sink
, DVASPECT_CONTENT
, -1);
283 call_property_onchanged(&doc
->cp_container
, 1005);
284 call_explorer_69(doc
);
286 if(doc
->webbrowser
&& doc
->nscontainer
->usermode
!= EDITMODE
&& !(doc
->basedoc
.window
->load_flags
& BINDING_REFRESH
))
287 IDocObjectService_FireNavigateComplete2(doc
->doc_object_service
, &doc
->basedoc
.window
->base
.IHTMLWindow2_iface
, 0);
289 /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
292 static nsresult
run_end_load(HTMLDocumentNode
*This
, nsISupports
*arg1
, nsISupports
*arg2
)
294 TRACE("(%p)\n", This
);
296 if(!This
->basedoc
.doc_obj
)
299 if(This
== This
->basedoc
.doc_obj
->basedoc
.doc_node
) {
301 * This should be done in the worker thread that parses HTML,
302 * but we don't have such thread (Gecko parses HTML for us).
304 parse_complete(This
->basedoc
.doc_obj
);
307 bind_event_scripts(This
);
308 set_ready_state(This
->basedoc
.window
, READYSTATE_INTERACTIVE
);
312 static nsresult
run_insert_script(HTMLDocumentNode
*doc
, nsISupports
*script_iface
, nsISupports
*parser_iface
)
314 nsIDOMHTMLScriptElement
*nsscript
;
315 HTMLScriptElement
*script_elem
;
316 nsIParser
*nsparser
= NULL
;
317 script_queue_entry_t
*iter
;
318 HTMLInnerWindow
*window
;
322 TRACE("(%p)->(%p)\n", doc
, script_iface
);
324 window
= doc
->window
;
328 nsres
= nsISupports_QueryInterface(script_iface
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
329 if(NS_FAILED(nsres
)) {
330 ERR("Could not get nsIDOMHTMLScriptElement: %08lx\n", nsres
);
335 nsres
= nsISupports_QueryInterface(parser_iface
, &IID_nsIParser
, (void**)&nsparser
);
336 if(NS_FAILED(nsres
)) {
337 ERR("Could not get nsIParser iface: %08lx\n", nsres
);
342 hres
= script_elem_from_nsscript(nsscript
, &script_elem
);
343 nsIDOMHTMLScriptElement_Release(nsscript
);
345 return NS_ERROR_FAILURE
;
348 nsIParser_BeginEvaluatingParserInsertedScript(nsparser
);
349 window
->parser_callback_cnt
++;
352 IHTMLWindow2_AddRef(&window
->base
.IHTMLWindow2_iface
);
354 doc_insert_script(window
, script_elem
, TRUE
);
356 while(!list_empty(&window
->script_queue
)) {
357 iter
= LIST_ENTRY(list_head(&window
->script_queue
), script_queue_entry_t
, entry
);
358 list_remove(&iter
->entry
);
359 if(!iter
->script
->parsed
)
360 doc_insert_script(window
, iter
->script
, TRUE
);
361 IHTMLScriptElement_Release(&iter
->script
->IHTMLScriptElement_iface
);
365 IHTMLWindow2_Release(&window
->base
.IHTMLWindow2_iface
);
368 window
->parser_callback_cnt
--;
369 nsIParser_EndEvaluatingParserInsertedScript(nsparser
);
370 nsIParser_Release(nsparser
);
373 IHTMLScriptElement_Release(&script_elem
->IHTMLScriptElement_iface
);
379 * We may change document mode only in early stage of document lifetime.
380 * Later attempts will not have an effect.
382 compat_mode_t
lock_document_mode(HTMLDocumentNode
*doc
)
384 TRACE("%p: %d\n", doc
, doc
->document_mode
);
386 doc
->document_mode_locked
= TRUE
;
387 return doc
->document_mode
;
390 static void set_document_mode(HTMLDocumentNode
*doc
, compat_mode_t document_mode
, BOOL lock
)
392 compat_mode_t max_compat_mode
;
394 if(doc
->document_mode_locked
) {
395 WARN("attempting to set document mode %d on locked document %p\n", document_mode
, doc
);
399 TRACE("%p: %d\n", doc
, document_mode
);
401 max_compat_mode
= doc
->window
&& doc
->window
->base
.outer_window
402 ? get_max_compat_mode(doc
->window
->base
.outer_window
->uri
)
404 if(max_compat_mode
< document_mode
) {
405 WARN("Tried to set compat mode %u higher than maximal configured %u\n",
406 document_mode
, max_compat_mode
);
407 document_mode
= max_compat_mode
;
410 doc
->document_mode
= document_mode
;
412 lock_document_mode(doc
);
415 static BOOL
is_ua_compatible_delimiter(WCHAR c
)
417 return !c
|| c
== ';' || c
== ',' || iswspace(c
);
420 const WCHAR
*parse_compat_version(const WCHAR
*version_string
, compat_mode_t
*r
)
425 for(p
= version_string
; '0' <= *p
&& *p
<= '9'; p
++)
426 version
= version
* 10 + *p
-'0';
427 if(!is_ua_compatible_delimiter(*p
) || p
== version_string
)
433 *r
= COMPAT_MODE_IE5
;
436 *r
= COMPAT_MODE_IE7
;
439 *r
= COMPAT_MODE_IE8
;
442 *r
= COMPAT_MODE_IE9
;
445 *r
= COMPAT_MODE_IE10
;
448 *r
= version
< 5 ? COMPAT_MODE_QUIRKS
: COMPAT_MODE_IE11
;
453 static BOOL
parse_ua_compatible(const WCHAR
*p
, compat_mode_t
*r
)
455 static const WCHAR ie_eqW
[] = {'I','E','='};
456 static const WCHAR edgeW
[] = {'e','d','g','e'};
457 compat_mode_t mode
= COMPAT_MODE_INVALID
;
459 TRACE("%s\n", debugstr_w(p
));
461 if(wcsnicmp(ie_eqW
, p
, ARRAY_SIZE(ie_eqW
)))
466 while(iswspace(*p
)) p
++;
467 if(!wcsnicmp(p
, edgeW
, ARRAY_SIZE(edgeW
))) {
468 p
+= ARRAY_SIZE(edgeW
);
469 if(is_ua_compatible_delimiter(*p
))
470 mode
= COMPAT_MODE_IE11
;
472 }else if(!(p
= parse_compat_version(p
, r
)))
476 while(iswspace(*p
)) p
++;
477 } while(*p
++ == ',');
480 return mode
!= COMPAT_MODE_INVALID
;
483 void process_document_response_headers(HTMLDocumentNode
*doc
, IBinding
*binding
)
485 IWinInetHttpInfo
*http_info
;
490 hres
= IBinding_QueryInterface(binding
, &IID_IWinInetHttpInfo
, (void**)&http_info
);
492 TRACE("No IWinInetHttpInfo\n");
497 strcpy(buf
, "X-UA-Compatible");
498 hres
= IWinInetHttpInfo_QueryInfo(http_info
, HTTP_QUERY_CUSTOM
, buf
, &size
, NULL
, NULL
);
499 if(hres
== S_OK
&& size
) {
500 compat_mode_t document_mode
;
503 TRACE("size %lu\n", size
);
505 header
= heap_strdupAtoW(buf
);
506 if(header
&& parse_ua_compatible(header
, &document_mode
)) {
507 TRACE("setting document mode %d\n", document_mode
);
508 set_document_mode(doc
, document_mode
, FALSE
);
513 IWinInetHttpInfo_Release(http_info
);
516 static void process_meta_element(HTMLDocumentNode
*doc
, nsIDOMHTMLMetaElement
*meta_element
)
518 nsAString http_equiv_str
, content_str
;
521 nsAString_Init(&http_equiv_str
, NULL
);
522 nsAString_Init(&content_str
, NULL
);
523 nsres
= nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element
, &http_equiv_str
);
524 if(NS_SUCCEEDED(nsres
))
525 nsres
= nsIDOMHTMLMetaElement_GetContent(meta_element
, &content_str
);
527 if(NS_SUCCEEDED(nsres
)) {
528 const PRUnichar
*http_equiv
, *content
;
530 nsAString_GetData(&http_equiv_str
, &http_equiv
);
531 nsAString_GetData(&content_str
, &content
);
533 TRACE("%s: %s\n", debugstr_w(http_equiv
), debugstr_w(content
));
535 if(!wcsicmp(http_equiv
, L
"x-ua-compatible")) {
536 compat_mode_t document_mode
;
537 if(parse_ua_compatible(content
, &document_mode
))
538 set_document_mode(doc
, document_mode
, TRUE
);
540 FIXME("Unsupported document mode %s\n", debugstr_w(content
));
544 nsAString_Finish(&http_equiv_str
);
545 nsAString_Finish(&content_str
);
548 typedef struct nsRunnable nsRunnable
;
550 typedef nsresult (*runnable_proc_t
)(HTMLDocumentNode
*,nsISupports
*,nsISupports
*);
553 nsIRunnable nsIRunnable_iface
;
557 runnable_proc_t proc
;
559 HTMLDocumentNode
*doc
;
564 static inline nsRunnable
*impl_from_nsIRunnable(nsIRunnable
*iface
)
566 return CONTAINING_RECORD(iface
, nsRunnable
, nsIRunnable_iface
);
569 static nsresult NSAPI
nsRunnable_QueryInterface(nsIRunnable
*iface
,
570 nsIIDRef riid
, void **result
)
572 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
574 if(IsEqualGUID(riid
, &IID_nsISupports
)) {
575 TRACE("(%p)->(IID_nsISupports %p)\n", This
, result
);
576 *result
= &This
->nsIRunnable_iface
;
577 }else if(IsEqualGUID(riid
, &IID_nsIRunnable
)) {
578 TRACE("(%p)->(IID_nsIRunnable %p)\n", This
, result
);
579 *result
= &This
->nsIRunnable_iface
;
582 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), result
);
583 return NS_NOINTERFACE
;
586 nsISupports_AddRef((nsISupports
*)*result
);
590 static nsrefcnt NSAPI
nsRunnable_AddRef(nsIRunnable
*iface
)
592 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
593 LONG ref
= InterlockedIncrement(&This
->ref
);
595 TRACE("(%p) ref=%ld\n", This
, ref
);
600 static nsrefcnt NSAPI
nsRunnable_Release(nsIRunnable
*iface
)
602 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
603 LONG ref
= InterlockedDecrement(&This
->ref
);
605 TRACE("(%p) ref=%ld\n", This
, ref
);
608 htmldoc_release(&This
->doc
->basedoc
);
610 nsISupports_Release(This
->arg1
);
612 nsISupports_Release(This
->arg2
);
619 static nsresult NSAPI
nsRunnable_Run(nsIRunnable
*iface
)
621 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
623 return This
->proc(This
->doc
, This
->arg1
, This
->arg2
);
626 static const nsIRunnableVtbl nsRunnableVtbl
= {
627 nsRunnable_QueryInterface
,
633 static void add_script_runner(HTMLDocumentNode
*This
, runnable_proc_t proc
, nsISupports
*arg1
, nsISupports
*arg2
)
635 nsRunnable
*runnable
;
637 runnable
= heap_alloc_zero(sizeof(*runnable
));
641 runnable
->nsIRunnable_iface
.lpVtbl
= &nsRunnableVtbl
;
644 htmldoc_addref(&This
->basedoc
);
645 runnable
->doc
= This
;
646 runnable
->proc
= proc
;
649 nsISupports_AddRef(arg1
);
650 runnable
->arg1
= arg1
;
653 nsISupports_AddRef(arg2
);
654 runnable
->arg2
= arg2
;
656 nsIContentUtils_AddScriptRunner(content_utils
, &runnable
->nsIRunnable_iface
);
658 nsIRunnable_Release(&runnable
->nsIRunnable_iface
);
661 static inline HTMLDocumentNode
*impl_from_nsIDocumentObserver(nsIDocumentObserver
*iface
)
663 return CONTAINING_RECORD(iface
, HTMLDocumentNode
, nsIDocumentObserver_iface
);
666 static nsresult NSAPI
nsDocumentObserver_QueryInterface(nsIDocumentObserver
*iface
,
667 nsIIDRef riid
, void **result
)
669 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
671 if(IsEqualGUID(&IID_nsISupports
, riid
)) {
672 TRACE("(%p)->(IID_nsISupports, %p)\n", This
, result
);
673 *result
= &This
->nsIDocumentObserver_iface
;
674 }else if(IsEqualGUID(&IID_nsIMutationObserver
, riid
)) {
675 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This
, result
);
676 *result
= &This
->nsIDocumentObserver_iface
;
677 }else if(IsEqualGUID(&IID_nsIDocumentObserver
, riid
)) {
678 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This
, result
);
679 *result
= &This
->nsIDocumentObserver_iface
;
682 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), result
);
683 return NS_NOINTERFACE
;
686 htmldoc_addref(&This
->basedoc
);
690 static nsrefcnt NSAPI
nsDocumentObserver_AddRef(nsIDocumentObserver
*iface
)
692 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
693 return htmldoc_addref(&This
->basedoc
);
696 static nsrefcnt NSAPI
nsDocumentObserver_Release(nsIDocumentObserver
*iface
)
698 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
699 return htmldoc_release(&This
->basedoc
);
702 static void NSAPI
nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver
*iface
,
703 nsIDocument
*aDocument
, nsIContent
*aContent
, void /*CharacterDataChangeInfo*/ *aInfo
)
707 static void NSAPI
nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver
*iface
,
708 nsIDocument
*aDocument
, nsIContent
*aContent
, void /*CharacterDataChangeInfo*/ *aInfo
)
712 static void NSAPI
nsDocumentObserver_AttributeWillChange(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
713 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
, LONG aModType
, const nsAttrValue
*aNewValue
)
717 static void NSAPI
nsDocumentObserver_AttributeChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
718 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
, LONG aModType
, const nsAttrValue
*aOldValue
)
722 static void NSAPI
nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
723 nsIContent
*aContent
, cpp_bool aIsRemove
)
727 static void NSAPI
nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
728 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
)
732 static void NSAPI
nsDocumentObserver_ContentAppended(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
733 nsIContent
*aContainer
, nsIContent
*aFirstNewContent
, LONG aNewIndexInContainer
)
737 static void NSAPI
nsDocumentObserver_ContentInserted(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
738 nsIContent
*aContainer
, nsIContent
*aChild
, LONG aIndexInContainer
)
742 static void NSAPI
nsDocumentObserver_ContentRemoved(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
743 nsIContent
*aContainer
, nsIContent
*aChild
, LONG aIndexInContainer
,
744 nsIContent
*aProviousSibling
)
748 static void NSAPI
nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver
*iface
, const nsINode
*aNode
)
752 static void NSAPI
nsDocumentObserver_ParentChainChanged(nsIDocumentObserver
*iface
, nsIContent
*aContent
)
756 static void NSAPI
nsDocumentObserver_BeginUpdate(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
757 nsUpdateType aUpdateType
)
761 static void NSAPI
nsDocumentObserver_EndUpdate(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
762 nsUpdateType aUpdateType
)
766 static void NSAPI
nsDocumentObserver_BeginLoad(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
)
770 static void NSAPI
nsDocumentObserver_EndLoad(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
)
772 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
774 TRACE("(%p)\n", This
);
776 if(This
->skip_mutation_notif
)
779 This
->content_ready
= TRUE
;
780 add_script_runner(This
, run_end_load
, NULL
, NULL
);
783 static void NSAPI
nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
784 nsIContent
*aContent
, EventStates aStateMask
)
788 static void NSAPI
nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
789 EventStates aStateMask
)
793 static void NSAPI
nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
,
794 cpp_bool aDocumentSheet
)
798 static void NSAPI
nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
,
799 cpp_bool aDocumentSheet
)
803 static void NSAPI
nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver
*iface
,
804 mozilla_StyleSheetHandle aStyleSheet
)
808 static void NSAPI
nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
812 static void NSAPI
nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
816 static void NSAPI
nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
820 static void NSAPI
nsDocumentObserver_BindToDocument(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
821 nsIContent
*aContent
)
823 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
824 nsIDOMHTMLIFrameElement
*nsiframe
;
825 nsIDOMHTMLFrameElement
*nsframe
;
826 nsIDOMHTMLScriptElement
*nsscript
;
827 nsIDOMHTMLMetaElement
*nsmeta
;
828 nsIDOMElement
*nselem
;
829 nsIDOMComment
*nscomment
;
832 TRACE("(%p)->(%p %p)\n", This
, aDocument
, aContent
);
834 if(This
->document_mode
< COMPAT_MODE_IE10
) {
835 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMComment
, (void**)&nscomment
);
836 if(NS_SUCCEEDED(nsres
)) {
837 TRACE("comment node\n");
839 add_script_runner(This
, run_insert_comment
, (nsISupports
*)nscomment
, NULL
);
840 nsIDOMComment_Release(nscomment
);
845 if(This
->document_mode
== COMPAT_MODE_QUIRKS
) {
846 nsIDOMDocumentType
*nsdoctype
;
848 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMDocumentType
, (void**)&nsdoctype
);
849 if(NS_SUCCEEDED(nsres
)) {
850 compat_mode_t mode
= COMPAT_MODE_IE7
;
852 TRACE("doctype node\n");
854 /* Native mshtml hardcodes special behavior for iexplore.exe here. The feature control registry
855 keys under HKLM or HKCU\Software\Microsoft\Internet Explorer\Main\FeatureControl are not used
856 in this case (neither in Wow6432Node), although FEATURE_BROWSER_EMULATION does override this,
857 but it is not set by default on native, and the behavior is still different. This was tested
858 by removing all iexplore.exe values from any FeatureControl subkeys, and renaming the test
859 executable to iexplore.exe, which changed its default compat mode in such cases. */
860 if(This
->window
&& This
->window
->base
.outer_window
&& is_iexplore()) {
861 HTMLOuterWindow
*window
= This
->window
->base
.outer_window
;
865 /* Internet URL zone is treated differently and defaults to the latest supported mode. */
866 hres
= IInternetSecurityManager_MapUrlToZone(get_security_manager(), window
->url
, &zone
, 0);
867 if(SUCCEEDED(hres
) && zone
== URLZONE_INTERNET
)
868 mode
= COMPAT_MODE_IE11
;
871 set_document_mode(This
, mode
, FALSE
);
872 nsIDOMDocumentType_Release(nsdoctype
);
876 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMElement
, (void**)&nselem
);
880 check_event_attr(This
, nselem
);
881 nsIDOMElement_Release(nselem
);
883 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLIFrameElement
, (void**)&nsiframe
);
884 if(NS_SUCCEEDED(nsres
)) {
885 TRACE("iframe node\n");
887 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsiframe
, NULL
);
888 nsIDOMHTMLIFrameElement_Release(nsiframe
);
892 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLFrameElement
, (void**)&nsframe
);
893 if(NS_SUCCEEDED(nsres
)) {
894 TRACE("frame node\n");
896 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsframe
, NULL
);
897 nsIDOMHTMLFrameElement_Release(nsframe
);
901 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
902 if(NS_SUCCEEDED(nsres
)) {
903 TRACE("script element\n");
905 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsscript
, NULL
);
906 nsIDOMHTMLScriptElement_Release(nsscript
);
910 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLMetaElement
, (void**)&nsmeta
);
911 if(NS_SUCCEEDED(nsres
)) {
912 process_meta_element(This
, nsmeta
);
913 nsIDOMHTMLMetaElement_Release(nsmeta
);
917 static void NSAPI
nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver
*iface
, nsIContent
*aContent
,
918 nsIParser
*aParser
, cpp_bool
*aBlock
)
920 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
921 nsIDOMHTMLScriptElement
*nsscript
;
924 TRACE("(%p)->(%p %p %p)\n", This
, aContent
, aParser
, aBlock
);
926 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
927 if(NS_SUCCEEDED(nsres
)) {
928 TRACE("script node\n");
930 lock_document_mode(This
);
931 add_script_runner(This
, run_insert_script
, (nsISupports
*)nsscript
, (nsISupports
*)aParser
);
932 nsIDOMHTMLScriptElement_Release(nsscript
);
936 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl
= {
937 nsDocumentObserver_QueryInterface
,
938 nsDocumentObserver_AddRef
,
939 nsDocumentObserver_Release
,
940 nsDocumentObserver_CharacterDataWillChange
,
941 nsDocumentObserver_CharacterDataChanged
,
942 nsDocumentObserver_AttributeWillChange
,
943 nsDocumentObserver_AttributeChanged
,
944 nsDocumentObserver_NativeAnonymousChildListChange
,
945 nsDocumentObserver_AttributeSetToCurrentValue
,
946 nsDocumentObserver_ContentAppended
,
947 nsDocumentObserver_ContentInserted
,
948 nsDocumentObserver_ContentRemoved
,
949 nsDocumentObserver_NodeWillBeDestroyed
,
950 nsDocumentObserver_ParentChainChanged
,
951 nsDocumentObserver_BeginUpdate
,
952 nsDocumentObserver_EndUpdate
,
953 nsDocumentObserver_BeginLoad
,
954 nsDocumentObserver_EndLoad
,
955 nsDocumentObserver_ContentStatesChanged
,
956 nsDocumentObserver_DocumentStatesChanged
,
957 nsDocumentObserver_StyleSheetAdded
,
958 nsDocumentObserver_StyleSheetRemoved
,
959 nsDocumentObserver_StyleSheetApplicableStateChanged
,
960 nsDocumentObserver_StyleRuleChanged
,
961 nsDocumentObserver_StyleRuleAdded
,
962 nsDocumentObserver_StyleRuleRemoved
,
963 nsDocumentObserver_BindToDocument
,
964 nsDocumentObserver_AttemptToExecuteScript
967 void init_document_mutation(HTMLDocumentNode
*doc
)
972 doc
->nsIDocumentObserver_iface
.lpVtbl
= &nsDocumentObserverVtbl
;
974 nsres
= nsIDOMHTMLDocument_QueryInterface(doc
->nsdoc
, &IID_nsIDocument
, (void**)&nsdoc
);
975 if(NS_FAILED(nsres
)) {
976 ERR("Could not get nsIDocument: %08lx\n", nsres
);
980 nsIContentUtils_AddDocumentObserver(content_utils
, nsdoc
, &doc
->nsIDocumentObserver_iface
);
981 nsIDocument_Release(nsdoc
);
984 void release_document_mutation(HTMLDocumentNode
*doc
)
989 nsres
= nsIDOMHTMLDocument_QueryInterface(doc
->nsdoc
, &IID_nsIDocument
, (void**)&nsdoc
);
990 if(NS_FAILED(nsres
)) {
991 ERR("Could not get nsIDocument: %08lx\n", nsres
);
995 nsIContentUtils_RemoveDocumentObserver(content_utils
, nsdoc
, &doc
->nsIDocumentObserver_iface
);
996 nsIDocument_Release(nsdoc
);
999 JSContext
*get_context_from_document(nsIDOMHTMLDocument
*nsdoc
)
1005 nsres
= nsIDOMHTMLDocument_QueryInterface(nsdoc
, &IID_nsIDocument
, (void**)&doc
);
1006 assert(nsres
== NS_OK
);
1008 ctx
= nsIContentUtils_GetContextFromDocument(content_utils
, doc
);
1009 nsIDocument_Release(doc
);
1011 TRACE("ret %p\n", ctx
);
1015 void init_mutation(nsIComponentManager
*component_manager
)
1017 nsIFactory
*factory
;
1020 if(!component_manager
) {
1022 nsIContentUtils_Release(content_utils
);
1023 content_utils
= NULL
;
1028 nsres
= nsIComponentManager_GetClassObject(component_manager
, &NS_ICONTENTUTILS_CID
,
1029 &IID_nsIFactory
, (void**)&factory
);
1030 if(NS_FAILED(nsres
)) {
1031 ERR("Could not create nsIContentUtils service: %08lx\n", nsres
);
1035 nsres
= nsIFactory_CreateInstance(factory
, NULL
, &IID_nsIContentUtils
, (void**)&content_utils
);
1036 nsIFactory_Release(factory
);
1037 if(NS_FAILED(nsres
))
1038 ERR("Could not create nsIContentUtils instance: %08lx\n", nsres
);