Jacek Caban : mshtml: Allow setting event handlers to strings.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Mar 11 10:00:42 CDT 2015


Module: wine
Branch: master
Commit: 144056bce0f1195ab8f4bdd8b2c40bf5b39e9d50
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=144056bce0f1195ab8f4bdd8b2c40bf5b39e9d50

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Mar 10 18:27:31 2015 +0100

mshtml: Allow setting event handlers to strings.

---

 dlls/mshtml/htmlevent.c       | 62 +++++++++++++++++++++++++++++++++----------
 dlls/mshtml/htmlevent.h       |  8 +++---
 dlls/mshtml/htmlwindow.c      |  5 ++--
 dlls/mshtml/tests/events.c    |  2 +-
 dlls/mshtml/tests/events.html | 19 +++++++++++++
 5 files changed, 75 insertions(+), 21 deletions(-)

diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index e1ece61..a14ce72 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -1367,23 +1367,29 @@ void detach_events(HTMLDocumentNode *doc)
 }
 
 
-static HRESULT remove_event_handler(event_target_t **event_target, eventid_t eid)
+static void remove_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid)
 {
+    VARIANT *store;
+    HRESULT hres;
+
+    hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &store);
+    if(SUCCEEDED(hres))
+        VariantClear(store);
+
     if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
         IDispatch_Release((*event_target)->event_table[eid]->handler_prop);
         (*event_target)->event_table[eid]->handler_prop = NULL;
     }
-
-    return S_OK;
 }
 
-static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDocumentNode *doc,
+static HRESULT set_event_handler_disp(DispatchEx *dispex, event_target_t **event_target_ptr, HTMLDocumentNode *doc,
         eventid_t eid, IDispatch *disp)
 {
     event_target_t *event_target;
 
+    remove_event_handler(dispex, event_target_ptr, eid);
     if(!disp)
-        return remove_event_handler(event_target_ptr, eid);
+        return S_OK;
 
     event_target = get_event_target(event_target_ptr);
     if(!event_target)
@@ -1392,23 +1398,44 @@ static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDoc
     if(!alloc_handler_vector(event_target, eid, 0))
         return E_OUTOFMEMORY;
 
-    if(event_target->event_table[eid]->handler_prop)
-        IDispatch_Release(event_target->event_table[eid]->handler_prop);
-
     event_target->event_table[eid]->handler_prop = disp;
     IDispatch_AddRef(disp);
 
     return ensure_nsevent_handler(doc, event_target, eid);
 }
 
-HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var)
+HRESULT set_event_handler(DispatchEx *dispex, event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var)
 {
     switch(V_VT(var)) {
     case VT_NULL:
-        return remove_event_handler(event_target, eid);
+        remove_event_handler(dispex, event_target, eid);
+        return S_OK;
 
     case VT_DISPATCH:
-        return set_event_handler_disp(event_target, doc, eid, V_DISPATCH(var));
+        return set_event_handler_disp(dispex, event_target, doc, eid, V_DISPATCH(var));
+
+    case VT_BSTR: {
+        VARIANT *v;
+        HRESULT hres;
+
+        /*
+         * Setting event handler to string is a rare case and we don't want to
+         * complicate nor increase memory of event_target_t for that. Instead,
+         * we store the value in DispatchEx, which can already handle custom
+         * properties.
+         */
+        remove_event_handler(dispex, event_target, eid);
+
+        hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, TRUE, &v);
+        if(FAILED(hres))
+            return hres;
+
+        V_BSTR(v) = SysAllocString(V_BSTR(var));
+        if(!V_BSTR(v))
+            return E_OUTOFMEMORY;
+        V_VT(v) = VT_BSTR;
+        return S_OK;
+    }
 
     default:
         FIXME("not handler %s\n", debugstr_variant(var));
@@ -1420,8 +1447,15 @@ HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc,
     return S_OK;
 }
 
-HRESULT get_event_handler(event_target_t **event_target, eventid_t eid, VARIANT *var)
+HRESULT get_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid, VARIANT *var)
 {
+    VARIANT *v;
+    HRESULT hres;
+
+    hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &v);
+    if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY)
+        return VariantCopy(var, v);
+
     if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
         V_VT(var) = VT_DISPATCH;
         V_DISPATCH(var) = (*event_target)->event_table[eid]->handler_prop;
@@ -1507,7 +1541,7 @@ void bind_node_event(HTMLDocumentNode *doc, event_target_t **event_target, HTMLD
         return;
     }
 
-    set_event_handler_disp(event_target, doc, eid, disp);
+    set_event_handler_disp(&node->dispex, event_target, doc, eid, disp);
 }
 
 void update_cp_events(HTMLInnerWindow *window, event_target_t **event_target_ptr, cp_static_data_t *cp)
