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; +});
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 91 +++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 44 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index c4c1a5431b4..f74aacbfd8f 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -67,6 +67,7 @@ typedef struct { } func_info_t;
struct dispex_data_t { + const dispex_static_data_vtbl_t *vtbl; dispex_static_data_t *desc; compat_mode_t compat_mode;
@@ -506,6 +507,7 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ ERR("Out of memory\n"); return NULL; } + data->vtbl = desc->vtbl; data->desc = desc; data->compat_mode = compat_mode; data->func_cnt = 0; @@ -643,8 +645,8 @@ static inline dispex_dynamic_data_t *get_dynamic_data(DispatchEx *This) if(!This->dynamic_data) return NULL;
- if(This->info->desc->vtbl->populate_props) - This->info->desc->vtbl->populate_props(This); + if(This->info->vtbl->populate_props) + This->info->vtbl->populate_props(This);
return This->dynamic_data; } @@ -763,8 +765,8 @@ HRESULT dispex_get_dynid(DispatchEx *This, const WCHAR *name, BOOL hidden, DISPI
IWineJSDispatchHost *dispex_outer_iface(DispatchEx *dispex) { - if(dispex->info->desc->vtbl->get_outer_iface) - return dispex->info->desc->vtbl->get_outer_iface(dispex); + if(dispex->info->vtbl->get_outer_iface) + return dispex->info->vtbl->get_outer_iface(dispex);
IWineJSDispatchHost_AddRef(&dispex->IWineJSDispatchHost_iface); return &dispex->IWineJSDispatchHost_iface; @@ -775,8 +777,8 @@ static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS { HRESULT hres;
- if(This->info->desc->vtbl->value) - return This->info->desc->vtbl->value(This, lcid, flags, params, res, ei, caller); + if(This->info->vtbl->value) + return This->info->vtbl->value(This, lcid, flags, params, res, ei, caller);
switch(flags) { case DISPATCH_PROPERTYGET: @@ -1207,8 +1209,8 @@ static HRESULT get_builtin_id(DispatchEx *This, const WCHAR *name, DWORD grfdex, int min, max, n, c; HRESULT hres;
- if(This->info->desc->vtbl->lookup_dispid) { - hres = This->info->desc->vtbl->lookup_dispid(This, name, grfdex, ret); + if(This->info->vtbl->lookup_dispid) { + hres = This->info->vtbl->lookup_dispid(This, name, grfdex, ret); if(hres != DISP_E_UNKNOWNNAME) return hres; } @@ -1234,8 +1236,8 @@ static HRESULT get_builtin_id(DispatchEx *This, const WCHAR *name, DWORD grfdex, min = n+1; }
- if(This->info->desc->vtbl->get_dispid) { - hres = This->info->desc->vtbl->get_dispid(This, name, grfdex, ret); + if(This->info->vtbl->get_dispid) { + hres = This->info->vtbl->get_dispid(This, name, grfdex, ret); if(hres != DISP_E_UNKNOWNNAME) return hres; } @@ -1768,7 +1770,7 @@ static BOOL ensure_real_info(DispatchEx *dispex) if(dispex->info != dispex->info->desc->delayed_init_info) return TRUE;
- script_global = dispex->info->desc->vtbl->get_script_global(dispex); + script_global = dispex->info->vtbl->get_script_global(dispex); dispex->info = ensure_dispex_info(dispex, dispex->info->desc, script_global->doc->document_mode, script_global); return dispex->info != NULL; @@ -1792,8 +1794,8 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatchHost *iface, REFI
TRACE("%s (%p)->(%s %p)\n", This->info->desc->name, This, debugstr_mshtml_guid(riid), ppv);
- if(This->info->desc->vtbl->query_interface) { - *ppv = This->info->desc->vtbl->query_interface(This, riid); + if(This->info->vtbl->query_interface) { + *ppv = This->info->vtbl->query_interface(This, riid); if(*ppv) goto ret; } @@ -1845,9 +1847,9 @@ static ULONG WINAPI DispatchEx_Release(IWineJSDispatchHost *iface) /* Gecko ccref may not free the object immediately when ref count reaches 0, so we need * an extra care for objects that need an immediate clean up. See Gecko's * NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE for details. */ - if(!ref && This->info->desc->vtbl->last_release) { + if(!ref && This->info->vtbl->last_release) { ccref_incr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface); - This->info->desc->vtbl->last_release(This); + This->info->vtbl->last_release(This); ccref_decr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface, &dispex_ccp); }
@@ -1922,8 +1924,8 @@ HRESULT dispex_get_id(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID
hres = get_dynamic_prop(dispex, name, flags & ~fdexNameEnsure, &dprop); if(FAILED(hres)) { - if(dispex->info->desc->vtbl->find_dispid) { - hres = dispex->info->desc->vtbl->find_dispid(dispex, name, flags, pid); + if(dispex->info->vtbl->find_dispid) { + hres = dispex->info->vtbl->find_dispid(dispex, name, flags, pid); if(SUCCEEDED(hres)) return hres; } @@ -1958,9 +1960,9 @@ HRESULT dispex_prop_get(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *r, EX switch(get_dispid_type(id)) { case DISPEXPROP_CUSTOM: { DISPPARAMS dp = { .cArgs = 0 }; - if(!dispex->info->desc->vtbl->invoke) + if(!dispex->info->vtbl->invoke) return DISP_E_MEMBERNOTFOUND; - return dispex->info->desc->vtbl->invoke(dispex, id, lcid, DISPATCH_PROPERTYGET, &dp, r, ei, caller); + return dispex->info->vtbl->invoke(dispex, id, lcid, DISPATCH_PROPERTYGET, &dp, r, ei, caller); }
case DISPEXPROP_DYNAMIC: { @@ -1996,9 +1998,9 @@ HRESULT dispex_prop_put(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *v, EX switch(get_dispid_type(id)) { case DISPEXPROP_CUSTOM: { DISPPARAMS dp = { .cArgs = 1, .rgvarg = v, .cNamedArgs = 1, .rgdispidNamedArgs = &propput_dispid }; - if(!dispex->info->desc->vtbl->invoke) + if(!dispex->info->vtbl->invoke) return DISP_E_MEMBERNOTFOUND; - return dispex->info->desc->vtbl->invoke(dispex, id, lcid, DISPATCH_PROPERTYPUT, &dp, NULL, ei, caller); + return dispex->info->vtbl->invoke(dispex, id, lcid, DISPATCH_PROPERTYPUT, &dp, NULL, ei, caller); }
case DISPEXPROP_DYNAMIC: { @@ -2037,9 +2039,9 @@ static HRESULT dispex_prop_call(DispatchEx *dispex, DISPID id, LCID lcid, WORD f { switch(get_dispid_type(id)) { case DISPEXPROP_CUSTOM: - if(!dispex->info->desc->vtbl->invoke) + if(!dispex->info->vtbl->invoke) return DISP_E_MEMBERNOTFOUND; - return dispex->info->desc->vtbl->invoke(dispex, id, lcid, flags, dp, r, ei, caller); + return dispex->info->vtbl->invoke(dispex, id, lcid, flags, dp, r, ei, caller);
case DISPEXPROP_DYNAMIC: { DWORD idx = id - DISPID_DYNPROP_0; @@ -2070,8 +2072,8 @@ static HRESULT dispex_prop_call(DispatchEx *dispex, DISPID id, LCID lcid, WORD f case DISPEXPROP_BUILTIN: if(flags == DISPATCH_CONSTRUCT) { if(id == DISPID_VALUE) { - if(dispex->info->desc->vtbl->value) { - return dispex->info->desc->vtbl->value(dispex, lcid, flags, dp, r, ei, caller); + if(dispex->info->vtbl->value) { + return dispex->info->vtbl->value(dispex, lcid, flags, dp, r, ei, caller); } FIXME("DISPATCH_CONSTRUCT flag but missing value function\n"); return E_FAIL; @@ -2101,8 +2103,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatchHost *iface, DISPID id, if(wFlags == (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) wFlags = DISPATCH_PROPERTYPUT;
- if(This->info->desc->vtbl->disp_invoke) { - HRESULT hres = This->info->desc->vtbl->disp_invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + if(This->info->vtbl->disp_invoke) { + HRESULT hres = This->info->vtbl->disp_invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); if(hres != S_FALSE) return hres; } @@ -2132,8 +2134,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatchHost *iface, DISPID id,
static HRESULT dispex_prop_delete(DispatchEx *dispex, DISPID id) { - if(is_custom_dispid(id) && dispex->info->desc->vtbl->delete) - return dispex->info->desc->vtbl->delete(dispex, id); + if(is_custom_dispid(id) && dispex->info->vtbl->delete) + return dispex->info->vtbl->delete(dispex, id);
if(dispex_compat_mode(dispex) < COMPAT_MODE_IE8) { /* Not implemented by IE */ @@ -2168,7 +2170,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatchHost *iface, return E_OUTOFMEMORY; if(This->jsdisp) return IWineJSDispatch_DeleteMemberByName(This->jsdisp, name, grfdex); - if(dispex_compat_mode(This) < COMPAT_MODE_IE8 && !This->info->desc->vtbl->delete) + if(dispex_compat_mode(This) < COMPAT_MODE_IE8 && !This->info->vtbl->delete) return E_NOTIMPL;
hres = IWineJSDispatchHost_GetDispID(&This->IWineJSDispatchHost_iface, name, grfdex & ~fdexNameEnsure, &id); @@ -2211,10 +2213,10 @@ HRESULT dispex_prop_name(DispatchEx *dispex, DISPID id, BSTR *ret) struct property_info desc; WCHAR buf[12];
- if(!dispex->info->desc->vtbl->get_prop_desc) + if(!dispex->info->vtbl->get_prop_desc) return DISP_E_MEMBERNOTFOUND;
- hres = dispex->info->desc->vtbl->get_prop_desc(dispex, id, &desc); + hres = dispex->info->vtbl->get_prop_desc(dispex, id, &desc); if(FAILED(hres)) return hres; if(!desc.name) { @@ -2306,8 +2308,8 @@ HRESULT dispex_next_id(DispatchEx *dispex, DISPID id, DISPID *ret) id = DISPID_STARTENUM; }
- if(dispex->info->desc->vtbl->next_dispid) { - hres = dispex->info->desc->vtbl->next_dispid(dispex, id, ret); + if(dispex->info->vtbl->next_dispid) { + hres = dispex->info->vtbl->next_dispid(dispex, id, ret); if(hres != S_FALSE) return hres; } @@ -2354,7 +2356,7 @@ HRESULT dispex_index_prop_desc(DispatchEx *dispex, DISPID id, struct property_in { desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; - if(dispex->info->desc->vtbl->next_dispid) + if(dispex->info->vtbl->next_dispid) desc->flags |= PROPF_ENUMERABLE; desc->name = NULL; desc->index = id - MSHTML_DISPID_CUSTOM_MIN; @@ -2393,7 +2395,7 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct break; } case DISPEXPROP_CUSTOM: - return This->info->desc->vtbl->get_prop_desc(This, id, desc); + return This->info->vtbl->get_prop_desc(This, id, desc); }
return S_OK; @@ -2543,8 +2545,8 @@ static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTrave
describe_cc_node(&This->ccref, This->info->desc->name, cb);
- if(This->info->desc->vtbl->traverse) - This->info->desc->vtbl->traverse(This, cb); + if(This->info->vtbl->traverse) + This->info->vtbl->traverse(This, cb);
if(!This->dynamic_data) return NS_OK; @@ -2598,8 +2600,8 @@ static nsresult NSAPI dispex_unlink(void *p) { DispatchEx *This = impl_from_IWineJSDispatchHost(p);
- if(This->info->desc->vtbl->unlink) - This->info->desc->vtbl->unlink(This); + if(This->info->vtbl->unlink) + This->info->vtbl->unlink(This);
dispex_props_unlink(This); return NS_OK; @@ -2611,8 +2613,8 @@ static void NSAPI dispex_delete_cycle_collectable(void *p) IWineJSDispatch *jsdisp = This->jsdisp; dynamic_prop_t *prop;
- if(This->info->desc->vtbl->unlink) - This->info->desc->vtbl->unlink(This); + if(This->info->vtbl->unlink) + This->info->vtbl->unlink(This);
if(!This->dynamic_data) goto destructor; @@ -2641,7 +2643,7 @@ static void NSAPI dispex_delete_cycle_collectable(void *p) free(This->dynamic_data);
destructor: - This->info->desc->vtbl->destructor(This); + This->info->vtbl->destructor(This); if(jsdisp) IWineJSDispatch_Free(jsdisp); } @@ -2658,7 +2660,7 @@ void init_dispex_cc(void)
const void *dispex_get_vtbl(DispatchEx *dispex) { - return dispex->info->desc->vtbl; + return dispex->info->vtbl; }
void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWindow *script_global, compat_mode_t compat_mode) @@ -2677,6 +2679,7 @@ void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWind if(!data->delayed_init_info) { dispex_data_t *info = calloc(1, sizeof(*data->delayed_init_info)); if(info) { + info->vtbl = data->vtbl; info->desc = data; data->delayed_init_info = info; }
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index f74aacbfd8f..3fdff6f9750 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1735,11 +1735,8 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) return *ret ? S_OK : E_OUTOFMEMORY; }
-static dispex_data_t *ensure_dispex_info(DispatchEx *dispex, dispex_static_data_t *desc, - compat_mode_t compat_mode, HTMLInnerWindow *script_global) +static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode_t compat_mode) { - HRESULT hres; - if(!desc->info_cache[compat_mode]) { EnterCriticalSection(&cs_dispex_static_data); if(!desc->info_cache[compat_mode]) @@ -1749,20 +1746,26 @@ static dispex_data_t *ensure_dispex_info(DispatchEx *dispex, dispex_static_data_ return NULL; }
- if(compat_mode >= COMPAT_MODE_IE9 && script_global) { - if(!script_global->jscript) - initialize_script_global(script_global); - if(script_global->jscript && !dispex->jsdisp) { - hres = IWineJScript_InitHostObject(script_global->jscript, &dispex->IWineJSDispatchHost_iface, - &dispex->jsdisp); - if(FAILED(hres)) - ERR("Failed to initialize jsdisp: %08lx\n", hres); - } - } - return desc->info_cache[compat_mode]; }
+static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global) +{ + HRESULT hres; + + if(dispex->info->compat_mode < COMPAT_MODE_IE9 || !script_global) + return; + + if(!script_global->jscript) + initialize_script_global(script_global); + if(script_global->jscript && !dispex->jsdisp) { + hres = IWineJScript_InitHostObject(script_global->jscript, &dispex->IWineJSDispatchHost_iface, + &dispex->jsdisp); + if(FAILED(hres)) + ERR("Failed to initialize jsdisp: %08lx\n", hres); + } +} + static BOOL ensure_real_info(DispatchEx *dispex) { HTMLInnerWindow *script_global; @@ -1771,9 +1774,10 @@ static BOOL ensure_real_info(DispatchEx *dispex) return TRUE;
script_global = dispex->info->vtbl->get_script_global(dispex); - dispex->info = ensure_dispex_info(dispex, dispex->info->desc, - script_global->doc->document_mode, script_global); - return dispex->info != NULL; + if (!(dispex->info = ensure_dispex_info(dispex->info->desc, script_global->doc->document_mode))) + return FALSE; + init_host_object(dispex, script_global); + return TRUE; }
compat_mode_t dispex_compat_mode(DispatchEx *dispex) @@ -2688,7 +2692,8 @@ void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWind } dispex->info = data->delayed_init_info; }else { - dispex->info = ensure_dispex_info(dispex, data, compat_mode, script_global); + dispex->info = ensure_dispex_info(data, compat_mode); + init_host_object(dispex, script_global); } }
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 3fdff6f9750..2ee0bea7986 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2667,14 +2667,22 @@ const void *dispex_get_vtbl(DispatchEx *dispex) return dispex->info->vtbl; }
-void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWindow *script_global, compat_mode_t compat_mode) +static void init_dispatch_from_desc(DispatchEx *dispex, dispex_data_t *info, HTMLInnerWindow *script_global) { - assert(compat_mode < COMPAT_MODE_CNT); - dispex->IWineJSDispatchHost_iface.lpVtbl = &JSDispatchHostVtbl; dispex->dynamic_data = NULL; dispex->jsdisp = NULL; + dispex->info = info; ccref_init(&dispex->ccref, 1); + if(info != info->desc->delayed_init_info) + init_host_object(dispex, script_global); +} + +void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWindow *script_global, compat_mode_t compat_mode) +{ + dispex_data_t *info; + + assert(compat_mode < COMPAT_MODE_CNT);
if(data->vtbl->get_script_global) { /* delayed init */ @@ -2690,11 +2698,12 @@ void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWind } LeaveCriticalSection(&cs_dispex_static_data); } - dispex->info = data->delayed_init_info; + info = data->delayed_init_info; }else { - dispex->info = ensure_dispex_info(data, compat_mode); - init_host_object(dispex, script_global); + info = ensure_dispex_info(data, compat_mode); } + + init_dispatch_from_desc(dispex, info, script_global); }
void init_dispatch_with_owner(DispatchEx *dispex, dispex_static_data_t *desc, DispatchEx *owner)
From: Jacek Caban jacek@codeweavers.com
--- dlls/jscript/dispex.c | 10 ++- dlls/jscript/jscript.c | 4 +- dlls/jscript/jscript.h | 2 +- dlls/jscript/jsdisp.idl | 2 +- dlls/mshtml/dispex.c | 128 ++++++++++++++++++++++++++++++++--- dlls/mshtml/htmlwindow.c | 6 ++ dlls/mshtml/mshtml_private.h | 9 +++ dlls/mshtml/omnavigator.c | 17 ++--- dlls/mshtml/script.c | 1 + dlls/mshtml/tests/es5.js | 17 +++++ 10 files changed, 172 insertions(+), 24 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 95954866345..eec8bf7c1e9 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -3495,15 +3495,21 @@ static const builtin_info_t HostObject_info = { .to_string = HostObject_to_string, };
-HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWineJSDispatch **ret) +HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWineJSDispatch *prototype_iface, + IWineJSDispatch **ret) { HostObject *host_obj; + jsdisp_t *prototype; HRESULT hres;
if(!(host_obj = calloc(1, sizeof(*host_obj)))) return E_OUTOFMEMORY;
- hres = init_dispex(&host_obj->jsdisp, ctx, &HostObject_info, ctx->object_prototype); + if(prototype_iface) + prototype = impl_from_IWineJSDispatch(prototype_iface); + else + prototype = ctx->object_prototype; + hres = init_dispex(&host_obj->jsdisp, ctx, &HostObject_info, prototype); if(FAILED(hres)) { free(host_obj); return hres; diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 4d53e8a6832..fac025366e9 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -1452,10 +1452,10 @@ static ULONG WINAPI WineJScript_Release(IWineJScript *iface) }
static HRESULT WINAPI WineJScript_InitHostObject(IWineJScript *iface, IWineJSDispatchHost *host_obj, - IWineJSDispatch **ret) + IWineJSDispatch *prototype, IWineJSDispatch **ret) { JScript *This = impl_from_IWineJScript(iface); - return init_host_object(This->ctx, host_obj, ret); + return init_host_object(This->ctx, host_obj, prototype, ret); }
static const IWineJScriptVtbl WineJScriptVtbl = { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 48738ca82f4..3691ca562f8 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -242,7 +242,7 @@ enum jsdisp_enum_type { HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**); HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); -HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch**); +HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**);
HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 518edabba9d..35419178e97 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -75,5 +75,5 @@ interface IWineJSDispatchHost : IDispatchEx ] interface IWineJScript : IUnknown { - HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch **ret); + HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, IWineJSDispatch **ret); } diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 2ee0bea7986..2d61848a296 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -45,6 +45,8 @@ static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg = }; static CRITICAL_SECTION cs_dispex_static_data = { &cs_dispex_static_data_dbg, -1, 0, 0, 0, 0 };
+static HRESULT get_prototype(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret); + typedef struct { IID iid; VARIANT default_value; @@ -1749,7 +1751,7 @@ static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode return desc->info_cache[compat_mode]; }
-static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global) +static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global, DispatchEx *prototype) { HRESULT hres;
@@ -1760,7 +1762,7 @@ static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global) initialize_script_global(script_global); if(script_global->jscript && !dispex->jsdisp) { hres = IWineJScript_InitHostObject(script_global->jscript, &dispex->IWineJSDispatchHost_iface, - &dispex->jsdisp); + prototype ? prototype->jsdisp : NULL, &dispex->jsdisp); if(FAILED(hres)) ERR("Failed to initialize jsdisp: %08lx\n", hres); } @@ -1769,14 +1771,24 @@ static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global) static BOOL ensure_real_info(DispatchEx *dispex) { HTMLInnerWindow *script_global; + DispatchEx *prototype = NULL;
if(dispex->info != dispex->info->desc->delayed_init_info) return TRUE;
script_global = dispex->info->vtbl->get_script_global(dispex); + + if(dispex->info->compat_mode >= COMPAT_MODE_IE9 && dispex->info->desc->id) { + HRESULT hres = get_prototype(script_global, dispex->info->desc->id, &prototype); + if(FAILED(hres)) { + ERR("could not get prototype: %08lx\n", hres); + return FALSE; + } + } + if (!(dispex->info = ensure_dispex_info(dispex->info->desc, script_global->doc->document_mode))) return FALSE; - init_host_object(dispex, script_global); + init_host_object(dispex, script_global, prototype); return TRUE; }
@@ -2667,7 +2679,7 @@ const void *dispex_get_vtbl(DispatchEx *dispex) return dispex->info->vtbl; }
-static void init_dispatch_from_desc(DispatchEx *dispex, dispex_data_t *info, HTMLInnerWindow *script_global) +static void init_dispatch_from_desc(DispatchEx *dispex, dispex_data_t *info, HTMLInnerWindow *script_global, DispatchEx *prototype) { dispex->IWineJSDispatchHost_iface.lpVtbl = &JSDispatchHostVtbl; dispex->dynamic_data = NULL; @@ -2675,11 +2687,12 @@ static void init_dispatch_from_desc(DispatchEx *dispex, dispex_data_t *info, HTM dispex->info = info; ccref_init(&dispex->ccref, 1); if(info != info->desc->delayed_init_info) - init_host_object(dispex, script_global); + init_host_object(dispex, script_global, prototype); }
void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWindow *script_global, compat_mode_t compat_mode) { + DispatchEx *prototype = NULL; dispex_data_t *info;
assert(compat_mode < COMPAT_MODE_CNT); @@ -2700,10 +2713,16 @@ void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, HTMLInnerWind } info = data->delayed_init_info; }else { + if(compat_mode >= COMPAT_MODE_IE9 && data->id) { + HRESULT hres = get_prototype(script_global, data->id, &prototype); + if(FAILED(hres)) + ERR("could not get prototype: %08lx\n", hres); + } + info = ensure_dispex_info(data, compat_mode); }
- init_dispatch_from_desc(dispex, info, script_global); + init_dispatch_from_desc(dispex, info, script_global, prototype); }
void init_dispatch_with_owner(DispatchEx *dispex, dispex_static_data_t *desc, DispatchEx *owner) @@ -2714,6 +2733,83 @@ void init_dispatch_with_owner(DispatchEx *dispex, dispex_static_data_t *desc, Di IHTMLWindow2_Release(&script_global->base.IHTMLWindow2_iface); }
+dispex_static_data_t *object_descriptors[] = { + NULL, +#define X(name) &name ## _dispex, + ALL_PROTOTYPES +#undef X +}; + +static void prototype_destructor(DispatchEx *dispex) +{ + free(dispex); +} + +static HRESULT prototype_find_dispid(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID *dispid) +{ + HTMLInnerWindow *script_global; + DispatchEx *constructor; + HRESULT hres; + + if(wcscmp(name, L"constructor")) + return DISP_E_UNKNOWNNAME; + + script_global = get_script_global(dispex); + if(!script_global) + return DISP_E_UNKNOWNNAME; + + hres = get_constructor(script_global, dispex->info->desc->id, &constructor); + if(SUCCEEDED(hres)) { + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch *)&constructor->IWineJSDispatchHost_iface; + hres = dispex_define_property(dispex, L"constructor", PROPF_WRITABLE | PROPF_CONFIGURABLE, &v, dispid); + } + IHTMLWindow2_Release(&script_global->base.IHTMLWindow2_iface); + return hres; +} + +static const dispex_static_data_vtbl_t prototype_dispex_vtbl = { + .destructor = prototype_destructor, + .find_dispid = prototype_find_dispid, +}; + +static HRESULT get_prototype(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret) +{ + compat_mode_t compat_mode = dispex_compat_mode(&script_global->event_target.dispex); + dispex_static_data_t *desc; + DispatchEx *prototype; + dispex_data_t *info; + + if(script_global->prototypes[id]) { + *ret = script_global->prototypes[id]; + return S_OK; + } + + desc = object_descriptors[id]; + info = desc->prototype_info[compat_mode - COMPAT_MODE_IE9]; + if(!info) { + EnterCriticalSection(&cs_dispex_static_data); + info = desc->prototype_info[compat_mode - COMPAT_MODE_IE9]; + if(!info) { + info = preprocess_dispex_data(desc, compat_mode); + if(info) { + info->vtbl = &prototype_dispex_vtbl; + desc->prototype_info[compat_mode - COMPAT_MODE_IE9] = info; + } + } + LeaveCriticalSection(&cs_dispex_static_data); + if(!info) + return E_OUTOFMEMORY; + } + + if(!(prototype = calloc(sizeof(*prototype), 1))) + return E_OUTOFMEMORY; + init_dispatch_from_desc(prototype, info, script_global, NULL); + *ret = script_global->prototypes[id] = prototype; + return S_OK; +} + struct constructor { DispatchEx dispex; @@ -2734,14 +2830,26 @@ static void constructor_destructor(DispatchEx *dispex) static HRESULT constructor_find_dispid(DispatchEx *dispex, const WCHAR *name, DWORD flags, DISPID *dispid) { struct constructor *constr = constr_from_DispatchEx(dispex); - VARIANT v; + HTMLInnerWindow *script_global; + DispatchEx *prototype; + HRESULT hres;
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); + script_global = get_script_global(&constr->dispex); + if(!script_global) + return DISP_E_UNKNOWNNAME; + + hres = get_prototype(script_global, constr->id, &prototype); + if(SUCCEEDED(hres)) { + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch *)&prototype->IWineJSDispatchHost_iface; + hres = dispex_define_property(&constr->dispex, name, 0, &v, dispid); + } + IHTMLWindow2_Release(&script_global->base.IHTMLWindow2_iface); + return hres; }
static const dispex_static_data_vtbl_t constructor_dispex_vtbl = { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index ac427ded3ba..3569b9caad1 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3683,6 +3683,10 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa 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->prototypes); i++) { + if(This->prototypes[i]) + note_cc_edge((nsISupports*)&This->prototypes[i]->IWineJSDispatchHost_iface, "prototypes", cb); + } for(i = 0; i < ARRAYSIZE(This->constructors); i++) { if(This->constructors[i]) note_cc_edge((nsISupports*)&This->constructors[i]->IWineJSDispatchHost_iface, "constructors", cb); @@ -3724,6 +3728,8 @@ static void HTMLWindow_unlink(DispatchEx *dispex) unlink_ref(&This->console); detach_inner_window(This);
+ for(i = 0; i < ARRAYSIZE(This->prototypes); i++) + unlink_ref(&This->prototypes[i]); for(i = 0; i < ARRAYSIZE(This->constructors); i++) unlink_ref(&This->constructors[i]);
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 207fcd7cafa..eb00a7b3629 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -424,9 +424,17 @@ typedef struct { const tid_t* const iface_tids; void (*init_info)(dispex_data_t*,compat_mode_t); dispex_data_t *info_cache[COMPAT_MODE_CNT]; + dispex_data_t *prototype_info[COMPAT_MODE_CNT - COMPAT_MODE_IE9]; dispex_data_t *delayed_init_info; + prototype_id_t id; } dispex_static_data_t;
+#define X(name) extern dispex_static_data_t name ## _dispex; +ALL_PROTOTYPES +#undef X + +extern dispex_static_data_t *object_descriptors[PROT_LAST]; + typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,WORD,DISPPARAMS*,VARIANT*, EXCEPINFO*,IServiceProvider*);
@@ -695,6 +703,7 @@ struct HTMLInnerWindow { ULONG navigation_type; ULONG redirect_count;
+ DispatchEx *prototypes[PROT_LAST]; DispatchEx *constructors[PROT_LAST];
ULONGLONG navigation_start_time; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 900c4ee0ca7..93a48309e2e 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -202,7 +202,7 @@ static void HTMLDOMImplementation_destructor(DispatchEx *dispex) free(This); }
-static const dispex_static_data_vtbl_t HTMLDOMImplementation_dispex_vtbl = { +static const dispex_static_data_vtbl_t DOMImplementation_dispex_vtbl = { .query_interface = HTMLDOMImplementation_query_interface, .destructor = HTMLDOMImplementation_destructor, .traverse = HTMLDOMImplementation_traverse, @@ -219,12 +219,13 @@ static const tid_t HTMLDOMImplementation_iface_tids[] = { IHTMLDOMImplementation_tid, 0 }; -static dispex_static_data_t HTMLDOMImplementation_dispex = { - "DOMImplementation", - &HTMLDOMImplementation_dispex_vtbl, - DispHTMLDOMImplementation_tid, - HTMLDOMImplementation_iface_tids, - HTMLDOMImplementation_init_dispex_info +dispex_static_data_t DOMImplementation_dispex = { + .name = "DOMImplementation", + .id = PROT_DOMImplementation, + .vtbl = &DOMImplementation_dispex_vtbl, + .disp_tid = DispHTMLDOMImplementation_tid, + .iface_tids = HTMLDOMImplementation_iface_tids, + .init_info = HTMLDOMImplementation_init_dispex_info, };
HRESULT create_dom_implementation(HTMLDocumentNode *doc_node, IHTMLDOMImplementation **ret) @@ -243,7 +244,7 @@ HRESULT create_dom_implementation(HTMLDocumentNode *doc_node, IHTMLDOMImplementa dom_implementation->IHTMLDOMImplementation2_iface.lpVtbl = &HTMLDOMImplementation2Vtbl; dom_implementation->doc = doc_node;
- init_dispatch(&dom_implementation->dispex, &HTMLDOMImplementation_dispex, doc_node->script_global, doc_node->document_mode); + init_dispatch(&dom_implementation->dispex, &DOMImplementation_dispex, doc_node->script_global, doc_node->document_mode);
nsres = nsIDOMDocument_GetImplementation(doc_node->dom_document, &dom_implementation->implementation); if(NS_FAILED(nsres)) { diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index e985912c526..2b6abe6d8e2 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -209,6 +209,7 @@ static BOOL init_script_engine(ScriptHost *script_host, IActiveScript *script)
hres = IWineJScript_InitHostObject(jscript, &script_host->window->event_target.dispex.IWineJSDispatchHost_iface, + NULL, &script_host->window->event_target.dispex.jsdisp); if(FAILED(hres)) ERR("Could not initialize script global: %08lx\n", hres); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 2aec564f77a..294b9fed490 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2732,7 +2732,24 @@ sync_test("prototypes", function() { todo_wine. ok(DOMImplementation == "[object DOMImplementation]", "DOMImplementation = " + DOMImplementation);
+ var proto = constr.prototype; + todo_wine. + ok(proto == "[object DOMImplementationPrototype]", "DOMImplementation.prototype = " + proto); + ok(Object.getPrototypeOf(document.implementation) === proto, + "Object.getPrototypeOf(document.implementation) = " + Object.getPrototypeOf(document.implementation)); + ok(Object.getPrototypeOf(proto) === Object.prototype, "Object.getPrototypeOf(proto) = " + Object.getPrototypeOf(proto)); + test_own_data_prop_desc(constr, "prototype", false, false, false); + test_own_data_prop_desc(proto, "constructor", true, false, true); + ok(proto.hasOwnProperty("createHTMLDocument"), "prototype has no own createHTMLDocument property"); + todo_wine. + ok(!document.implementation.hasOwnProperty("createHTMLDocument"), + "prototype has own createHTMLDocument property"); + + ok(proto.constructor === constr, "proto.constructor = " + proto.constructor); + proto.constructor = 1; + ok(proto.constructor === 1, "proto.constructor = " + proto.constructor + " expected 1"); + proto.constructor = constr;
DOMImplementation = 1; ok(DOMImplementation === 1, "DOMImplementation = " + DOMImplementation + " expected 1");
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 39 ++++++++++++++++++++++++++++++++------- dlls/mshtml/tests/es5.js | 1 - 2 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 2d61848a296..45d1920e7eb 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -72,10 +72,12 @@ struct dispex_data_t { const dispex_static_data_vtbl_t *vtbl; dispex_static_data_t *desc; compat_mode_t compat_mode; + BOOL is_prototype;
DWORD func_cnt; DWORD func_size; func_info_t *funcs; + DWORD name_cnt; func_info_t **name_table; DWORD func_disp_cnt;
@@ -279,6 +281,10 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, BSTR name; HRESULT hres;
+ /* FIXME: Expose non-function properties from prototypes too (requires support for accessor properties). */ + if(data->is_prototype && !(desc->invkind & DISPATCH_METHOD)) + return; + if(name_override) name = SysAllocString(name_override); else if(desc->wFuncFlags & FUNCFLAG_FRESTRICTED) @@ -488,7 +494,20 @@ static int __cdecl func_name_cmp(const void *p1, const void *p2) return wcsicmp((*(func_info_t* const*)p1)->name, (*(func_info_t* const*)p2)->name); }
-static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_mode_t compat_mode) +static BOOL find_prototype_member(const dispex_data_t *info, DISPID id) +{ + compat_mode_t compat_mode = info->compat_mode; + + if(compat_mode < COMPAT_MODE_IE9) + return FALSE; + if(!(info = info->desc->prototype_info[compat_mode - COMPAT_MODE_IE9])) + return FALSE; + if(bsearch(&id, info->funcs, info->func_cnt, sizeof(info->funcs[0]), dispid_cmp)) + return TRUE; + return FALSE; +} + +static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_mode_t compat_mode, BOOL is_prototype) { const tid_t *tid; dispex_data_t *data; @@ -512,9 +531,11 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ data->vtbl = desc->vtbl; data->desc = desc; data->compat_mode = compat_mode; + data->is_prototype = is_prototype; data->func_cnt = 0; data->func_disp_cnt = 0; data->func_size = 16; + data->name_cnt = 0; data->funcs = calloc(data->func_size, sizeof(func_info_t)); if (!data->funcs) { free(data); @@ -547,9 +568,13 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp);
data->name_table = malloc(data->func_cnt * sizeof(func_info_t*)); - for(i=0; i < data->func_cnt; i++) - data->name_table[i] = data->funcs+i; - qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp); + for(i=0; i < data->func_cnt; i++) { + /* Don't expose properties that are exposed by object's prototype */ + if(find_prototype_member(data, data->funcs[i].id)) + continue; + data->name_table[data->name_cnt++] = data->funcs+i; + } + qsort(data->name_table, data->name_cnt, sizeof(func_info_t*), func_name_cmp); return data; }
@@ -1218,7 +1243,7 @@ static HRESULT get_builtin_id(DispatchEx *This, const WCHAR *name, DWORD grfdex, }
min = 0; - max = This->info->func_cnt-1; + max = This->info->name_cnt-1;
while(min <= max) { n = (min+max)/2; @@ -1742,7 +1767,7 @@ static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode if(!desc->info_cache[compat_mode]) { EnterCriticalSection(&cs_dispex_static_data); if(!desc->info_cache[compat_mode]) - desc->info_cache[compat_mode] = preprocess_dispex_data(desc, compat_mode); + desc->info_cache[compat_mode] = preprocess_dispex_data(desc, compat_mode, FALSE); LeaveCriticalSection(&cs_dispex_static_data); if(!desc->info_cache[compat_mode]) return NULL; @@ -2792,7 +2817,7 @@ static HRESULT get_prototype(HTMLInnerWindow *script_global, prototype_id_t id, EnterCriticalSection(&cs_dispex_static_data); info = desc->prototype_info[compat_mode - COMPAT_MODE_IE9]; if(!info) { - info = preprocess_dispex_data(desc, compat_mode); + info = preprocess_dispex_data(desc, compat_mode, TRUE); if(info) { info->vtbl = &prototype_dispex_vtbl; desc->prototype_info[compat_mode - COMPAT_MODE_IE9] = info; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 294b9fed490..62e8f8e9c0f 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2742,7 +2742,6 @@ sync_test("prototypes", function() { test_own_data_prop_desc(constr, "prototype", false, false, false); test_own_data_prop_desc(proto, "constructor", true, false, true); ok(proto.hasOwnProperty("createHTMLDocument"), "prototype has no own createHTMLDocument property"); - todo_wine. ok(!document.implementation.hasOwnProperty("createHTMLDocument"), "prototype has own createHTMLDocument property");
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 54 +++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 26 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 45d1920e7eb..a6214aa666d 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -73,6 +73,7 @@ struct dispex_data_t { dispex_static_data_t *desc; compat_mode_t compat_mode; BOOL is_prototype; + const char *name;
DWORD func_cnt; DWORD func_size; @@ -529,6 +530,7 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_ return NULL; } data->vtbl = desc->vtbl; + data->name = desc->name; data->desc = desc; data->compat_mode = compat_mode; data->is_prototype = is_prototype; @@ -1742,7 +1744,7 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) static const WCHAR suffix[] = L"]"; WCHAR buf[ARRAY_SIZE(prefix) + 28 + ARRAY_SIZE(suffix)], *p = buf; compat_mode_t compat_mode = dispex_compat_mode(dispex); - const char *name = dispex->info->desc->name; + const char *name = dispex->info->name;
if(!ret) return E_INVALIDARG; @@ -1833,7 +1835,7 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatchHost *iface, REFI { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%s %p)\n", This->info->desc->name, This, debugstr_mshtml_guid(riid), ppv); + TRACE("%s (%p)->(%s %p)\n", This->info->name, This, debugstr_mshtml_guid(riid), ppv);
if(This->info->vtbl->query_interface) { *ppv = This->info->vtbl->query_interface(This, riid); @@ -1859,7 +1861,7 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatchHost *iface, REFI return E_NOINTERFACE; }else { *ppv = NULL; - WARN("%s (%p)->(%s %p)\n", This->info->desc->name, This, debugstr_mshtml_guid(riid), ppv); + WARN("%s (%p)->(%s %p)\n", This->info->name, This, debugstr_mshtml_guid(riid), ppv); return E_NOINTERFACE; }
@@ -1873,7 +1875,7 @@ static ULONG WINAPI DispatchEx_AddRef(IWineJSDispatchHost *iface) DispatchEx *This = impl_from_IWineJSDispatchHost(iface); LONG ref = ccref_incr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface);
- TRACE("%s (%p) ref=%ld\n", This->info->desc->name, This, ref); + TRACE("%s (%p) ref=%ld\n", This->info->name, This, ref);
return ref; } @@ -1883,7 +1885,7 @@ static ULONG WINAPI DispatchEx_Release(IWineJSDispatchHost *iface) DispatchEx *This = impl_from_IWineJSDispatchHost(iface); LONG ref = ccref_decr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface, &dispex_ccp);
- TRACE("%s (%p) ref=%ld\n", This->info->desc->name, This, ref); + TRACE("%s (%p) ref=%ld\n", This->info->name, This, ref);
/* Gecko ccref may not free the object immediately when ref count reaches 0, so we need * an extra care for objects that need an immediate clean up. See Gecko's @@ -1901,7 +1903,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IWineJSDispatchHost *iface, UI { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%p)\n", This->info->desc->name, This, pctinfo); + TRACE("%s (%p)->(%p)\n", This->info->name, This, pctinfo);
*pctinfo = 1; return S_OK; @@ -1913,7 +1915,7 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IWineJSDispatchHost *iface, UINT iT DispatchEx *This = impl_from_IWineJSDispatchHost(iface); HRESULT hres;
- TRACE("%s (%p)->(%u %lu %p)\n", This->info->desc->name, This, iTInfo, lcid, ppTInfo); + TRACE("%s (%p)->(%u %lu %p)\n", This->info->name, This, iTInfo, lcid, ppTInfo);
hres = get_typeinfo(This->info->desc->disp_tid, ppTInfo); if(FAILED(hres)) @@ -1930,7 +1932,7 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IWineJSDispatchHost *iface, REFII DispatchEx *This = impl_from_IWineJSDispatchHost(iface); HRESULT hres = S_OK;
- TRACE("%s (%p)->(%s %p %u %lu %p)\n", This->info->desc->name, This, debugstr_guid(riid), rgszNames, + TRACE("%s (%p)->(%s %p %u %lu %p)\n", This->info->name, This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
/* Native ignores all cNames > 1, and doesn't even fill them */ @@ -1947,7 +1949,7 @@ static HRESULT WINAPI DispatchEx_Invoke(IWineJSDispatchHost *iface, DISPID dispI { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%ld %s %ld %d %p %p %p %p)\n", This->info->desc->name, This, dispIdMember, + TRACE("%s (%p)->(%ld %s %ld %d %p %p %p %p)\n", This->info->name, This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
return IWineJSDispatchHost_InvokeEx(&This->IWineJSDispatchHost_iface, dispIdMember, lcid, wFlags, pDispParams, @@ -1984,7 +1986,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IWineJSDispatchHost *iface, BSTR bstr { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%s %lx %p)\n", This->info->desc->name, This, debugstr_w(bstrName), grfdex, pid); + TRACE("%s (%p)->(%s %lx %p)\n", This->info->name, This, debugstr_w(bstrName), grfdex, pid);
if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) FIXME("Unsupported grfdex %lx\n", grfdex); @@ -2136,7 +2138,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatchHost *iface, DISPID id, { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx %lx %x %p %p %p %p)\n", This->info->desc->name, This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + TRACE("%s (%p)->(%lx %lx %x %p %p %p %p)\n", This->info->name, This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
if(!ensure_real_info(This)) return E_OUTOFMEMORY; @@ -2205,7 +2207,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatchHost *iface, DISPID id; HRESULT hres;
- TRACE("%s (%p)->(%s %lx)\n", This->info->desc->name, This, debugstr_w(name), grfdex); + TRACE("%s (%p)->(%s %lx)\n", This->info->name, This, debugstr_w(name), grfdex);
if(!ensure_real_info(This)) return E_OUTOFMEMORY; @@ -2229,7 +2231,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatchHost *iface { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id); + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id);
if(!ensure_real_info(This)) return E_OUTOFMEMORY; @@ -2241,7 +2243,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatchHost *iface static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatchHost *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); - FIXME("%s (%p)->(%lx %lx %p)\n", This->info->desc->name, This, id, grfdexFetch, pgrfdex); + FIXME("%s (%p)->(%lx %lx %p)\n", This->info->name, This, id, grfdexFetch, pgrfdex); return E_NOTIMPL; }
@@ -2290,7 +2292,7 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IWineJSDispatchHost *iface, DISPI { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx %p)\n", This->info->desc->name, This, id, pbstrName); + TRACE("%s (%p)->(%lx %p)\n", This->info->name, This, id, pbstrName);
if(!ensure_real_info(This)) return E_OUTOFMEMORY; @@ -2366,7 +2368,7 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IWineJSDispatchHost *iface, DWORD { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx %lx %p)\n", This->info->desc->name, This, grfdex, id, pid); + TRACE("%s (%p)->(%lx %lx %p)\n", This->info->name, This, grfdex, id, pid);
if(!ensure_real_info(This)) return E_OUTOFMEMORY; @@ -2378,7 +2380,7 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IWineJSDispatchHost *iface, DWORD static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IWineJSDispatchHost *iface, IUnknown **ppunk) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); - FIXME("%s (%p)->(%p)\n", This->info->desc->name, This, ppunk); + FIXME("%s (%p)->(%p)\n", This->info->name, This, ppunk); return E_NOTIMPL; }
@@ -2449,7 +2451,7 @@ static HRESULT WINAPI JSDispatchHost_LookupProperty(IWineJSDispatchHost *iface, DISPID id; HRESULT hres;
- TRACE("%s (%p)->(%s)\n", This->info->desc->name, This, debugstr_w(name)); + TRACE("%s (%p)->(%s)\n", This->info->name, This, debugstr_w(name));
hres = dispex_get_id(This, name, flags, &id); if(FAILED(hres)) @@ -2464,7 +2466,7 @@ static HRESULT WINAPI JSDispatchHost_NextProperty(IWineJSDispatchHost *iface, DI DISPID next; HRESULT hres;
- TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id); + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id);
hres = dispex_next_id(This, id, &next); if(hres != S_OK) @@ -2478,7 +2480,7 @@ static HRESULT WINAPI JSDispatchHost_GetProperty(IWineJSDispatchHost *iface, DIS { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id); + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id);
return dispex_prop_get(This, id, lcid, r, ei, caller); } @@ -2488,7 +2490,7 @@ static HRESULT WINAPI JSDispatchHost_SetProperty(IWineJSDispatchHost *iface, DIS { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id); + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id);
return dispex_prop_put(This, id, lcid, v, ei, caller); } @@ -2497,7 +2499,7 @@ static HRESULT WINAPI JSDispatchHost_DeleteProperty(IWineJSDispatchHost *iface, { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id); + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id);
return dispex_prop_delete(This, id); } @@ -2506,7 +2508,7 @@ static HRESULT WINAPI JSDispatchHost_ConfigureProperty(IWineJSDispatchHost *ifac { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)->(%lx %x)\n", This->info->desc->name, This, id, flags); + TRACE("%s (%p)->(%lx %x)\n", This->info->name, This, id, flags);
if(is_dynamic_dispid(id)) { DWORD idx = id - DISPID_DYNPROP_0; @@ -2526,7 +2528,7 @@ static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DI func_info_t *func; HRESULT hres;
- TRACE("%s (%p)->(%lx %x %p %p %p %p)\n", This->info->desc->name, This, id, iid, dp, ret, ei, caller); + TRACE("%s (%p)->(%lx %x %p %p %p %p)\n", This->info->name, This, id, iid, dp, ret, ei, caller);
hres = get_builtin_func(This->info, id, &func); if(FAILED(hres) || func->tid != iid || func->func_disp_idx < 0) @@ -2546,7 +2548,7 @@ static HRESULT WINAPI JSDispatchHost_ToString(IWineJSDispatchHost *iface, BSTR * { DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
- TRACE("%s (%p)\n", This->info->desc->name, This); + TRACE("%s (%p)\n", This->info->name, This);
return dispex_to_string(This, str); } @@ -2584,7 +2586,7 @@ static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTrave DispatchEx *This = impl_from_IWineJSDispatchHost(p); dynamic_prop_t *prop;
- describe_cc_node(&This->ccref, This->info->desc->name, cb); + describe_cc_node(&This->ccref, This->info->name, cb);
if(This->info->vtbl->traverse) This->info->vtbl->traverse(This, cb);
From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/dispex.c | 4 ++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/es5.js | 1 - 3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index a6214aa666d..1cbb3388f87 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2821,7 +2821,10 @@ static HRESULT get_prototype(HTMLInnerWindow *script_global, prototype_id_t id, if(!info) { info = preprocess_dispex_data(desc, compat_mode, TRUE); if(info) { + if(!desc->prototype_name[0]) + sprintf(desc->prototype_name, "%sPrototype", desc->name); info->vtbl = &prototype_dispex_vtbl; + info->name = desc->prototype_name; desc->prototype_info[compat_mode - COMPAT_MODE_IE9] = info; } } @@ -2908,4 +2911,5 @@ HRESULT get_constructor(HTMLInnerWindow *script_global, prototype_id_t id, Dispa constr->id = id; *ret = script_global->constructors[id] = &constr->dispex; return S_OK; + } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index eb00a7b3629..4f6b0bb11c0 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -427,6 +427,7 @@ typedef struct { dispex_data_t *prototype_info[COMPAT_MODE_CNT - COMPAT_MODE_IE9]; dispex_data_t *delayed_init_info; prototype_id_t id; + char prototype_name[64]; } dispex_static_data_t;
#define X(name) extern dispex_static_data_t name ## _dispex; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 62e8f8e9c0f..880b59a85ff 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2733,7 +2733,6 @@ sync_test("prototypes", function() { ok(DOMImplementation == "[object DOMImplementation]", "DOMImplementation = " + DOMImplementation);
var proto = constr.prototype; - todo_wine. ok(proto == "[object DOMImplementationPrototype]", "DOMImplementation.prototype = " + proto); ok(Object.getPrototypeOf(document.implementation) === proto, "Object.getPrototypeOf(document.implementation) = " + Object.getPrototypeOf(document.implementation));
From: Jacek Caban jacek@codeweavers.com
--- dlls/jscript/dispex.c | 5 ++++- dlls/jscript/engine.c | 2 +- dlls/jscript/jscript.c | 4 ++-- dlls/jscript/jscript.h | 3 ++- dlls/jscript/jsdisp.idl | 4 +++- dlls/mshtml/dispex.c | 8 +++++--- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/script.c | 3 +-- dlls/mshtml/tests/es5.js | 2 ++ 9 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index eec8bf7c1e9..a99f09776e2 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2413,6 +2413,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b dispex->ref = 1; dispex->builtin_info = builtin_info; dispex->extensible = TRUE; + dispex->is_constructor = builtin_info->class == JSCLASS_FUNCTION; dispex->prop_cnt = 0;
dispex->props = calloc(1, sizeof(dispex_prop_t)*(dispex->buf_size=4)); @@ -3496,7 +3497,7 @@ static const builtin_info_t HostObject_info = { };
HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWineJSDispatch *prototype_iface, - IWineJSDispatch **ret) + UINT32 flags, IWineJSDispatch **ret) { HostObject *host_obj; jsdisp_t *prototype; @@ -3516,6 +3517,8 @@ HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWi }
host_obj->host_iface = host_iface; + if(flags & HOSTOBJ_CONSTRUCTOR) + host_obj->jsdisp.is_constructor = TRUE; *ret = &host_obj->jsdisp.IWineJSDispatch_iface; return S_OK; } diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 12e53435f16..ca662ae99ff 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -2027,7 +2027,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) return E_FAIL; }
- if(is_class(obj, JSCLASS_FUNCTION)) { + if(obj->is_constructor) { hres = jsdisp_propget_name(obj, L"prototype", &prot); }else { hres = JS_E_FUNCTION_EXPECTED; diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index fac025366e9..5822cf1222f 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -1452,10 +1452,10 @@ static ULONG WINAPI WineJScript_Release(IWineJScript *iface) }
static HRESULT WINAPI WineJScript_InitHostObject(IWineJScript *iface, IWineJSDispatchHost *host_obj, - IWineJSDispatch *prototype, IWineJSDispatch **ret) + IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret) { JScript *This = impl_from_IWineJScript(iface); - return init_host_object(This->ctx, host_obj, prototype, ret); + return init_host_object(This->ctx, host_obj, prototype, flags, ret); }
static const IWineJScriptVtbl WineJScriptVtbl = { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 3691ca562f8..5e3640b69b7 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -204,6 +204,7 @@ struct jsdisp_t { BOOLEAN has_weak_refs; BOOLEAN extensible; BOOLEAN gc_marked; + BOOLEAN is_constructor;
DWORD buf_size; DWORD prop_cnt; @@ -242,7 +243,7 @@ enum jsdisp_enum_type { HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**); HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); -HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**); +HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,UINT32,IWineJSDispatch**);
HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 35419178e97..a1b63579fce 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -36,6 +36,8 @@ const unsigned int PROPF_CONFIGURABLE = 0x1000;
const unsigned int PROPF_PUBLIC_MASK = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE;
+const unsigned int HOSTOBJ_CONSTRUCTOR = 0x0001; + interface IWineJSDispatchHost;
[ @@ -75,5 +77,5 @@ interface IWineJSDispatchHost : IDispatchEx ] interface IWineJScript : IUnknown { - HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, IWineJSDispatch **ret); + HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret); } diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 1cbb3388f87..1848fef01f2 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1789,7 +1789,8 @@ static void init_host_object(DispatchEx *dispex, HTMLInnerWindow *script_global, initialize_script_global(script_global); if(script_global->jscript && !dispex->jsdisp) { hres = IWineJScript_InitHostObject(script_global->jscript, &dispex->IWineJSDispatchHost_iface, - prototype ? prototype->jsdisp : NULL, &dispex->jsdisp); + prototype ? prototype->jsdisp : NULL, + dispex->info->desc->js_flags, &dispex->jsdisp); if(FAILED(hres)) ERR("Failed to initialize jsdisp: %08lx\n", hres); } @@ -2888,8 +2889,9 @@ static const dispex_static_data_vtbl_t constructor_dispex_vtbl = { };
static dispex_static_data_t constructor_dispex = { - .name = "Constructor", - .vtbl = &constructor_dispex_vtbl, + .name = "Constructor", + .vtbl = &constructor_dispex_vtbl, + .js_flags = HOSTOBJ_CONSTRUCTOR, };
HRESULT get_constructor(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4f6b0bb11c0..ca8629b64ef 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -427,6 +427,7 @@ typedef struct { dispex_data_t *prototype_info[COMPAT_MODE_CNT - COMPAT_MODE_IE9]; dispex_data_t *delayed_init_info; prototype_id_t id; + UINT32 js_flags; char prototype_name[64]; } dispex_static_data_t;
diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 2b6abe6d8e2..30571c15fff 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -209,8 +209,7 @@ static BOOL init_script_engine(ScriptHost *script_host, IActiveScript *script)
hres = IWineJScript_InitHostObject(jscript, &script_host->window->event_target.dispex.IWineJSDispatchHost_iface, - NULL, - &script_host->window->event_target.dispex.jsdisp); + NULL, 0, &script_host->window->event_target.dispex.jsdisp); if(FAILED(hres)) ERR("Could not initialize script global: %08lx\n", hres);
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 880b59a85ff..78b50a40ec6 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2752,4 +2752,6 @@ sync_test("prototypes", function() { DOMImplementation = 1; ok(DOMImplementation === 1, "DOMImplementation = " + DOMImplementation + " expected 1"); DOMImplementation = constr; + + ok(document.implementation instanceof DOMImplementation, "document.implementation is not an instance of DOMImplementation"); });
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147512
Your paranoid android.
=== w7u_el (32 bit report) ===
mshtml: script.c:1223: Test failed: L"/index.html?dom.js:document_lastModified: lastModified too far from navigationStart: 1575"
=== debian11b (64 bit WoW report) ===
dinput: joystick8.c:5759: Test failed: input 1: WaitForSingleObject returned 0x102 joystick8.c:5760: Test failed: input 1: got 0 WM_INPUT messages joystick8.c:5763: Test failed: input 1: got dwType 0 joystick8.c:5764: Test failed: input 1: got header.dwSize 0 joystick8.c:5766: Test failed: input 1: got hDevice 0000000000000000 joystick8.c:5768: Test failed: input 1: got dwSizeHid 0 joystick8.c:5769: Test failed: input 1: got dwCount 0