This get us pass the "Update your browser" blocker in adobe's sign-in page. The page itself doesn't make use of `window.MutationObserver`.
However the sign-in page is still broken.
-- v6: mshtml: implement window.MutationObserver with MutationObserver stub
From: Yuxuan Shui yshui@codeweavers.com
--- dlls/mshtml/htmlwindow.c | 33 +++- dlls/mshtml/mshtml_private.h | 6 +- dlls/mshtml/mshtml_private_iface.idl | 14 ++ dlls/mshtml/mutation.c | 272 +++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 4 + 5 files changed, 327 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c6072c7e9fa..ba19f20a51c 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -309,6 +309,9 @@ static void release_inner_window(HTMLInnerWindow *This) if(This->mon) IMoniker_Release(This->mon);
+ if(This->mutation_observer_ctor) + IDispatch_Release(This->mutation_observer_ctor); + free(This); }
@@ -3330,6 +3333,26 @@ static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, return S_OK; }
+static HRESULT WINAPI window_private_get_MutationObserver(IWineHTMLWindowPrivate *iface, + IDispatch **mutation_observer) +{ + HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); + HRESULT hres; + + FIXME("iface %p, mutation_observer %p, stub.\n", iface, mutation_observer); + + if (!This->inner_window->mutation_observer_ctor) { + hres = create_mutation_observer_ctor(dispex_compat_mode(&This->inner_window->event_target.dispex), + &This->inner_window->mutation_observer_ctor); + if (FAILED(hres)) + return hres; + } + + IDispatch_AddRef(This->inner_window->mutation_observer_ctor); + *mutation_observer = This->inner_window->mutation_observer_ctor; + return S_OK; +} + static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_QueryInterface, window_private_AddRef, @@ -3343,6 +3366,7 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_get_console, window_private_matchMedia, window_private_postMessage, + window_private_get_MutationObserver };
static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface) @@ -3975,12 +3999,19 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_UNKNOWN} };
+ // Hide MutationObserver from IE10 and older + static const dispex_hook_t private_ie10_hooks[] = { + {DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBS}, + {DISPID_UNKNOWN} + }; + if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); else dispex_info_add_interface(info, IWineHTMLWindowCompatPrivate_tid, NULL); if(compat_mode >= COMPAT_MODE_IE10) - dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL); + dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, + compat_mode >= COMPAT_MODE_IE11 ? NULL: private_ie10_hooks);
dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 59d652a828b..ffd179f1124 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -294,7 +294,8 @@ typedef struct EventTarget EventTarget; XIID(IWinePageTransitionEvent) \ XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ - XIID(IWineMSHTMLMediaQueryList) + XIID(IWineMSHTMLMediaQueryList) \ + XIID(IWineMSHTMLMutationObserver)
typedef enum { #define XIID(iface) iface ## _tid, @@ -619,6 +620,7 @@ struct HTMLInnerWindow { LONG task_magic;
IMoniker *mon; + IDispatch *mutation_observer_ctor; nsChannelBSC *bscallback; struct list bindings; }; @@ -1479,3 +1481,5 @@ IInternetSecurityManager *get_security_manager(void); extern HINSTANCE hInst; void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret); HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret); + +HRESULT create_mutation_observer_ctor(compat_mode_t compat_mode, IDispatch **ret); diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index c0bb30fbbc8..8aaa21b6eba 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -76,6 +76,17 @@ interface IWineMSHTMLConsole : IDispatch HRESULT warn([in, optional] VARIANT *varargStart); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(6ac5491e-1758-4b82-98a2-83e31a7c8871) +] +interface IWineMSHTMLMutationObserver : IDispatch +{ +} + [ odl, oleautomation, @@ -95,6 +106,7 @@ interface IWineMSHTMLMediaQueryList : IDispatch HRESULT removeListener([in] VARIANT *listener); }
+const long DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBS = 55; [ odl, oleautomation, @@ -114,6 +126,8 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); [id(54)] HRESULT postMessage([in] VARIANT msg, [in] BSTR targetOrigin, [in, optional] VARIANT transfer); + [propget, id(DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBS)] + HRESULT MutationObserver([retval, out] IDispatch **observer_ctor); }
[ diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index 83ab623aea8..0e79f75abee 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -1076,3 +1076,275 @@ void init_mutation(nsIComponentManager *component_manager) if(NS_FAILED(nsres)) ERR("Could not create nsIContentUtils instance: %08lx\n", nsres); } + +struct mutation_observer { + IWineMSHTMLMutationObserver IWineMSHTMLMutationObserver_iface; + + LONG ref; + DispatchEx dispex; + IDispatch *callback; + + HTMLDOMNode *node; +}; + +static inline struct mutation_observer *impl_from_IWineMSHTMLMutationObserver(IWineMSHTMLMutationObserver *iface) +{ + return CONTAINING_RECORD(iface, struct mutation_observer, IWineMSHTMLMutationObserver_iface); +} + +static HRESULT WINAPI MutationObserver_QueryInterface(IWineMSHTMLMutationObserver *iface, REFIID riid, void **ppv) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IWineMSHTMLMutationObserver, riid)) { + *ppv = &This->IWineMSHTMLMutationObserver_iface; + }else { + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI MutationObserver_AddRef(IWineMSHTMLMutationObserver *iface) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI MutationObserver_Release(IWineMSHTMLMutationObserver *iface) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + if(This->node) { + IHTMLDOMNode_Release(&This->node->IHTMLDOMNode_iface); + This->node = NULL; + } + release_dispex(&This->dispex); + IDispatch_Release(This->callback); + This->callback = NULL; + free(This); + } + + return ref; +} + +static HRESULT WINAPI MutationObserver_GetTypeInfoCount(IWineMSHTMLMutationObserver *iface, UINT *pctinfo) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + FIXME("(%p)->(%p)\n", This, pctinfo); + return E_NOTIMPL; +} + +static HRESULT WINAPI MutationObserver_GetTypeInfo(IWineMSHTMLMutationObserver *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI MutationObserver_GetIDsOfNames(IWineMSHTMLMutationObserver *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, + DISPID *rgDispId) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, + rgDispId); +} + +static HRESULT WINAPI MutationObserver_Invoke(IWineMSHTMLMutationObserver *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface); + + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static const IWineMSHTMLMutationObserverVtbl WineMSHTMLMutationObserverVtbl = { + MutationObserver_QueryInterface, + MutationObserver_AddRef, + MutationObserver_Release, + MutationObserver_GetTypeInfoCount, + MutationObserver_GetTypeInfo, + MutationObserver_GetIDsOfNames, + MutationObserver_Invoke, +}; + +static const tid_t mutation_observer_iface_tids[] = { + IWineMSHTMLMutationObserver_tid, + 0 +}; +static dispex_static_data_t mutation_observer_dispex = { + L"MutationObserver", + NULL, + IWineMSHTMLMutationObserver_tid, + mutation_observer_iface_tids +}; + +static HRESULT create_mutation_observer(compat_mode_t compat_mode, IDispatch *callback, + IWineMSHTMLMutationObserver **ret) { + struct mutation_observer *obj; + + TRACE("(compat_mode = %d, callback = %p, ret = %p)\n", compat_mode, callback, ret); + + obj = calloc(1, sizeof(*obj)); + if(!obj) + { + ERR("No memory.\n"); + return E_OUTOFMEMORY; + } + + obj->IWineMSHTMLMutationObserver_iface.lpVtbl = &WineMSHTMLMutationObserverVtbl; + obj->ref = 1; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLMutationObserver_iface.lpVtbl, + &mutation_observer_dispex, compat_mode); + + IDispatch_AddRef(callback); + obj->callback = callback; + *ret = &obj->IWineMSHTMLMutationObserver_iface; + return S_OK; +} + +struct mutation_observer_ctor { + IUnknown IUnknown_iface; + DispatchEx dispex; + + LONG ref; +}; + +static inline struct mutation_observer_ctor *mutation_observer_ctor_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct mutation_observer_ctor, IUnknown_iface); +} + +static inline struct mutation_observer_ctor *mutation_observer_ctor_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct mutation_observer_ctor, dispex); +} + +static HRESULT WINAPI mutation_observer_ctor_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + struct mutation_observer_ctor *This = mutation_observer_ctor_from_IUnknown(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IUnknown_iface; + }else { + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI mutation_observer_ctor_AddRef(IUnknown *iface) +{ + struct mutation_observer_ctor *This = mutation_observer_ctor_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI mutation_observer_ctor_Release(IUnknown *iface) +{ + struct mutation_observer_ctor *This = mutation_observer_ctor_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_dispex(&This->dispex); + free(This); + } + + return ref; +} + +static const IUnknownVtbl mutation_observer_ctor_vtbl = { + mutation_observer_ctor_QueryInterface, + mutation_observer_ctor_AddRef, + mutation_observer_ctor_Release, +}; + +HRESULT mutation_observer_ctor_value(DispatchEx *dispex, LCID lcid, + WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, + IServiceProvider *caller) +{ + struct mutation_observer_ctor *This = mutation_observer_ctor_from_DispatchEx(dispex); + VARIANT *callback; + IWineMSHTMLMutationObserver *mutation_observer; + HRESULT hres; + int argc = params->cArgs - params->cNamedArgs; + + V_VT(res) = VT_NULL; + + if (argc != 1) + return E_INVALIDARG; + + callback = params->rgvarg + (params->cArgs - 1); + if (V_VT(callback) != VT_DISPATCH) + return E_INVALIDARG; + + hres = create_mutation_observer(dispex_compat_mode(&This->dispex), V_DISPATCH(callback), + &mutation_observer); + if (FAILED(hres)) + return hres; + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)mutation_observer; + + return S_OK; +} + +static dispex_static_data_t mutation_observer_ctor_dispex = { + L"Function", + (dispex_static_data_vtbl_t[]){ + { + .value = mutation_observer_ctor_value, + } + }, + NULL_tid, + (const tid_t []){0}, +}; + +HRESULT create_mutation_observer_ctor(compat_mode_t compat_mode, IDispatch **ret) { + struct mutation_observer_ctor *obj; + + TRACE("(compat_mode = %d, ret = %p)\n", compat_mode, ret); + + obj = calloc(1, sizeof(*obj)); + if(!obj) + { + ERR("No memory.\n"); + return E_OUTOFMEMORY; + } + + obj->IUnknown_iface.lpVtbl = &mutation_observer_ctor_vtbl; + obj->ref = 1; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IUnknown_iface.lpVtbl, + &mutation_observer_ctor_dispex, compat_mode); + + *ret = (IDispatch *)&obj->dispex.IDispatchEx_iface; + return S_OK; +} diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 00a6eded3fe..15760058403 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -343,6 +343,9 @@ sync_test("builtin_toString", function() { test("console", window.console, "Console"); test("mediaQueryList", window.matchMedia("(hover:hover)"), "MediaQueryList"); } + if(v >= 11) { + test("MutationObserver", new window.MutationObserver(function() {}), "MutationObserver"); + } if(v >= 9) { document.body.innerHTML = "<!--...-->"; test("comment", document.body.firstChild, "Comment"); @@ -475,6 +478,7 @@ sync_test("window_props", function() { test_exposed("performance", true); test_exposed("console", v >= 10); test_exposed("matchMedia", v >= 10); + test_exposed("MutationObserver", v >= 11); });
sync_test("domimpl_props", function() {
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=135168
Your paranoid android.
=== debian11 (32 bit report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit ar:MA report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit de report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit fr report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit he:IL report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit hi:IN report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit ja:JP report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11 (32 bit zh:CN report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11b (32 bit WoW report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
=== debian11b (64 bit WoW report) ===
mshtml: script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception " script.c:1126: Test failed: L"/index.html?11:builtin_toString: Got exception "
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/htmlwindow.c:
};
- // Hide MutationObserver from IE10 and older
- static const dispex_hook_t private_ie10_hooks[] = {
{DISPID_IWINEHTMLWINDOWPRIVATE_MUTATIONOBS},
{DISPID_UNKNOWN}
- };
- if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); else dispex_info_add_interface(info, IWineHTMLWindowCompatPrivate_tid, NULL); if(compat_mode >= COMPAT_MODE_IE10)
dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL);
dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid,
compat_mode >= COMPAT_MODE_IE11 ? NULL: private_ie10_hooks);
nitpick: add a space after NULL please.
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/htmlwindow.c:
{DISPID_UNKNOWN} };
- // Hide MutationObserver from IE10 and older
You should make this comment less explicit to MutationObserver; just say something like `Hide props not available in IE10`. Also please use C-style comments so it fits the rest of the code: ```c /* Hide props not available in IE10 */ ```
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/mutation.c:
if(NS_FAILED(nsres)) ERR("Could not create nsIContentUtils instance: %08lx\n", nsres);
}
+struct mutation_observer {
- IWineMSHTMLMutationObserver IWineMSHTMLMutationObserver_iface;
- LONG ref;
- DispatchEx dispex;
- IDispatch *callback;
- HTMLDOMNode *node;
Please remove the node, you're not even making use of it, and it's not a DOM node in the first place.
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/mutation.c:
This->node = NULL;
}
release_dispex(&This->dispex);
IDispatch_Release(This->callback);
This->callback = NULL;
free(This);
- }
- return ref;
+}
+static HRESULT WINAPI MutationObserver_GetTypeInfoCount(IWineMSHTMLMutationObserver *iface, UINT *pctinfo) +{
- struct mutation_observer *This = impl_from_IWineMSHTMLMutationObserver(iface);
- FIXME("(%p)->(%p)\n", This, pctinfo);
- return E_NOTIMPL;
Why not forward this as well?
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/mutation.c:
return E_INVALIDARG;
- callback = params->rgvarg + (params->cArgs - 1);
- if (V_VT(callback) != VT_DISPATCH)
return E_INVALIDARG;
- hres = create_mutation_observer(dispex_compat_mode(&This->dispex), V_DISPATCH(callback),
&mutation_observer);
- if (FAILED(hres))
return hres;
- V_VT(res) = VT_DISPATCH;
- V_DISPATCH(res) = (IDispatch*)mutation_observer;
- return S_OK;
+}
Please add some basic tests for the constructor, I suggested some earlier, but now since you can instantiate the object, I suggest some like:
* What happens if you construct with more than 1 arg? Probably it ignores further args rather than giving error. * What happens if you pass a null to callback? Or a number, for example? Does it give error or simply ignores it? * I think you should ignore named args, the rest of the code doesn't really deal with them, and you only have one arg to care about anyway.
Gabriel Ivăncescu (@insn) commented about dlls/mshtml/mutation.c:
- V_VT(res) = VT_DISPATCH;
- V_DISPATCH(res) = (IDispatch*)mutation_observer;
- return S_OK;
+}
+static dispex_static_data_t mutation_observer_ctor_dispex = {
- L"Function",
- (dispex_static_data_vtbl_t[]){
{
.value = mutation_observer_ctor_value,
}
- },
- NULL_tid,
- (const tid_t []){0},
+};
I think you should use separate variables here like the rest of the code instead of inlining the structs.
Thanks, looks a lot better now, just a couple of comments.
On Mon Jul 24 18:13:11 2023 +0000, Gabriel Ivăncescu wrote:
Please remove the node, you're not even making use of it, and it's not a DOM node in the first place.
MutationObserver has a target DOM `Node`, this is meant to store that. I don't know if this is the right type.