@@ -1547,7 +1581,7 @@ void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
             if(disp) {
                 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
                 if(SUCCEEDED(hres)) {
-                    set_event_handler_disp(get_node_event_target(node), node->doc, i, disp);
+                    set_event_handler_disp(&node->dispex, get_node_event_target(node), node->doc, i, disp);
                     node_release(node);
                 }
                 IDispatch_Release(disp);
diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h
index e312a9c..0517834 100644
--- a/dlls/mshtml/htmlevent.h
+++ b/dlls/mshtml/htmlevent.h
@@ -54,8 +54,8 @@ eventid_t str_to_eid(LPCWSTR) DECLSPEC_HIDDEN;
 void check_event_attr(HTMLDocumentNode*,nsIDOMHTMLElement*) DECLSPEC_HIDDEN;
 void release_event_target(event_target_t*) DECLSPEC_HIDDEN;
 void fire_event(HTMLDocumentNode*,eventid_t,BOOL,nsIDOMNode*,nsIDOMEvent*,IDispatch*) DECLSPEC_HIDDEN;
-HRESULT set_event_handler(event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
-HRESULT get_event_handler(event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
+HRESULT set_event_handler(DispatchEx*,event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
+HRESULT get_event_handler(DispatchEx*,event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
 HRESULT attach_event(event_target_t**,HTMLDocument*,BSTR,IDispatch*,VARIANT_BOOL*) DECLSPEC_HIDDEN;
 HRESULT detach_event(event_target_t*,HTMLDocument*,BSTR,IDispatch*) DECLSPEC_HIDDEN;
 HRESULT dispatch_event(HTMLDOMNode*,const WCHAR*,VARIANT*,VARIANT_BOOL*) DECLSPEC_HIDDEN;
@@ -78,12 +78,12 @@ static inline event_target_t **get_node_event_target(HTMLDOMNode *node)
 
 static inline HRESULT set_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var)
 {
-    return set_event_handler(get_node_event_target(node), node->doc, eid, var);
+    return set_event_handler(&node->dispex, get_node_event_target(node), node->doc, eid, var);
 }
 
 static inline HRESULT get_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var)
 {
-    return get_event_handler(get_node_event_target(node), eid, var);
+    return get_event_handler(&node->dispex, get_node_event_target(node), eid, var);
 }
 
 static inline HRESULT set_doc_event(HTMLDocument *doc, eventid_t eid, VARIANT *var)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c
index 6f3cbd4..3a31301 100644
--- a/dlls/mshtml/htmlwindow.c
+++ b/dlls/mshtml/htmlwindow.c
@@ -95,7 +95,8 @@ static inline HRESULT set_window_event(HTMLWindow *window, eventid_t eid, VARIAN
         return E_FAIL;
     }
 
-    return set_event_handler(&window->inner_window->doc->body_event_target, window->inner_window->doc, eid, var);
+    return set_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target,
+                             window->inner_window->doc, eid, var);
 }
 
 static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIANT *var)
@@ -105,7 +106,7 @@ static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIAN
         return E_FAIL;
     }
 
-    return get_event_handler(&window->inner_window->doc->body_event_target, eid, var);
+    return get_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target, eid, var);
 }
 
 static void detach_inner_window(HTMLInnerWindow *window)
diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c
index 8f4e15e..e3e7f72 100644
--- a/dlls/mshtml/tests/events.c
+++ b/dlls/mshtml/tests/events.c
@@ -1571,7 +1571,7 @@ static void test_onclick(IHTMLDocument2 *doc)
     V_VT(&v) = VT_BSTR;
     V_BSTR(&v) = a2bstr("function();");
     hres = IHTMLElement_put_onclick(div, v);
-    todo_wine ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
+    ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
 
     if(hres == S_OK) {
         V_VT(&v) = VT_EMPTY;
diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html
index ae83ebe..5a0bbfb 100644
--- a/dlls/mshtml/tests/events.html
+++ b/dlls/mshtml/tests/events.html
@@ -139,6 +139,24 @@ function test_insert_script() {
     readystatechange_log = "append";
 }
 
+var string_handler_called = false;
+
+function test_string_event_handler() {
+    var e = document.createElement("div");
+    var event_str = "string_handler_called = true;";
+
+    document.body.appendChild(e);
+    e.onclick = event_str;
+    ok(e.onclick === event_str, "e.onclick = " + e.onclick);
+    e.click();
+    ok(string_handler_called === false, "string handler called");
+
+    e.setAttribute("onclick", event_str);
+    ok(e.onclick === event_str, "e.onclick = " + e.onclick);
+    e.click();
+    ok(string_handler_called === false, "string handler called");
+}
+
 window.onload = function() {
     try {
         ok(inlscr_complete_called, "onreadystatechange not fired");
@@ -159,6 +177,7 @@ window.onload = function() {
         ondataavailable_test();
         test_handler_this();
         test_insert_script();
+        test_string_event_handler();
     }catch(e) {
         ok(false, "Got an exception: " + e.message);
     }




More information about the wine-cvs mailing list