-- v3: mshtml: Move Option constructor to the window rather than the prototype. mshtml: Move Image constructor to the window rather than the prototype. mshtml: Validate builtin host functions in IE9+ using prototype_id rather mshtml: Store the prototype_id of the last member that contains the needed
From: Gabriel Ivăncescu gabrielopcode@gmail.com
And use it instead of on_prototype boolean.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 77eec049912..1dc98698e7d 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -55,7 +55,7 @@ typedef struct { tid_t tid; BSTR name; dispex_hook_invoke_t hook; - BOOLEAN on_prototype; + prototype_id_t prototype_id; SHORT call_vtbl_off; SHORT put_vtbl_off; SHORT get_vtbl_off; @@ -517,31 +517,32 @@ 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 BOOL find_prototype_member(const dispex_data_t *info, DISPID id) +static prototype_id_t find_prototype_member(const dispex_data_t *info, DISPID id) { compat_mode_t compat_mode = info->compat_mode; + prototype_id_t ret = PROT_NONE;
if(compat_mode < COMPAT_MODE_IE9) - return FALSE; + return ret;
if(!info->is_prototype) { if(!info->desc->id) - return FALSE; + return ret; info = info->desc->prototype_info[compat_mode - COMPAT_MODE_IE9]; }else { if(!info->desc->prototype_id) - return FALSE; + return ret; info = object_descriptors[info->desc->prototype_id]->prototype_info[compat_mode - COMPAT_MODE_IE9]; }
for(;;) { if(bsearch(&id, info->funcs, info->func_cnt, sizeof(info->funcs[0]), dispid_cmp)) - return TRUE; + ret = info->desc->id; if(!info->desc->prototype_id) break; info = object_descriptors[info->desc->prototype_id]->prototype_info[compat_mode - COMPAT_MODE_IE9]; } - return FALSE; + return ret; }
static const char *object_names[] = { @@ -616,11 +617,11 @@ static dispex_data_t *preprocess_dispex_data(dispex_static_data_t *desc, compat_
data->name_table = malloc(data->func_cnt * sizeof(func_info_t*)); for(i=0; i < data->func_cnt; i++) { + data->funcs[i].prototype_id = find_prototype_member(data, data->funcs[i].id); + /* Don't expose properties that are exposed by object's prototype */ - if(find_prototype_member(data, data->funcs[i].id)) { - data->funcs[i].on_prototype = TRUE; + if(data->funcs[i].prototype_id != PROT_NONE) continue; - } data->name_table[data->name_cnt++] = data->funcs+i; } qsort(data->name_table, data->name_cnt, sizeof(func_info_t*), func_name_cmp); @@ -2511,7 +2512,7 @@ HRESULT dispex_next_id(DispatchEx *dispex, DISPID id, BOOL enum_all_own_props, D }
while(func < dispex->info->funcs + dispex->info->func_cnt) { - if(enum_all_own_props ? (!func->on_prototype) : (func->func_disp_idx == -1)) { + if(enum_all_own_props ? (func->prototype_id == PROT_NONE) : (func->func_disp_idx == -1)) { *ret = func->id; return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 2 +- dlls/jscript/jsdisp.idl | 4 ++-- dlls/mshtml/dispex.c | 21 ++++++++++++++------- dlls/mshtml/htmlwindow.c | 4 ++-- dlls/mshtml/tests/documentmode.js | 14 ++++++++++++++ 5 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 9f1f53a96ae..4fd49368ad9 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -67,7 +67,7 @@ typedef struct { FunctionInstance function; const WCHAR *name; UINT32 id; - UINT32 iid; + INT32 iid; UINT32 flags; } HostFunction;
diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 5f1384bce78..cfd1beba55d 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -27,7 +27,7 @@ struct property_info UINT32 flags; const WCHAR *name; UINT32 index; - UINT32 iid; + INT32 iid; };
const unsigned int PROPF_METHOD = 0x0100; @@ -69,7 +69,7 @@ interface IWineJSDispatchHost : IDispatchEx HRESULT SetProperty(DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller); HRESULT DeleteProperty(DISPID id); HRESULT ConfigureProperty(DISPID id, UINT32 flags); - HRESULT CallFunction(DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT CallFunction(DISPID id, INT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); HRESULT Construct(LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); HRESULT GetOuterDispatch(IWineJSDispatchHost **ret); HRESULT ToString(BSTR *str); diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 1dc98698e7d..95cddfd9c17 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1076,7 +1076,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI } }
- hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, -func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller);
fail: while(argc--) @@ -1103,7 +1103,7 @@ static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIA if(FAILED(hres)) return CTL_E_ILLEGALFUNCTIONCALL;
- hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, -func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); IWineJSDispatchHost_Release(this_iface); return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; } @@ -2594,13 +2594,13 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct desc->flags = PROPF_CONFIGURABLE; desc->name = func->name; if(func->func_disp_idx >= 0) { - desc->iid = func->tid; + desc->iid = This->info->desc->id; desc->flags |= PROPF_METHOD | PROPF_WRITABLE; }else { if(func->func_disp_idx == -1) desc->flags |= PROPF_ENUMERABLE; if(This->info->is_prototype) { - desc->iid = func->tid; + desc->iid = This->info->desc->id; if(func->put_vtbl_off) desc->flags |= PROPF_WRITABLE; }else { @@ -2701,19 +2701,26 @@ static HRESULT WINAPI JSDispatchHost_ConfigureProperty(IWineJSDispatchHost *ifac return S_OK; }
-static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, +static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, INT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); func_info_t *func; HRESULT hres;
- TRACE("%s (%p)->(%lx %x %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller); + TRACE("%s (%p)->(%lx %d %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller);
hres = get_builtin_func(This->info, id, &func); - if(FAILED(hres) || func->tid != iid) + if(FAILED(hres)) return E_UNEXPECTED;
+ if(iid <= 0) { + if(func->tid != -iid) + return E_UNEXPECTED; + }else if(iid != func->prototype_id) { + return E_UNEXPECTED; + } + switch(flags) { case DISPATCH_METHOD: assert(func->func_disp_idx >= 0); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index ffcaf86a361..c7e45439545 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3491,8 +3491,8 @@ static HRESULT WINAPI WindowDispEx_ConfigureProperty(IWineJSDispatchHost *iface, return IWineJSDispatchHost_ConfigureProperty(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, flags); }
-static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, - VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, INT32 iid, DWORD flags, + DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5bbd8b098f6..d304fbadd62 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -3131,6 +3131,13 @@ sync_test("__proto__", function() { ok(e.number === 0xa13b6 - 0x80000000 && e.name === "TypeError", "changing __proto__ on non-extensible object threw exception " + e.number + " (" + e.name + ")"); } + + obj = document.createElement("img"); + obj.__proto__ = ctor.prototype; + document.body.setAttribute.call(obj, "height", "101"); + r = document.body.getAttribute.call(obj, "height"); + ok(r === "101", "getAttribute(height) = " + r); + ok(!("getAttribute" in obj), "getAttribute exposed in obj"); });
sync_test("__defineGetter__", function() { @@ -3750,6 +3757,13 @@ sync_test("prototypes", function() { check(Attr.prototype, Node.prototype, "attr prototype"); check(document.createDocumentFragment(), DocumentFragment.prototype, "fragment"); check(DocumentFragment.prototype, Node.prototype, "fragment prototype"); + + try { + HTMLAreaElement.prototype.toString.call(document.createElement("a")); + ok(false, "Area element's toString on Anchor element didn't fail"); + } catch(e) { + ok(e.number == 0xffff - 0x80000000, "Area element's toString on Anchor element threw exception " + e.number); + } });
sync_test("prototype props", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 1 + dlls/mshtml/htmlimg.c | 17 ++++++----- dlls/mshtml/htmlwindow.c | 51 +++++++++++++++---------------- dlls/mshtml/mshtml_private.h | 18 ++++++++--- dlls/mshtml/tests/documentmode.js | 16 ++++++++++ 5 files changed, 65 insertions(+), 38 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 95cddfd9c17..858242d3878 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2978,6 +2978,7 @@ dispex_static_data_t *object_descriptors[] = { NULL, #define X(name) &name ## _dispex, ALL_PROTOTYPES + ALL_ALT_CTORS #undef X };
diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index f6a4b992ab6..5973e134064 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -877,15 +877,16 @@ static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { .value = HTMLImageElementFactory_value, };
-static dispex_static_data_t HTMLImageElementFactory_dispex = { - .name = "Function", - .constructor_id = PROT_HTMLImageElement, - .vtbl = &HTMLImageElementFactory_dispex_vtbl, - .disp_tid = IHTMLImageElementFactory_tid, - .iface_tids = HTMLImageElementFactory_iface_tids, +dispex_static_data_t HTMLImageElementFactory_dispex = { + .name = "Function", + .constructor_id = PROT_HTMLImageElement, + .init_constructor = HTMLImageElementFactory_Create, + .vtbl = &HTMLImageElementFactory_dispex_vtbl, + .disp_tid = IHTMLImageElementFactory_tid, + .iface_tids = HTMLImageElementFactory_iface_tids, };
-HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElementFactory **ret_val) +HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, DispatchEx **ret_val) { HTMLImageElementFactory *ret;
@@ -900,6 +901,6 @@ HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElement init_dispatch(&ret->dispex, &HTMLImageElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex));
- *ret_val = ret; + *ret_val = &ret->dispex; return S_OK; } diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c7e45439545..29c2a6e8e64 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -676,18 +676,14 @@ static HRESULT WINAPI HTMLWindow2_get_Image(IHTMLWindow2 *iface, IHTMLImageEleme
TRACE("(%p)->(%p)\n", This, p);
- if(!window->image_factory) { - HRESULT hres; - - hres = HTMLImageElementFactory_Create(window, &window->image_factory); + if(!window->constructors[CTOR_HTMLImageElementFactory]) { + HRESULT hres = HTMLImageElementFactory_Create(window, &window->constructors[CTOR_HTMLImageElementFactory]); if(FAILED(hres)) return hres; }
- *p = &window->image_factory->IHTMLImageElementFactory_iface; - IHTMLImageElementFactory_AddRef(*p); - - return S_OK; + return IWineJSDispatchHost_QueryInterface(&window->constructors[CTOR_HTMLImageElementFactory]->IWineJSDispatchHost_iface, + &IID_IHTMLImageElementFactory, (void**)p); }
static HRESULT WINAPI HTMLWindow2_get_location(IHTMLWindow2 *iface, IHTMLLocation **p) @@ -3700,8 +3696,6 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); if(This->console) note_cc_edge((nsISupports*)This->console, "console", cb); - if(This->image_factory) - note_cc_edge((nsISupports*)&This->image_factory->IHTMLImageElementFactory_iface, "image_factory", cb); if(This->option_factory) note_cc_edge((nsISupports*)&This->option_factory->IHTMLOptionElementFactory_iface, "option_factory", cb); if(This->screen) @@ -3742,11 +3736,6 @@ static void HTMLWindow_unlink(DispatchEx *dispex)
release_event_target(&This->event_target);
- if(This->image_factory) { - HTMLImageElementFactory *image_factory = This->image_factory; - This->image_factory = NULL; - IHTMLImageElementFactory_Release(&image_factory->IHTMLImageElementFactory_iface); - } if(This->option_factory) { HTMLOptionElementFactory *option_factory = This->option_factory; This->option_factory = NULL; @@ -3818,18 +3807,24 @@ static int CDECL cmp_name(const void *x, const void *y)
static HRESULT HTMLWindow_find_dispid(DispatchEx *dispex, const WCHAR *name, DWORD grfdex, DISPID *dispid) { + compat_mode_t compat_mode = dispex_compat_mode(dispex); HTMLInnerWindow *This = impl_from_DispatchEx(dispex); HTMLOuterWindow *frame; global_prop_t *prop; HTMLElement *elem; HRESULT hres;
- if(dispex_compat_mode(dispex) >= COMPAT_MODE_IE9) { + if(compat_mode >= 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; - compat_mode_t compat_mode = dispex_compat_mode(dispex); + prototype_id_t id = 0; + + if(constr_name) + id = constr_name - constructor_names + 1; + else if(!wcscmp(name, L"Image")) + id = CTOR_HTMLImageElementFactory; + + if(id) { DispatchEx *constr; VARIANT v;
@@ -4188,15 +4183,18 @@ static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DIS
static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { - static const dispex_hook_t window2_hooks[] = { - {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, - {DISPID_UNKNOWN} - }; static const dispex_hook_t window2_ie11_hooks[] = { - {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, - {DISPID_IHTMLWINDOW2_EXECSCRIPT, NULL}, + {DISPID_IHTMLWINDOW2_EXECSCRIPT}, + + /* IE9+ */ + {DISPID_IHTMLWINDOW2_IMAGE}, + + /* Common for all modes */ + {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const window2_ie9_hooks = window2_ie11_hooks + 1; + const dispex_hook_t *const window2_hooks = window2_ie9_hooks + 1; static const dispex_hook_t window3_hooks[] = { {DISPID_IHTMLWINDOW3_SETTIMEOUT, IHTMLWindow3_setTimeout_hook}, {DISPID_UNKNOWN} @@ -4228,7 +4226,8 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks); - dispex_info_add_interface(info, IHTMLWindow2_tid, compat_mode >= COMPAT_MODE_IE11 ? window2_ie11_hooks : window2_hooks); + dispex_info_add_interface(info, IHTMLWindow2_tid, compat_mode >= COMPAT_MODE_IE11 ? window2_ie11_hooks : + compat_mode >= COMPAT_MODE_IE9 ? window2_ie9_hooks : window2_hooks); EventTarget_init_dispex_info(info, compat_mode); }
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index f306cff68c6..58dad8a68e0 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -504,12 +504,22 @@ typedef struct { X(Window) \ X(XMLHttpRequest)
+/* Extra constructors without new prototypes */ +#define ALL_ALT_CTORS \ + X(HTMLImageElementFactory) + typedef enum { PROT_NONE, #define X(name) PROT_##name, ALL_PROTOTYPES #undef X PROT_LAST, + + PROT_LAST_ = PROT_LAST - 1, /* align alt ctors enum */ +#define X(name) CTOR_##name, + ALL_ALT_CTORS +#undef X + CTOR_LAST } prototype_id_t;
struct dispex_static_data_t { @@ -533,9 +543,10 @@ struct dispex_static_data_t {
#define X(name) extern dispex_static_data_t name ## _dispex; ALL_PROTOTYPES +ALL_ALT_CTORS #undef X
-extern dispex_static_data_t *object_descriptors[PROT_LAST]; +extern dispex_static_data_t *object_descriptors[CTOR_LAST];
typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,WORD,DISPPARAMS*,VARIANT*, EXCEPINFO*,IServiceProvider*); @@ -771,7 +782,6 @@ struct HTMLInnerWindow {
IHTMLEventObj *event;
- HTMLImageElementFactory *image_factory; HTMLOptionElementFactory *option_factory; IHTMLScreen *screen; OmHistory *history; @@ -801,7 +811,7 @@ struct HTMLInnerWindow { ULONG redirect_count;
DispatchEx *prototypes[PROT_LAST]; - DispatchEx *constructors[PROT_LAST]; + DispatchEx *constructors[CTOR_LAST];
ULONGLONG navigation_start_time; ULONGLONG unload_event_start_time; @@ -1170,7 +1180,7 @@ HRESULT update_window_doc(HTMLInnerWindow*); HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*); void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**); HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**); -HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**); +HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT create_location(HTMLOuterWindow*,HTMLLocation**); HRESULT create_navigator(HTMLInnerWindow*,IOmNavigator**); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d304fbadd62..e9a2f0172d0 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -3995,3 +3995,19 @@ sync_test("prototype props", function() { check(Text, [ "removeNode", "replaceNode", "replaceWholeText", "splitText", "swapNode", "wholeText" ], [ "replaceWholeText", "wholeText" ]); check(UIEvent, [ "detail", "initUIEvent", "view" ], null, [ "deviceSessionId" ]); }); + +sync_test("constructors", function() { + var v = document.documentMode, i, r; + if(v < 9) + return; + + var ctors = [ "Image", "MutationObserver", "XMLHttpRequest" ]; + for(i = 0; i < ctors.length; i++) { + r = ctors[i]; + if(!(r in window)) + continue; + ok(window.hasOwnProperty(r), r + " not prop of window"); + ok(!Object.getPrototypeOf(window).hasOwnProperty(r), r + " is a prop of window's prototype"); + } + ok(window.Image.prototype === window.HTMLImageElement.prototype, "Image.prototype != HTMLImageElement.prototype"); +});
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlselect.c | 17 +++++++++-------- dlls/mshtml/htmlwindow.c | 24 ++++++++---------------- dlls/mshtml/mshtml_private.h | 6 +++--- dlls/mshtml/tests/documentmode.js | 3 ++- 4 files changed, 22 insertions(+), 28 deletions(-)
diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 2d02589db38..9bfe0afb45c 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -523,15 +523,16 @@ static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { .value = HTMLOptionElementFactory_value, };
-static dispex_static_data_t HTMLOptionElementFactory_dispex = { - .name = "Function", - .constructor_id = PROT_HTMLOptionElement, - .vtbl = &HTMLOptionElementFactory_dispex_vtbl, - .disp_tid = IHTMLOptionElementFactory_tid, - .iface_tids = HTMLOptionElementFactory_iface_tids, +dispex_static_data_t HTMLOptionElementFactory_dispex = { + .name = "Function", + .constructor_id = PROT_HTMLOptionElement, + .init_constructor = HTMLOptionElementFactory_Create, + .vtbl = &HTMLOptionElementFactory_dispex_vtbl, + .disp_tid = IHTMLOptionElementFactory_tid, + .iface_tids = HTMLOptionElementFactory_iface_tids, };
-HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionElementFactory **ret_ptr) +HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, DispatchEx **ret_ptr) { HTMLOptionElementFactory *ret;
@@ -546,7 +547,7 @@ HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionEleme init_dispatch(&ret->dispex, &HTMLOptionElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex));
- *ret_ptr = ret; + *ret_ptr = &ret->dispex; return S_OK; }
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 29c2a6e8e64..79d16b715de 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -1230,18 +1230,14 @@ static HRESULT WINAPI HTMLWindow2_get_Option(IHTMLWindow2 *iface, IHTMLOptionEle
TRACE("(%p)->(%p)\n", This, p);
- if(!window->option_factory) { - HRESULT hres; - - hres = HTMLOptionElementFactory_Create(window, &window->option_factory); + if(!window->constructors[CTOR_HTMLOptionElementFactory]) { + HRESULT hres = HTMLOptionElementFactory_Create(window, &window->constructors[CTOR_HTMLOptionElementFactory]); if(FAILED(hres)) return hres; }
- *p = &window->option_factory->IHTMLOptionElementFactory_iface; - IHTMLOptionElementFactory_AddRef(*p); - - return S_OK; + return IWineJSDispatchHost_QueryInterface(&window->constructors[CTOR_HTMLOptionElementFactory]->IWineJSDispatchHost_iface, + &IID_IHTMLOptionElementFactory, (void**)p); }
static HRESULT WINAPI HTMLWindow2_focus(IHTMLWindow2 *iface) @@ -3696,8 +3692,6 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); if(This->console) note_cc_edge((nsISupports*)This->console, "console", cb); - if(This->option_factory) - note_cc_edge((nsISupports*)&This->option_factory->IHTMLOptionElementFactory_iface, "option_factory", cb); if(This->screen) note_cc_edge((nsISupports*)This->screen, "screen", cb); if(This->history) @@ -3736,11 +3730,6 @@ static void HTMLWindow_unlink(DispatchEx *dispex)
release_event_target(&This->event_target);
- if(This->option_factory) { - HTMLOptionElementFactory *option_factory = This->option_factory; - This->option_factory = NULL; - IHTMLOptionElementFactory_Release(&option_factory->IHTMLOptionElementFactory_iface); - } unlink_ref(&This->screen); if(This->history) { OmHistory *history = This->history; @@ -3823,6 +3812,8 @@ static HRESULT HTMLWindow_find_dispid(DispatchEx *dispex, const WCHAR *name, DWO id = constr_name - constructor_names + 1; else if(!wcscmp(name, L"Image")) id = CTOR_HTMLImageElementFactory; + else if(!wcscmp(name, L"Option")) + id = CTOR_HTMLOptionElementFactory;
if(id) { DispatchEx *constr; @@ -4188,13 +4179,14 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa
/* IE9+ */ {DISPID_IHTMLWINDOW2_IMAGE}, + {DISPID_IHTMLWINDOW2_OPTION},
/* Common for all modes */ {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, {DISPID_UNKNOWN} }; const dispex_hook_t *const window2_ie9_hooks = window2_ie11_hooks + 1; - const dispex_hook_t *const window2_hooks = window2_ie9_hooks + 1; + const dispex_hook_t *const window2_hooks = window2_ie9_hooks + 2; static const dispex_hook_t window3_hooks[] = { {DISPID_IHTMLWINDOW3_SETTIMEOUT, IHTMLWindow3_setTimeout_hook}, {DISPID_UNKNOWN} diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 58dad8a68e0..5575a07ff4f 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -506,7 +506,8 @@ typedef struct {
/* Extra constructors without new prototypes */ #define ALL_ALT_CTORS \ - X(HTMLImageElementFactory) + X(HTMLImageElementFactory) \ + X(HTMLOptionElementFactory)
typedef enum { PROT_NONE, @@ -782,7 +783,6 @@ struct HTMLInnerWindow {
IHTMLEventObj *event;
- HTMLOptionElementFactory *option_factory; IHTMLScreen *screen; OmHistory *history; IOmNavigator *navigator; @@ -1179,7 +1179,7 @@ HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,H HRESULT update_window_doc(HTMLInnerWindow*); HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*); void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**); -HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**); +HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT create_location(HTMLOuterWindow*,HTMLLocation**); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index e9a2f0172d0..7b0152a6ecd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -4001,7 +4001,7 @@ sync_test("constructors", function() { if(v < 9) return;
- var ctors = [ "Image", "MutationObserver", "XMLHttpRequest" ]; + var ctors = [ "Image", "MutationObserver", "Option", "XMLHttpRequest" ]; for(i = 0; i < ctors.length; i++) { r = ctors[i]; if(!(r in window)) @@ -4010,4 +4010,5 @@ sync_test("constructors", function() { ok(!Object.getPrototypeOf(window).hasOwnProperty(r), r + " is a prop of window's prototype"); } ok(window.Image.prototype === window.HTMLImageElement.prototype, "Image.prototype != HTMLImageElement.prototype"); + ok(window.Option.prototype === window.HTMLOptionElement.prototype, "Option.prototype != HTMLOptionElement.prototype"); });
Jacek Caban (@jacek) commented about dlls/mshtml/dispex.c:
HRESULT hres;
- TRACE("%s (%p)->(%lx %x %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller);
TRACE("%s (%p)->(%lx %d %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller);
hres = get_builtin_func(This->info, id, &func);
- if(FAILED(hres) || func->tid != iid)
if(FAILED(hres)) return E_UNEXPECTED;
if(iid <= 0) {
if(func->tid != -iid)
return E_UNEXPECTED;
}else if(iid != func->prototype_id) {
return E_UNEXPECTED;
}
We still have builtin properties that are not in prototypes in builtin MSHTML constructors. AFAIR, we shouldn't expose most of them in IE9+ mode, but some of them should remain. This would probably break them, please add a test.
Jacek Caban (@jacek) commented about dlls/mshtml/htmlwindow.c:
TRACE("(%p)->(%p)\n", This, p);
- if(!window->image_factory) {
HRESULT hres;
hres = HTMLImageElementFactory_Create(window, &window->image_factory);
- if(!window->constructors[CTOR_HTMLImageElementFactory]) {
}HRESULT hres = HTMLImageElementFactory_Create(window, &window->constructors[CTOR_HTMLImageElementFactory]); if(FAILED(hres)) return hres;
Can we just use `get_constructor` here?
On Mon Apr 14 08:32:31 2025 +0000, Jacek Caban wrote:
We still have builtin properties that are not in prototypes in builtin MSHTML constructors. AFAIR, we shouldn't expose most of them in IE9+ mode, but some of them should remain. This would probably break them, please add a test.
Sorry, probably having a dumb moment, which props do you have in mind to test to affect this code? Since accessors/methods are placed on the prototype. (I can add a check for the object's id regardless, not a big deal, I'm just having trouble coming up with a test)
On Mon Apr 14 15:03:59 2025 +0000, Gabriel Ivăncescu wrote:
Sorry, probably having a dumb moment, which props do you have in mind to test to affect this code? Since accessors/methods are placed on the prototype. (I can add a check for the object's id regardless, not a big deal, I'm just having trouble coming up with a test)
`XMLHttpRequest.create` is an own property of the constructor, not its prototype (which is `Function.prototype`).
On Mon Apr 14 15:27:43 2025 +0000, Jacek Caban wrote:
`XMLHttpRequest.create` is an own property of the constructor, not its prototype (which is `Function.prototype`).
BTW, I noticed you have patches removing most of the similar properties. It might be easier to land those first before changing the validation itself.
On Mon Apr 14 15:48:49 2025 +0000, Jacek Caban wrote:
BTW, I noticed you have patches removing most of the similar properties. It might be easier to land those first before changing the validation itself.
Yeah, but "create" is still available for XHR so it won't really help, now I'm getting a crash trying to test it (probably existing bug).
On Mon Apr 14 15:53:25 2025 +0000, Gabriel Ivăncescu wrote:
Yeah, but "create" is still available for XHR so it won't really help, now I'm getting a crash trying to test it (probably existing bug).
Sure, but is it the only property like that? If so, we might want to stop using the generic code for its lookup and treat it as a "custom" prop instead. That would allow the generic logic to assume all functions it handles come from prototypes. We might need to introduce some mechanism for "custom" iids anyway, since that could also be required for indexed property accessors. (Not saying this is necessarily the best approach, but it’s an example where knowing the scope could influence the decision.)
On Mon Apr 14 16:29:34 2025 +0000, Jacek Caban wrote:
Sure, but is it the only property like that? If so, we might want to stop using the generic code for its lookup and treat it as a "custom" prop instead. That would allow the generic logic to assume all functions it handles come from prototypes. We might need to introduce some mechanism for "custom" iids anyway, since that could also be required for indexed property accessors. (Not saying this is necessarily the best approach, but it’s an example where knowing the scope could influence the decision.)
Good point and I'm inclined to go that route, but there's one problem right now. XMLHttpRequest is an actual jscript function (which is fine because it matches the tests), but `create` is an external prop. This leads to the crash since a jscript function doesn't have `prop_get` method (HostObject_prop_get rather). Custom prop isn't going to solve this unfortunately.
IMO I think simplest way is to just make `create` a normal jscript prop in this case, especially since it's an exception to the rule. Is that fine?
On Mon Apr 14 18:14:34 2025 +0000, Gabriel Ivăncescu wrote:
Good point and I'm inclined to go that route, but there's one problem right now. XMLHttpRequest is an actual jscript function (which is fine because it matches the tests), but `create` is an external prop. This leads to the crash since a jscript function doesn't have `prop_get` method (HostObject_prop_get rather). Custom prop isn't going to solve this unfortunately. IMO I think simplest way is to just make `create` a normal jscript prop in this case, especially since it's an exception to the rule. Is that fine?
Ah, right, so it's already broken. Yeah, that might be the way to go.
On Mon Apr 14 21:43:15 2025 +0000, Jacek Caban wrote:
Ah, right, so it's already broken. Yeah, that might be the way to go.
Ugh, while this works, it creates a cyclic ref when XMLHttpRequest is used, which won't even get cleaned up now (it needs the CC integration). I've been thinking of ways how to do avoid it or create it on demand (like for InterpretedFunction's prototype), but I wasn't able to find a solution.
Because it's a method, we can't use on-demand getter or on-demand function (especially since it can get stored to a variable and called way later). We also can't convert HostConstructor to pure jsdisp since it's referenced from the mshtml window (so there would be no point, it would still be a cross mshtml-jscript cyclic ref). Storing a direct ref to the window (since we only need the window to construct) is pointless since it's also a cyclic ref (in fact, just having the prop should be?), i.e. window->XMLHttpRequest ctor->create->window. So there's really no way apart from creating it on demand which is not possible because it's a method. I guess I could add a flag or something to hijack the create_builtin_function somehow if that's even worth attempting, but anyway I'll let it for next MR if desirable.
Also I couldn't reuse HostConstructor since the function itself doesn't work with `new` operator (added tests) so I added a new function type that's mostly a wrapper.