mshtml: Added support for recursive script runners.

oldstable
Jacek Caban 2011-01-31 00:32:30 +01:00 committed by Alexandre Julliard
parent bfebbbb13e
commit c8a953c5d0
3 changed files with 178 additions and 191 deletions

View File

@ -586,13 +586,6 @@ struct HTMLFrameBase {
nsIDOMHTMLIFrameElement *nsiframe;
};
typedef struct _mutation_queue_t {
DWORD type;
nsISupports *nsiface;
struct _mutation_queue_t *next;
} mutation_queue_t;
typedef struct nsDocumentEventListener nsDocumentEventListener;
struct HTMLDocumentNode {
@ -602,7 +595,6 @@ struct HTMLDocumentNode {
IInternetHostSecurityManager IInternetHostSecurityManager_iface;
nsIDocumentObserver nsIDocumentObserver_iface;
nsIRunnable nsIRunnable_iface;
LONG ref;
@ -617,8 +609,6 @@ struct HTMLDocumentNode {
BOOL *event_vector;
BOOL skip_mutation_notif;
mutation_queue_t *mutation_queue;
mutation_queue_t *mutation_queue_tail;
struct list bindings;
struct list selection_list;

View File

@ -36,13 +36,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
enum {
MUTATION_BINDTOTREE,
MUTATION_COMMENT,
MUTATION_ENDLOAD,
MUTATION_SCRIPT
};
#define IE_MAJOR_VERSION 7
#define IE_MINOR_VERSION 0
@ -182,117 +175,78 @@ static BOOL handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *commen
return TRUE;
}
static void add_script_runner(HTMLDocumentNode *This)
static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
{
nsIDOMNSDocument *nsdoc;
const PRUnichar *comment;
nsIDOMComment *nscomment;
nsAString comment_str;
BOOL remove_comment;
nsresult nsres;
nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
if(NS_FAILED(nsres)) {
ERR("Could not get nsIDOMNSDocument: %08x\n", nsres);
return;
ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
return nsres;
}
nsIDOMNSDocument_WineAddScriptRunner(nsdoc, &This->nsIRunnable_iface);
nsIDOMNSDocument_Release(nsdoc);
}
nsAString_Init(&comment_str, NULL);
nsres = nsIDOMComment_GetData(nscomment, &comment_str);
if(NS_FAILED(nsres))
return nsres;
static inline HTMLDocumentNode *impl_from_nsIRunnable(nsIRunnable *iface)
{
return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIRunnable_iface);
}
nsAString_GetData(&comment_str, &comment);
remove_comment = handle_insert_comment(doc, comment);
nsAString_Finish(&comment_str);
static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
nsIIDRef riid, void **result)
{
HTMLDocumentNode *This = impl_from_nsIRunnable(iface);
if(remove_comment) {
nsIDOMNode *nsparent, *tmp;
nsAString magic_str;
if(IsEqualGUID(riid, &IID_nsISupports)) {
TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
*result = &This->nsIRunnable_iface;
}else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
*result = &This->nsIRunnable_iface;
}else {
*result = NULL;
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
return NS_NOINTERFACE;
static const PRUnichar remove_comment_magicW[] =
{'#','!','w','i','n','e', 'r','e','m','o','v','e','!','#',0};
nsAString_InitDepend(&magic_str, remove_comment_magicW);
nsres = nsIDOMComment_SetData(nscomment, &magic_str);
nsAString_Finish(&magic_str);
if(NS_FAILED(nsres))
ERR("SetData failed: %08x\n", nsres);
nsIDOMComment_GetParentNode(nscomment, &nsparent);
if(nsparent) {
nsIDOMNode_RemoveChild(nsparent, (nsIDOMNode*)nscomment, &tmp);
nsIDOMNode_Release(nsparent);
nsIDOMNode_Release(tmp);
}
}
nsISupports_AddRef((nsISupports*)*result);
nsIDOMComment_Release(nscomment);
return NS_OK;
}
static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
{
HTMLDocumentNode *This = impl_from_nsIRunnable(iface);
return htmldoc_addref(&This->basedoc);
}
static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
{
HTMLDocumentNode *This = impl_from_nsIRunnable(iface);
return htmldoc_release(&This->basedoc);
}
static void push_mutation_queue(HTMLDocumentNode *doc, DWORD type, nsISupports *nsiface)
{
mutation_queue_t *elem;
elem = heap_alloc(sizeof(mutation_queue_t));
if(!elem)
return;
elem->next = NULL;
elem->type = type;
elem->nsiface = nsiface;
if(nsiface)
nsISupports_AddRef(nsiface);
if(doc->mutation_queue_tail) {
doc->mutation_queue_tail = doc->mutation_queue_tail->next = elem;
}else {
doc->mutation_queue = doc->mutation_queue_tail = elem;
add_script_runner(doc);
}
}
static void pop_mutation_queue(HTMLDocumentNode *doc)
{
mutation_queue_t *tmp = doc->mutation_queue;
if(!tmp)
return;
doc->mutation_queue = tmp->next;
if(!tmp->next)
doc->mutation_queue_tail = NULL;
if(tmp->nsiface)
nsISupports_Release(tmp->nsiface);
heap_free(tmp);
}
static void bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface)
static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
{
nsIDOMNode *nsnode;
HTMLDOMNode *node;
nsresult nsres;
HRESULT hres;
TRACE("(%p)->(%p)\n", doc, nsiface);
nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
if(NS_FAILED(nsres))
return;
return nsres;
hres = get_node(doc, nsnode, TRUE, &node);
nsIDOMNode_Release(nsnode);
if(FAILED(hres)) {
ERR("Could not get node\n");
return;
return nsres;
}
if(node->vtbl->bind_to_tree)
node->vtbl->bind_to_tree(node);
return nsres;
}
/* Calls undocumented 69 cmd of CGID_Explorer */
@ -332,12 +286,12 @@ static void parse_complete(HTMLDocumentObj *doc)
/* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
}
static void handle_end_load(HTMLDocumentNode *This)
static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
{
TRACE("\n");
TRACE("(%p)\n", This);
if(!This->basedoc.doc_obj)
return;
return NS_OK;
if(This == This->basedoc.doc_obj->basedoc.doc_node) {
/*
@ -348,95 +302,103 @@ static void handle_end_load(HTMLDocumentNode *This)
}
set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
return NS_OK;
}
static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *arg)
{
nsIDOMHTMLScriptElement *nsscript;
nsresult nsres;
TRACE("(%p)->(%p)\n", doc, script_iface);
nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
if(NS_FAILED(nsres)) {
ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
return nsres;
}
doc_insert_script(doc->basedoc.window, nsscript);
nsIDOMHTMLScriptElement_Release(nsscript);
return NS_OK;
}
typedef struct nsRunnable nsRunnable;
typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
struct nsRunnable {
nsIRunnable nsIRunnable_iface;
LONG ref;
runnable_proc_t proc;
HTMLDocumentNode *doc;
nsISupports *arg1;
nsISupports *arg2;
};
static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
{
return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
}
static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
nsIIDRef riid, void **result)
{
nsRunnable *This = impl_from_nsIRunnable(iface);
if(IsEqualGUID(riid, &IID_nsISupports)) {
TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
*result = &This->nsIRunnable_iface;
}else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
*result = &This->nsIRunnable_iface;
}else {
*result = NULL;
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
return NS_NOINTERFACE;
}
nsISupports_AddRef((nsISupports*)*result);
return NS_OK;
}
static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
{
nsRunnable *This = impl_from_nsIRunnable(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
{
nsRunnable *This = impl_from_nsIRunnable(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
htmldoc_release(&This->doc->basedoc);
if(This->arg1)
nsISupports_Release(This->arg1);
if(This->arg2)
nsISupports_Release(This->arg2);
heap_free(This);
}
return ref;
}
static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
{
HTMLDocumentNode *This = impl_from_nsIRunnable(iface);
nsresult nsres;
nsRunnable *This = impl_from_nsIRunnable(iface);
TRACE("(%p)\n", This);
while(This->mutation_queue) {
switch(This->mutation_queue->type) {
case MUTATION_BINDTOTREE:
bind_to_tree(This, This->mutation_queue->nsiface);
break;
case MUTATION_COMMENT: {
nsIDOMComment *nscomment;
nsAString comment_str;
BOOL remove_comment = FALSE;
nsres = nsISupports_QueryInterface(This->mutation_queue->nsiface, &IID_nsIDOMComment, (void**)&nscomment);
if(NS_FAILED(nsres)) {
ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
return NS_OK;
}
nsAString_Init(&comment_str, NULL);
nsres = nsIDOMComment_GetData(nscomment, &comment_str);
if(NS_SUCCEEDED(nsres)) {
const PRUnichar *comment;
nsAString_GetData(&comment_str, &comment);
remove_comment = handle_insert_comment(This, comment);
}
nsAString_Finish(&comment_str);
if(remove_comment) {
nsIDOMNode *nsparent, *tmp;
nsAString magic_str;
static const PRUnichar remove_comment_magicW[] =
{'#','!','w','i','n','e', 'r','e','m','o','v','e','!','#',0};
nsAString_InitDepend(&magic_str, remove_comment_magicW);
nsres = nsIDOMComment_SetData(nscomment, &magic_str);
nsAString_Finish(&magic_str);
if(NS_FAILED(nsres))
ERR("SetData failed: %08x\n", nsres);
nsIDOMComment_GetParentNode(nscomment, &nsparent);
if(nsparent) {
nsIDOMNode_RemoveChild(nsparent, (nsIDOMNode*)nscomment, &tmp);
nsIDOMNode_Release(nsparent);
nsIDOMNode_Release(tmp);
}
}
nsIDOMComment_Release(nscomment);
break;
}
case MUTATION_ENDLOAD:
handle_end_load(This);
break;
case MUTATION_SCRIPT: {
nsIDOMHTMLScriptElement *nsscript;
nsres = nsISupports_QueryInterface(This->mutation_queue->nsiface, &IID_nsIDOMHTMLScriptElement,
(void**)&nsscript);
if(NS_FAILED(nsres)) {
ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
break;
}
doc_insert_script(This->basedoc.window, nsscript);
nsIDOMHTMLScriptElement_Release(nsscript);
break;
}
default:
ERR("invalid type %d\n", This->mutation_queue->type);
}
pop_mutation_queue(This);
}
return S_OK;
return This->proc(This->doc, This->arg1, This->arg2);
}
static const nsIRunnableVtbl nsRunnableVtbl = {
@ -446,6 +408,42 @@ static const nsIRunnableVtbl nsRunnableVtbl = {
nsRunnable_Run
};
static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
{
nsIDOMNSDocument *nsdoc;
nsRunnable *runnable;
nsresult nsres;
runnable = heap_alloc_zero(sizeof(*runnable));
if(!runnable)
return;
runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
runnable->ref = 1;
htmldoc_addref(&This->basedoc);
runnable->doc = This;
runnable->proc = proc;
if(arg1)
nsISupports_AddRef(arg1);
runnable->arg1 = arg1;
if(arg2)
nsISupports_AddRef(arg2);
runnable->arg2 = arg2;
nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
if(NS_SUCCEEDED(nsres)) {
nsIDOMNSDocument_WineAddScriptRunner(nsdoc, &runnable->nsIRunnable_iface);
nsIDOMNSDocument_Release(nsdoc);
}else {
ERR("Could not get nsIDOMNSDocument: %08x\n", nsres);
}
nsIRunnable_Release(&runnable->nsIRunnable_iface);
}
static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
{
return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
@ -555,7 +553,7 @@ static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocu
return;
This->content_ready = TRUE;
push_mutation_queue(This, MUTATION_ENDLOAD, NULL);
add_script_runner(This, run_end_load, NULL, NULL);
}
static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
@ -620,7 +618,7 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface,
if(NS_SUCCEEDED(nsres)) {
TRACE("comment node\n");
push_mutation_queue(This, MUTATION_COMMENT, (nsISupports*)nscomment);
add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
nsIDOMComment_Release(nscomment);
}
@ -628,7 +626,7 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface,
if(NS_SUCCEEDED(nsres)) {
TRACE("iframe node\n");
push_mutation_queue(This, MUTATION_BINDTOTREE, (nsISupports*)nsiframe);
add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
nsIDOMHTMLIFrameElement_Release(nsiframe);
}
@ -636,7 +634,7 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface,
if(NS_SUCCEEDED(nsres)) {
TRACE("frame node\n");
push_mutation_queue(This, MUTATION_BINDTOTREE, (nsISupports*)nsframe);
add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
nsIDOMHTMLFrameElement_Release(nsframe);
}
}
@ -654,7 +652,7 @@ static void NSAPI nsDocumentObserver_DoneAddingChildren(nsIDocumentObserver *ifa
if(NS_SUCCEEDED(nsres)) {
TRACE("script node\n");
push_mutation_queue(This, MUTATION_SCRIPT, (nsISupports*)nsscript);
add_script_runner(This, run_insert_script, (nsISupports*)nsscript, NULL);
nsIDOMHTMLScriptElement_Release(nsscript);
}
}
@ -694,7 +692,6 @@ void init_mutation(HTMLDocumentNode *doc)
nsresult nsres;
doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
doc->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDOMNSDocument, (void**)&nsdoc);
if(NS_FAILED(nsres)) {

View File

@ -21,7 +21,7 @@ document.write("<script>"
len = document.getElementsByTagName('script').length;
external.todo_wine_ok(len === 2, "script col length = " + len);
external.todo_wine_ok(executed, "writen script not executed");
ok(executed, "writen script not executed");
external.reportSuccess();
</script>