From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 85 ++++++++++++++++++++++++++++++++++-- dlls/mshtml/htmlwindow.c | 38 ++++++++++++++++ dlls/mshtml/mshtml_private.h | 15 +++++++ dlls/mshtml/tests/es5.js | 15 +++++++ 4 files changed, 149 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index b8ebf1ba5f4..c4c1a5431b4 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -522,10 +522,12 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ if(desc->init_info) desc->init_info(data, compat_mode);
- for(tid = desc->iface_tids; *tid; tid++) { - hres = process_interface(data, *tid, dti, NULL); - if(FAILED(hres)) - break; + if(desc->iface_tids) { + for(tid = desc->iface_tids; *tid; tid++) { + hres = process_interface(data, *tid, dti, NULL); + if(FAILED(hres)) + break; + } }
if(!data->func_cnt) { @@ -715,6 +717,20 @@ static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags return alloc_dynamic_prop(This, name, NULL, ret); }
+HRESULT dispex_define_property(DispatchEx *dispex, const WCHAR *name, DWORD flags, VARIANT *v, DISPID *id) +{ + dynamic_prop_t *prop; + HRESULT hres; + + hres = alloc_dynamic_prop(dispex, name, NULL, &prop); + if(FAILED(hres)) + return hres; + + *id = DISPID_DYNPROP_0 + (prop - dispex->dynamic_data->props); + prop->flags = flags; + return VariantCopy(&prop->var, v); +} + HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VARIANT **ret) { dynamic_prop_t *prop; @@ -2680,3 +2696,64 @@ void init_dispatch_with_owner(DispatchEx *dispex, dispex_static_data_t *desc, Di if(script_global) IHTMLWindow2_Release(&script_global->base.IHTMLWindow2_iface); } + +struct constructor +{ + DispatchEx dispex; + prototype_id_t id; +}; + +static inline struct constructor *constr_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct constructor, dispex); +} + +static void constructor_destructor(DispatchEx *dispex) +{ + struct constructor *constr = constr_from_DispatchEx(dispex); + free(constr); +} + +static HRESULT constructor_find_dispid(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID *dispid) +{ + struct constructor *constr = constr_from_DispatchEx(dispex); + VARIANT v; + + if(wcscmp(name, L"prototype")) + return DISP_E_UNKNOWNNAME; + + FIXME("prototype not implemented\n"); + V_VT(&v) = VT_EMPTY; + return dispex_define_property(&constr->dispex, name, 0, &v, dispid); +} + +static const dispex_static_data_vtbl_t constructor_dispex_vtbl = { + .destructor = constructor_destructor, + .find_dispid = constructor_find_dispid, +}; + +static dispex_static_data_t constructor_dispex = { + .name = "Constructor", + .vtbl = &constructor_dispex_vtbl, +}; + +HRESULT get_constructor(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret) +{ + struct constructor *constr; + + assert(script_global->doc->document_mode >= COMPAT_MODE_IE9); + + if(script_global->constructors[id]) { + *ret = script_global->constructors[id]; + return S_OK; + } + + if(!(constr = calloc(sizeof(*constr), 1))) + return E_OUTOFMEMORY; + + init_dispatch(&constr->dispex, &constructor_dispex, script_global, + dispex_compat_mode(&script_global->event_target.dispex)); + constr->id = id; + *ret = script_global->constructors[id] = &constr->dispex; + return S_OK; +} diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 52201715af8..ac427ded3ba 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3678,10 +3678,15 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); HTMLOuterWindow *child; + unsigned int i;
traverse_event_target(&This->event_target, cb); LIST_FOR_EACH_ENTRY(child, &This->children, HTMLOuterWindow, sibling_entry) note_cc_edge((nsISupports*)&child->base.IHTMLWindow2_iface, "child", cb); + for(i = 0; i < ARRAYSIZE(This->constructors); i++) { + if(This->constructors[i]) + note_cc_edge((nsISupports*)&This->constructors[i]->IWineJSDispatchHost_iface, "constructors", cb); + } if(This->doc) note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); if(This->console) @@ -3712,12 +3717,16 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa static void HTMLWindow_unlink(DispatchEx *dispex) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + unsigned int i;
TRACE("%p\n", This);
unlink_ref(&This->console); detach_inner_window(This);
+ for(i = 0; i < ARRAYSIZE(This->constructors); i++) + unlink_ref(&This->constructors[i]); + if(This->doc) { HTMLDocumentNode *doc = This->doc; This->doc = NULL; @@ -3793,6 +3802,17 @@ static HRESULT HTMLWindow_lookup_dispid(DispatchEx *dispex, const WCHAR *name, D return search_window_props(This, name, grfdex, dispid); }
+static const WCHAR *constructor_names[] = { +#define X(name) L ## #name, + ALL_PROTOTYPES +#undef X +}; + +static int CDECL cmp_name(const void *x, const void *y) +{ + return wcscmp(*(const WCHAR **)x, *(const WCHAR **)y); +} + static HRESULT HTMLWindow_find_dispid(DispatchEx *dispex, const WCHAR *name, DWORD grfdex, DISPID *dispid) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -3801,6 +3821,24 @@ static HRESULT HTMLWindow_find_dispid(DispatchEx *dispex, const WCHAR *name, DWO HTMLElement *elem; HRESULT hres;
+ if(dispex_compat_mode(dispex) >= COMPAT_MODE_IE9) { + const WCHAR **constr_name = bsearch(&name, constructor_names, ARRAYSIZE(constructor_names) , + sizeof(constructor_names[0]), cmp_name); + if(constr_name) { + prototype_id_t id = constr_name - constructor_names + 1; + DispatchEx *constr; + VARIANT v; + + hres = get_constructor(This, id, &constr); + if(FAILED(hres)) + return hres; + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch *)&constr->IWineJSDispatchHost_iface; + return dispex_define_property(&This->event_target.dispex, name, PROPF_WRITABLE | PROPF_CONFIGURABLE, &v, dispid); + } + } + hres = get_frame_by_name(This->base.outer_window, name, FALSE, &frame); if(SUCCEEDED(hres) && frame) { prop = alloc_global_prop(This, GLOBAL_FRAMEVAR, name); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index f07d56b19fa..207fcd7cafa 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -406,6 +406,17 @@ typedef struct { HRESULT (*populate_props)(DispatchEx*); } dispex_static_data_vtbl_t;
+#define ALL_PROTOTYPES \ + X(DOMImplementation) + +typedef enum { + PROT_NONE, +#define X(name) PROT_##name, + ALL_PROTOTYPES +#undef X + PROT_LAST, +} prototype_id_t; + typedef struct { const char *name; const dispex_static_data_vtbl_t *vtbl; @@ -518,8 +529,10 @@ HRESULT dispex_prop_put(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *v, EX HRESULT dispex_get_id(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID *pid); HRESULT dispex_next_id(DispatchEx *dispex, DISPID id, DISPID *ret); HRESULT dispex_prop_name(DispatchEx *dispex, DISPID id, BSTR *ret); +HRESULT dispex_define_property(DispatchEx *dispex, const WCHAR *name, DWORD flags, VARIANT *v, DISPID *id); HRESULT dispex_index_prop_desc(DispatchEx*,DISPID,struct property_info*); IWineJSDispatchHost *dispex_outer_iface(DispatchEx *dispex); +HRESULT get_constructor(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret);
typedef enum { DISPEXPROP_CUSTOM, @@ -682,6 +695,8 @@ struct HTMLInnerWindow { ULONG navigation_type; ULONG redirect_count;
+ DispatchEx *constructors[PROT_LAST]; + ULONGLONG navigation_start_time; ULONGLONG unload_event_start_time; ULONGLONG unload_event_end_time; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0b22861fb34..2aec564f77a 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2723,3 +2723,18 @@ sync_test("form_as_prop", function() { ok(!document.hasOwnProperty("testid"), 'document.hasOwnProperty("testid") = ' + document.hasOwnProperty("testid")); ok(!document.hasOwnProperty("testname"), 'document.hasOwnProperty("testname") = ' + document.hasOwnProperty("testname")); }); + +sync_test("prototypes", function() { + var constr = DOMImplementation; + test_own_data_prop_desc(window, "DOMImplementation", true, false, true); + ok(Object.getPrototypeOf(DOMImplementation) === Object.prototype, + "Object.getPrototypeOf(DOMImplementation) = " + Object.getPrototypeOf(DOMImplementation)); + todo_wine. + ok(DOMImplementation == "[object DOMImplementation]", "DOMImplementation = " + DOMImplementation); + + test_own_data_prop_desc(constr, "prototype", false, false, false); + + DOMImplementation = 1; + ok(DOMImplementation === 1, "DOMImplementation = " + DOMImplementation + " expected 1"); + DOMImplementation = constr; +});