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
= malloc((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
->dom_document
, (nsIDOMNode
*)nscomment
, 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
->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
->window
->load_flags
& BINDING_REFRESH
))
287 IDocObjectService_FireNavigateComplete2(doc
->doc_object_service
, &doc
->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 HTMLDocumentObj
*doc_obj
= This
->doc_obj
;
295 HTMLInnerWindow
*window
= This
->window
;
297 TRACE("(%p)\n", This
);
301 IHTMLWindow2_AddRef(&window
->base
.IHTMLWindow2_iface
);
303 if(This
== doc_obj
->doc_node
) {
305 * This should be done in the worker thread that parses HTML,
306 * but we don't have such thread (Gecko parses HTML for us).
308 IUnknown_AddRef(doc_obj
->outer_unk
);
309 parse_complete(doc_obj
);
310 IUnknown_Release(doc_obj
->outer_unk
);
313 bind_event_scripts(This
);
315 if(This
->window
== window
) {
316 window
->performance_timing
->dom_interactive_time
= get_time_stamp();
317 set_ready_state(This
->outer_window
, READYSTATE_INTERACTIVE
);
319 IHTMLWindow2_Release(&window
->base
.IHTMLWindow2_iface
);
323 static nsresult
run_insert_script(HTMLDocumentNode
*doc
, nsISupports
*script_iface
, nsISupports
*parser_iface
)
325 nsIDOMHTMLScriptElement
*nsscript
;
326 HTMLScriptElement
*script_elem
;
327 nsIParser
*nsparser
= NULL
;
328 script_queue_entry_t
*iter
;
329 HTMLInnerWindow
*window
;
333 TRACE("(%p)->(%p)\n", doc
, script_iface
);
335 window
= doc
->window
;
339 nsres
= nsISupports_QueryInterface(script_iface
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
340 if(NS_FAILED(nsres
)) {
341 ERR("Could not get nsIDOMHTMLScriptElement: %08lx\n", nsres
);
346 nsres
= nsISupports_QueryInterface(parser_iface
, &IID_nsIParser
, (void**)&nsparser
);
347 if(NS_FAILED(nsres
)) {
348 ERR("Could not get nsIParser iface: %08lx\n", nsres
);
353 hres
= script_elem_from_nsscript(nsscript
, &script_elem
);
354 nsIDOMHTMLScriptElement_Release(nsscript
);
357 nsIParser_Release(nsparser
);
358 return NS_ERROR_FAILURE
;
362 nsIParser_BeginEvaluatingParserInsertedScript(nsparser
);
363 window
->parser_callback_cnt
++;
366 IHTMLWindow2_AddRef(&window
->base
.IHTMLWindow2_iface
);
368 doc_insert_script(window
, script_elem
, TRUE
);
370 while(!list_empty(&window
->script_queue
)) {
371 iter
= LIST_ENTRY(list_head(&window
->script_queue
), script_queue_entry_t
, entry
);
372 list_remove(&iter
->entry
);
373 if(!iter
->script
->parsed
)
374 doc_insert_script(window
, iter
->script
, TRUE
);
375 IHTMLScriptElement_Release(&iter
->script
->IHTMLScriptElement_iface
);
380 window
->parser_callback_cnt
--;
381 nsIParser_EndEvaluatingParserInsertedScript(nsparser
);
382 nsIParser_Release(nsparser
);
385 IHTMLWindow2_Release(&window
->base
.IHTMLWindow2_iface
);
386 IHTMLScriptElement_Release(&script_elem
->IHTMLScriptElement_iface
);
391 DWORD
get_compat_mode_version(compat_mode_t compat_mode
)
393 switch(compat_mode
) {
394 case COMPAT_MODE_QUIRKS
:
395 case COMPAT_MODE_IE5
:
396 case COMPAT_MODE_IE7
:
398 case COMPAT_MODE_IE8
:
400 case COMPAT_MODE_IE9
:
402 case COMPAT_MODE_IE10
:
404 case COMPAT_MODE_IE11
:
412 * We may change document mode only in early stage of document lifetime.
413 * Later attempts will not have an effect.
415 compat_mode_t
lock_document_mode(HTMLDocumentNode
*doc
)
417 TRACE("%p: %d\n", doc
, doc
->document_mode
);
419 if(!doc
->document_mode_locked
) {
420 doc
->document_mode_locked
= TRUE
;
422 if(doc
->html_document
)
423 nsIDOMHTMLDocument_SetIECompatMode(doc
->html_document
, get_compat_mode_version(doc
->document_mode
));
426 return doc
->document_mode
;
429 static void set_document_mode(HTMLDocumentNode
*doc
, compat_mode_t document_mode
, BOOL lock
)
431 compat_mode_t max_compat_mode
;
433 if(doc
->document_mode_locked
) {
434 WARN("attempting to set document mode %d on locked document %p\n", document_mode
, doc
);
438 TRACE("%p: %d\n", doc
, document_mode
);
440 max_compat_mode
= doc
->window
&& doc
->window
->base
.outer_window
441 ? get_max_compat_mode(doc
->window
->base
.outer_window
->uri
)
443 if(max_compat_mode
< document_mode
) {
444 WARN("Tried to set compat mode %u higher than maximal configured %u\n",
445 document_mode
, max_compat_mode
);
446 document_mode
= max_compat_mode
;
449 doc
->document_mode
= document_mode
;
451 lock_document_mode(doc
);
454 static BOOL
is_ua_compatible_delimiter(WCHAR c
)
456 return !c
|| c
== ';' || c
== ',' || iswspace(c
);
459 const WCHAR
*parse_compat_version(const WCHAR
*version_string
, compat_mode_t
*r
)
464 for(p
= version_string
; '0' <= *p
&& *p
<= '9'; p
++)
465 version
= version
* 10 + *p
-'0';
466 if(!is_ua_compatible_delimiter(*p
) || p
== version_string
)
472 *r
= COMPAT_MODE_IE5
;
475 *r
= COMPAT_MODE_IE7
;
478 *r
= COMPAT_MODE_IE8
;
481 *r
= COMPAT_MODE_IE9
;
484 *r
= COMPAT_MODE_IE10
;
487 *r
= version
< 5 ? COMPAT_MODE_QUIRKS
: COMPAT_MODE_IE11
;
492 static BOOL
parse_ua_compatible(const WCHAR
*p
, compat_mode_t
*r
)
494 static const WCHAR ie_eqW
[] = {'I','E','='};
495 static const WCHAR edgeW
[] = {'e','d','g','e'};
496 compat_mode_t mode
= COMPAT_MODE_INVALID
;
498 TRACE("%s\n", debugstr_w(p
));
500 if(wcsnicmp(ie_eqW
, p
, ARRAY_SIZE(ie_eqW
)))
505 while(iswspace(*p
)) p
++;
506 if(!wcsnicmp(p
, edgeW
, ARRAY_SIZE(edgeW
))) {
507 p
+= ARRAY_SIZE(edgeW
);
508 if(is_ua_compatible_delimiter(*p
))
509 mode
= COMPAT_MODE_IE11
;
511 }else if(!(p
= parse_compat_version(p
, r
)))
515 while(iswspace(*p
)) p
++;
516 } while(*p
++ == ',');
519 return mode
!= COMPAT_MODE_INVALID
;
522 void process_document_response_headers(HTMLDocumentNode
*doc
, IBinding
*binding
)
524 IWinInetHttpInfo
*http_info
;
529 hres
= IBinding_QueryInterface(binding
, &IID_IWinInetHttpInfo
, (void**)&http_info
);
531 TRACE("No IWinInetHttpInfo\n");
536 strcpy(buf
, "X-UA-Compatible");
537 hres
= IWinInetHttpInfo_QueryInfo(http_info
, HTTP_QUERY_CUSTOM
, buf
, &size
, NULL
, NULL
);
538 if(hres
== S_OK
&& size
) {
539 compat_mode_t document_mode
;
542 TRACE("size %lu\n", size
);
544 header
= strdupAtoW(buf
);
545 if(header
&& parse_ua_compatible(header
, &document_mode
)) {
546 TRACE("setting document mode %d\n", document_mode
);
547 set_document_mode(doc
, document_mode
, FALSE
);
552 IWinInetHttpInfo_Release(http_info
);
555 static void process_meta_element(HTMLDocumentNode
*doc
, nsIDOMHTMLMetaElement
*meta_element
)
557 nsAString http_equiv_str
, content_str
;
560 nsAString_Init(&http_equiv_str
, NULL
);
561 nsAString_Init(&content_str
, NULL
);
562 nsres
= nsIDOMHTMLMetaElement_GetHttpEquiv(meta_element
, &http_equiv_str
);
563 if(NS_SUCCEEDED(nsres
))
564 nsres
= nsIDOMHTMLMetaElement_GetContent(meta_element
, &content_str
);
566 if(NS_SUCCEEDED(nsres
)) {
567 const PRUnichar
*http_equiv
, *content
;
569 nsAString_GetData(&http_equiv_str
, &http_equiv
);
570 nsAString_GetData(&content_str
, &content
);
572 TRACE("%s: %s\n", debugstr_w(http_equiv
), debugstr_w(content
));
574 if(!wcsicmp(http_equiv
, L
"x-ua-compatible")) {
575 compat_mode_t document_mode
;
576 if(parse_ua_compatible(content
, &document_mode
))
577 set_document_mode(doc
, document_mode
, TRUE
);
579 FIXME("Unsupported document mode %s\n", debugstr_w(content
));
583 nsAString_Finish(&http_equiv_str
);
584 nsAString_Finish(&content_str
);
587 typedef struct nsRunnable nsRunnable
;
589 typedef nsresult (*runnable_proc_t
)(HTMLDocumentNode
*,nsISupports
*,nsISupports
*);
592 nsIRunnable nsIRunnable_iface
;
596 runnable_proc_t proc
;
598 HTMLDocumentNode
*doc
;
603 static inline nsRunnable
*impl_from_nsIRunnable(nsIRunnable
*iface
)
605 return CONTAINING_RECORD(iface
, nsRunnable
, nsIRunnable_iface
);
608 static nsresult NSAPI
nsRunnable_QueryInterface(nsIRunnable
*iface
,
609 nsIIDRef riid
, void **result
)
611 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
613 if(IsEqualGUID(riid
, &IID_nsISupports
)) {
614 TRACE("(%p)->(IID_nsISupports %p)\n", This
, result
);
615 *result
= &This
->nsIRunnable_iface
;
616 }else if(IsEqualGUID(riid
, &IID_nsIRunnable
)) {
617 TRACE("(%p)->(IID_nsIRunnable %p)\n", This
, result
);
618 *result
= &This
->nsIRunnable_iface
;
621 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), result
);
622 return NS_NOINTERFACE
;
625 nsISupports_AddRef((nsISupports
*)*result
);
629 static nsrefcnt NSAPI
nsRunnable_AddRef(nsIRunnable
*iface
)
631 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
632 LONG ref
= InterlockedIncrement(&This
->ref
);
634 TRACE("(%p) ref=%ld\n", This
, ref
);
639 static nsrefcnt NSAPI
nsRunnable_Release(nsIRunnable
*iface
)
641 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
642 LONG ref
= InterlockedDecrement(&This
->ref
);
644 TRACE("(%p) ref=%ld\n", This
, ref
);
647 IHTMLDOMNode_Release(&This
->doc
->node
.IHTMLDOMNode_iface
);
649 nsISupports_Release(This
->arg1
);
651 nsISupports_Release(This
->arg2
);
658 static nsresult NSAPI
nsRunnable_Run(nsIRunnable
*iface
)
660 nsRunnable
*This
= impl_from_nsIRunnable(iface
);
662 return This
->proc(This
->doc
, This
->arg1
, This
->arg2
);
665 static const nsIRunnableVtbl nsRunnableVtbl
= {
666 nsRunnable_QueryInterface
,
672 static void add_script_runner(HTMLDocumentNode
*This
, runnable_proc_t proc
, nsISupports
*arg1
, nsISupports
*arg2
)
674 nsRunnable
*runnable
;
676 runnable
= calloc(1, sizeof(*runnable
));
680 runnable
->nsIRunnable_iface
.lpVtbl
= &nsRunnableVtbl
;
683 IHTMLDOMNode_AddRef(&This
->node
.IHTMLDOMNode_iface
);
684 runnable
->doc
= This
;
685 runnable
->proc
= proc
;
688 nsISupports_AddRef(arg1
);
689 runnable
->arg1
= arg1
;
692 nsISupports_AddRef(arg2
);
693 runnable
->arg2
= arg2
;
695 nsIContentUtils_AddScriptRunner(content_utils
, &runnable
->nsIRunnable_iface
);
697 nsIRunnable_Release(&runnable
->nsIRunnable_iface
);
700 static inline HTMLDocumentNode
*impl_from_nsIDocumentObserver(nsIDocumentObserver
*iface
)
702 return CONTAINING_RECORD(iface
, HTMLDocumentNode
, nsIDocumentObserver_iface
);
705 static nsresult NSAPI
nsDocumentObserver_QueryInterface(nsIDocumentObserver
*iface
,
706 nsIIDRef riid
, void **result
)
708 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
710 if(IsEqualGUID(&IID_nsISupports
, riid
)) {
711 TRACE("(%p)->(IID_nsISupports, %p)\n", This
, result
);
712 *result
= &This
->nsIDocumentObserver_iface
;
713 }else if(IsEqualGUID(&IID_nsIMutationObserver
, riid
)) {
714 TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This
, result
);
715 *result
= &This
->nsIDocumentObserver_iface
;
716 }else if(IsEqualGUID(&IID_nsIDocumentObserver
, riid
)) {
717 TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This
, result
);
718 *result
= &This
->nsIDocumentObserver_iface
;
721 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), result
);
722 return NS_NOINTERFACE
;
725 IHTMLDOMNode_AddRef(&This
->node
.IHTMLDOMNode_iface
);
729 static nsrefcnt NSAPI
nsDocumentObserver_AddRef(nsIDocumentObserver
*iface
)
731 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
732 return IHTMLDOMNode_AddRef(&This
->node
.IHTMLDOMNode_iface
);
735 static nsrefcnt NSAPI
nsDocumentObserver_Release(nsIDocumentObserver
*iface
)
737 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
738 return IHTMLDOMNode_Release(&This
->node
.IHTMLDOMNode_iface
);
741 static void NSAPI
nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver
*iface
,
742 nsIDocument
*aDocument
, nsIContent
*aContent
, void /*CharacterDataChangeInfo*/ *aInfo
)
746 static void NSAPI
nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver
*iface
,
747 nsIDocument
*aDocument
, nsIContent
*aContent
, void /*CharacterDataChangeInfo*/ *aInfo
)
751 static void NSAPI
nsDocumentObserver_AttributeWillChange(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
752 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
, LONG aModType
, const nsAttrValue
*aNewValue
)
756 static void NSAPI
nsDocumentObserver_AttributeChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
757 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
, LONG aModType
, const nsAttrValue
*aOldValue
)
761 static void NSAPI
nsDocumentObserver_NativeAnonymousChildListChange(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
762 nsIContent
*aContent
, cpp_bool aIsRemove
)
766 static void NSAPI
nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
767 void *aElement
, LONG aNameSpaceID
, nsIAtom
*aAttribute
)
771 static void NSAPI
nsDocumentObserver_ContentAppended(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
772 nsIContent
*aContainer
, nsIContent
*aFirstNewContent
, LONG aNewIndexInContainer
)
776 static void NSAPI
nsDocumentObserver_ContentInserted(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
777 nsIContent
*aContainer
, nsIContent
*aChild
, LONG aIndexInContainer
)
781 static void NSAPI
nsDocumentObserver_ContentRemoved(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
782 nsIContent
*aContainer
, nsIContent
*aChild
, LONG aIndexInContainer
,
783 nsIContent
*aProviousSibling
)
787 static void NSAPI
nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver
*iface
, const nsINode
*aNode
)
791 static void NSAPI
nsDocumentObserver_ParentChainChanged(nsIDocumentObserver
*iface
, nsIContent
*aContent
)
795 static void NSAPI
nsDocumentObserver_BeginUpdate(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
796 nsUpdateType aUpdateType
)
800 static void NSAPI
nsDocumentObserver_EndUpdate(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
801 nsUpdateType aUpdateType
)
805 static void NSAPI
nsDocumentObserver_BeginLoad(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
)
809 static void NSAPI
nsDocumentObserver_EndLoad(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
)
811 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
813 TRACE("(%p)\n", This
);
815 if(This
->skip_mutation_notif
)
818 This
->content_ready
= TRUE
;
819 add_script_runner(This
, run_end_load
, NULL
, NULL
);
822 static void NSAPI
nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
823 nsIContent
*aContent
, EventStates aStateMask
)
827 static void NSAPI
nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
828 EventStates aStateMask
)
832 static void NSAPI
nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
,
833 cpp_bool aDocumentSheet
)
837 static void NSAPI
nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
,
838 cpp_bool aDocumentSheet
)
842 static void NSAPI
nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver
*iface
,
843 mozilla_StyleSheetHandle aStyleSheet
)
847 static void NSAPI
nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
851 static void NSAPI
nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
855 static void NSAPI
nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver
*iface
, mozilla_StyleSheetHandle aStyleSheet
)
859 static void NSAPI
nsDocumentObserver_BindToDocument(nsIDocumentObserver
*iface
, nsIDocument
*aDocument
,
860 nsIContent
*aContent
)
862 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
863 nsIDOMHTMLIFrameElement
*nsiframe
;
864 nsIDOMHTMLFrameElement
*nsframe
;
865 nsIDOMHTMLScriptElement
*nsscript
;
866 nsIDOMHTMLMetaElement
*nsmeta
;
867 nsIDOMElement
*nselem
;
868 nsIDOMComment
*nscomment
;
871 TRACE("(%p)->(%p %p)\n", This
, aDocument
, aContent
);
873 if(This
->document_mode
< COMPAT_MODE_IE10
) {
874 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMComment
, (void**)&nscomment
);
875 if(NS_SUCCEEDED(nsres
)) {
876 TRACE("comment node\n");
878 add_script_runner(This
, run_insert_comment
, (nsISupports
*)nscomment
, NULL
);
879 nsIDOMComment_Release(nscomment
);
884 if(This
->document_mode
== COMPAT_MODE_QUIRKS
) {
885 nsIDOMDocumentType
*nsdoctype
;
887 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMDocumentType
, (void**)&nsdoctype
);
888 if(NS_SUCCEEDED(nsres
)) {
889 compat_mode_t mode
= COMPAT_MODE_IE7
;
891 TRACE("doctype node\n");
893 /* Native mshtml hardcodes special behavior for iexplore.exe here. The feature control registry
894 keys under HKLM or HKCU\Software\Microsoft\Internet Explorer\Main\FeatureControl are not used
895 in this case (neither in Wow6432Node), although FEATURE_BROWSER_EMULATION does override this,
896 but it is not set by default on native, and the behavior is still different. This was tested
897 by removing all iexplore.exe values from any FeatureControl subkeys, and renaming the test
898 executable to iexplore.exe, which changed its default compat mode in such cases. */
899 if(This
->window
&& This
->window
->base
.outer_window
&& is_iexplore()) {
900 HTMLOuterWindow
*window
= This
->window
->base
.outer_window
;
904 /* Internet URL zone is treated differently and defaults to the latest supported mode. */
905 hres
= IInternetSecurityManager_MapUrlToZone(get_security_manager(), window
->url
, &zone
, 0);
906 if(SUCCEEDED(hres
) && zone
== URLZONE_INTERNET
)
907 mode
= COMPAT_MODE_IE11
;
910 set_document_mode(This
, mode
, FALSE
);
911 nsIDOMDocumentType_Release(nsdoctype
);
915 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMElement
, (void**)&nselem
);
919 check_event_attr(This
, nselem
);
920 nsIDOMElement_Release(nselem
);
922 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLIFrameElement
, (void**)&nsiframe
);
923 if(NS_SUCCEEDED(nsres
)) {
924 TRACE("iframe node\n");
926 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsiframe
, NULL
);
927 nsIDOMHTMLIFrameElement_Release(nsiframe
);
931 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLFrameElement
, (void**)&nsframe
);
932 if(NS_SUCCEEDED(nsres
)) {
933 TRACE("frame node\n");
935 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsframe
, NULL
);
936 nsIDOMHTMLFrameElement_Release(nsframe
);
940 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
941 if(NS_SUCCEEDED(nsres
)) {
942 TRACE("script element\n");
944 add_script_runner(This
, run_bind_to_tree
, (nsISupports
*)nsscript
, NULL
);
945 nsIDOMHTMLScriptElement_Release(nsscript
);
949 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLMetaElement
, (void**)&nsmeta
);
950 if(NS_SUCCEEDED(nsres
)) {
951 process_meta_element(This
, nsmeta
);
952 nsIDOMHTMLMetaElement_Release(nsmeta
);
956 static void NSAPI
nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver
*iface
, nsIContent
*aContent
,
957 nsIParser
*aParser
, cpp_bool
*aBlock
)
959 HTMLDocumentNode
*This
= impl_from_nsIDocumentObserver(iface
);
960 nsIDOMHTMLScriptElement
*nsscript
;
963 TRACE("(%p)->(%p %p %p)\n", This
, aContent
, aParser
, aBlock
);
965 nsres
= nsIContent_QueryInterface(aContent
, &IID_nsIDOMHTMLScriptElement
, (void**)&nsscript
);
966 if(NS_SUCCEEDED(nsres
)) {
967 TRACE("script node\n");
969 lock_document_mode(This
);
970 add_script_runner(This
, run_insert_script
, (nsISupports
*)nsscript
, (nsISupports
*)aParser
);
971 nsIDOMHTMLScriptElement_Release(nsscript
);
975 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl
= {
976 nsDocumentObserver_QueryInterface
,
977 nsDocumentObserver_AddRef
,
978 nsDocumentObserver_Release
,
979 nsDocumentObserver_CharacterDataWillChange
,
980 nsDocumentObserver_CharacterDataChanged
,
981 nsDocumentObserver_AttributeWillChange
,
982 nsDocumentObserver_AttributeChanged
,
983 nsDocumentObserver_NativeAnonymousChildListChange
,
984 nsDocumentObserver_AttributeSetToCurrentValue
,
985 nsDocumentObserver_ContentAppended
,
986 nsDocumentObserver_ContentInserted
,
987 nsDocumentObserver_ContentRemoved
,
988 nsDocumentObserver_NodeWillBeDestroyed
,
989 nsDocumentObserver_ParentChainChanged
,
990 nsDocumentObserver_BeginUpdate
,
991 nsDocumentObserver_EndUpdate
,
992 nsDocumentObserver_BeginLoad
,
993 nsDocumentObserver_EndLoad
,
994 nsDocumentObserver_ContentStatesChanged
,
995 nsDocumentObserver_DocumentStatesChanged
,
996 nsDocumentObserver_StyleSheetAdded
,
997 nsDocumentObserver_StyleSheetRemoved
,
998 nsDocumentObserver_StyleSheetApplicableStateChanged
,
999 nsDocumentObserver_StyleRuleChanged
,
1000 nsDocumentObserver_StyleRuleAdded
,
1001 nsDocumentObserver_StyleRuleRemoved
,
1002 nsDocumentObserver_BindToDocument
,
1003 nsDocumentObserver_AttemptToExecuteScript
1006 void init_document_mutation(HTMLDocumentNode
*doc
)
1011 doc
->nsIDocumentObserver_iface
.lpVtbl
= &nsDocumentObserverVtbl
;
1013 nsres
= nsIDOMDocument_QueryInterface(doc
->dom_document
, &IID_nsIDocument
, (void**)&nsdoc
);
1014 if(NS_FAILED(nsres
)) {
1015 ERR("Could not get nsIDocument: %08lx\n", nsres
);
1019 nsIContentUtils_AddDocumentObserver(content_utils
, nsdoc
, &doc
->nsIDocumentObserver_iface
);
1020 nsIDocument_Release(nsdoc
);
1023 void release_document_mutation(HTMLDocumentNode
*doc
)
1028 nsres
= nsIDOMDocument_QueryInterface(doc
->dom_document
, &IID_nsIDocument
, (void**)&nsdoc
);
1029 if(NS_FAILED(nsres
)) {
1030 ERR("Could not get nsIDocument: %08lx\n", nsres
);
1034 nsIContentUtils_RemoveDocumentObserver(content_utils
, nsdoc
, &doc
->nsIDocumentObserver_iface
);
1035 nsIDocument_Release(nsdoc
);
1038 JSContext
*get_context_from_document(nsIDOMDocument
*nsdoc
)
1044 nsres
= nsIDOMDocument_QueryInterface(nsdoc
, &IID_nsIDocument
, (void**)&doc
);
1045 assert(nsres
== NS_OK
);
1047 ctx
= nsIContentUtils_GetContextFromDocument(content_utils
, doc
);
1048 nsIDocument_Release(doc
);
1050 TRACE("ret %p\n", ctx
);
1054 void init_mutation(nsIComponentManager
*component_manager
)
1056 nsIFactory
*factory
;
1059 if(!component_manager
) {
1061 nsIContentUtils_Release(content_utils
);
1062 content_utils
= NULL
;
1067 nsres
= nsIComponentManager_GetClassObject(component_manager
, &NS_ICONTENTUTILS_CID
,
1068 &IID_nsIFactory
, (void**)&factory
);
1069 if(NS_FAILED(nsres
)) {
1070 ERR("Could not create nsIContentUtils service: %08lx\n", nsres
);
1074 nsres
= nsIFactory_CreateInstance(factory
, NULL
, &IID_nsIContentUtils
, (void**)&content_utils
);
1075 nsIFactory_Release(factory
);
1076 if(NS_FAILED(nsres
))
1077 ERR("Could not create nsIContentUtils instance: %08lx\n", nsres
);