mshtml: Implement MediaQueryList's addListener method.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2023-04-14 16:52:50 +03:00 committed by Alexandre Julliard
parent 8b8d787d7d
commit 1a01fb23a3
6 changed files with 240 additions and 5 deletions

View file

@ -3337,7 +3337,7 @@ HRESULT create_storage_event(HTMLDocumentNode *doc, BSTR key, BSTR old_value, BS
return S_OK;
}
static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
{
IDispatchEx *dispex;
EXCEPINFO ei;

View file

@ -1055,6 +1055,7 @@ void init_node_cc(void) DECLSPEC_HIDDEN;
HRESULT nsuri_to_url(LPCWSTR,BOOL,BSTR*) DECLSPEC_HIDDEN;
HRESULT call_disp_func(IDispatch*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN;
void call_property_onchanged(ConnectionPointContainer*,DISPID) DECLSPEC_HIDDEN;
HRESULT call_set_active_object(IOleInPlaceUIWindow*,IOleInPlaceActiveObject*) DECLSPEC_HIDDEN;

View file

@ -923,6 +923,16 @@ interface nsIDOMMediaQueryList : nsISupports
nsresult SetListener(nsIDOMMediaQueryListListener *listener);
}
[
object,
uuid(279a5cbd-5c15-475d-847b-e0de1624eb77),
local
]
interface nsIDOMMediaQueryListListener : nsISupports
{
nsresult HandleChange(nsIDOMMediaQueryList *mql);
}
[
object,
uuid(450cf0ba-de90-4f86-85bf-e10cc8b8713f),

View file

@ -2651,11 +2651,25 @@ void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret)
*ret = &obj->IWineMSHTMLConsole_iface;
}
struct media_query_list_listener {
struct list entry;
IDispatch *function;
};
struct media_query_list_callback;
struct media_query_list {
DispatchEx dispex;
IWineMSHTMLMediaQueryList IWineMSHTMLMediaQueryList_iface;
LONG ref;
nsIDOMMediaQueryList *nsquerylist;
struct media_query_list_callback *callback;
struct list listeners;
};
struct media_query_list_callback {
nsIDOMMediaQueryListListener nsIDOMMediaQueryListListener_iface;
struct media_query_list *media_query_list;
LONG ref;
};
static inline struct media_query_list *impl_from_IWineMSHTMLMediaQueryList(IWineMSHTMLMediaQueryList *iface)
@ -2696,10 +2710,17 @@ static ULONG WINAPI media_query_list_Release(IWineMSHTMLMediaQueryList *iface)
{
struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface);
LONG ref = InterlockedDecrement(&media_query_list->ref);
struct media_query_list_listener *listener, *listener2;
TRACE("(%p) ref=%ld\n", media_query_list, ref);
if(!ref) {
media_query_list->callback->media_query_list = NULL;
LIST_FOR_EACH_ENTRY_SAFE(listener, listener2, &media_query_list->listeners, struct media_query_list_listener, entry) {
IDispatch_Release(listener->function);
free(listener);
}
nsIDOMMediaQueryListListener_Release(&media_query_list->callback->nsIDOMMediaQueryListListener_iface);
nsIDOMMediaQueryList_Release(media_query_list->nsquerylist);
release_dispex(&media_query_list->dispex);
free(media_query_list);
@ -2773,10 +2794,24 @@ static HRESULT WINAPI media_query_list_get_matches(IWineMSHTMLMediaQueryList *if
static HRESULT WINAPI media_query_list_addListener(IWineMSHTMLMediaQueryList *iface, VARIANT *listener)
{
struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface);
struct media_query_list_listener *entry;
FIXME("(%p)->(%s)\n", media_query_list, debugstr_variant(listener));
TRACE("(%p)->(%s)\n", media_query_list, debugstr_variant(listener));
return E_NOTIMPL;
if(V_VT(listener) != VT_DISPATCH || !V_DISPATCH(listener))
return S_OK;
LIST_FOR_EACH_ENTRY(entry, &media_query_list->listeners, struct media_query_list_listener, entry)
if(entry->function == V_DISPATCH(listener))
return S_OK;
if(!(entry = malloc(sizeof(*entry))))
return E_OUTOFMEMORY;
entry->function = V_DISPATCH(listener);
IDispatch_AddRef(V_DISPATCH(listener));
list_add_tail(&media_query_list->listeners, &entry->entry);
return S_OK;
}
static HRESULT WINAPI media_query_list_removeListener(IWineMSHTMLMediaQueryList *iface, VARIANT *listener)
@ -2802,6 +2837,101 @@ static const IWineMSHTMLMediaQueryListVtbl media_query_list_vtbl = {
media_query_list_removeListener
};
static inline struct media_query_list_callback *impl_from_nsIDOMMediaQueryListListener(nsIDOMMediaQueryListListener *iface)
{
return CONTAINING_RECORD(iface, struct media_query_list_callback, nsIDOMMediaQueryListListener_iface);
}
static nsresult NSAPI media_query_list_callback_QueryInterface(nsIDOMMediaQueryListListener *iface,
nsIIDRef riid, void **result)
{
struct media_query_list_callback *callback = impl_from_nsIDOMMediaQueryListListener(iface);
if(IsEqualGUID(&IID_nsISupports, riid) || IsEqualGUID(&IID_nsIDOMMediaQueryListListener, riid)) {
*result = &callback->nsIDOMMediaQueryListListener_iface;
}else {
*result = NULL;
return NS_NOINTERFACE;
}
nsIDOMMediaQueryListListener_AddRef(&callback->nsIDOMMediaQueryListListener_iface);
return NS_OK;
}
static nsrefcnt NSAPI media_query_list_callback_AddRef(nsIDOMMediaQueryListListener *iface)
{
struct media_query_list_callback *callback = impl_from_nsIDOMMediaQueryListListener(iface);
LONG ref = InterlockedIncrement(&callback->ref);
TRACE("(%p) ref=%ld\n", callback, ref);
return ref;
}
static nsrefcnt NSAPI media_query_list_callback_Release(nsIDOMMediaQueryListListener *iface)
{
struct media_query_list_callback *callback = impl_from_nsIDOMMediaQueryListListener(iface);
LONG ref = InterlockedDecrement(&callback->ref);
TRACE("(%p) ref=%ld\n", callback, ref);
if(!ref)
free(callback);
return ref;
}
static nsresult NSAPI media_query_list_callback_HandleChange(nsIDOMMediaQueryListListener *iface, nsIDOMMediaQueryList *mql)
{
struct media_query_list_callback *callback = impl_from_nsIDOMMediaQueryListListener(iface);
IDispatch *listener_funcs_buf[4], **listener_funcs = listener_funcs_buf;
struct media_query_list *media_query_list = callback->media_query_list;
struct media_query_list_listener *listener;
unsigned cnt, i = 0;
VARIANT args[1], v;
HRESULT hres;
if(!media_query_list)
return NS_OK;
cnt = list_count(&media_query_list->listeners);
if(cnt > ARRAY_SIZE(listener_funcs_buf) && !(listener_funcs = malloc(cnt * sizeof(*listener_funcs))))
return NS_ERROR_OUT_OF_MEMORY;
LIST_FOR_EACH_ENTRY(listener, &media_query_list->listeners, struct media_query_list_listener, entry) {
listener_funcs[i] = listener->function;
IDispatch_AddRef(listener_funcs[i++]);
}
for(i = 0; i < cnt; i++) {
DISPPARAMS dp = { args, NULL, 1, 0 };
V_VT(args) = VT_DISPATCH;
V_DISPATCH(args) = (IDispatch*)&media_query_list->dispex.IDispatchEx_iface;
V_VT(&v) = VT_EMPTY;
TRACE("%p >>>\n", media_query_list);
hres = call_disp_func(listener_funcs[i], &dp, &v);
if(hres == S_OK) {
TRACE("%p <<< %s\n", media_query_list, debugstr_variant(&v));
VariantClear(&v);
}else {
WARN("%p <<< %08lx\n", media_query_list, hres);
}
IDispatch_Release(listener_funcs[i]);
}
if(listener_funcs != listener_funcs_buf)
free(listener_funcs);
return NS_OK;
}
static const nsIDOMMediaQueryListListenerVtbl media_query_list_callback_vtbl = {
media_query_list_callback_QueryInterface,
media_query_list_callback_AddRef,
media_query_list_callback_Release,
media_query_list_callback_HandleChange
};
static const tid_t media_query_list_iface_tids[] = {
IWineMSHTMLMediaQueryList_tid,
0
@ -2826,10 +2956,19 @@ HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch
if(!(media_query_list = malloc(sizeof(*media_query_list))))
return E_OUTOFMEMORY;
if(!(media_query_list->callback = malloc(sizeof(*media_query_list->callback)))) {
free(media_query_list);
return E_OUTOFMEMORY;
}
media_query_list->callback->nsIDOMMediaQueryListListener_iface.lpVtbl = &media_query_list_callback_vtbl;
media_query_list->callback->media_query_list = media_query_list;
media_query_list->callback->ref = 1;
nsAString_InitDepend(&nsstr, media_query);
nsres = nsIDOMWindow_MatchMedia(window->outer_window->nswindow, &nsstr, &nsunk);
nsAString_Finish(&nsstr);
if(NS_FAILED(nsres)) {
free(media_query_list->callback);
free(media_query_list);
return map_nsresult(nsres);
}
@ -2837,8 +2976,12 @@ HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch
assert(NS_SUCCEEDED(nsres));
nsISupports_Release(nsunk);
nsres = nsIDOMMediaQueryList_SetListener(media_query_list->nsquerylist, &media_query_list->callback->nsIDOMMediaQueryListListener_iface);
assert(NS_SUCCEEDED(nsres));
media_query_list->IWineMSHTMLMediaQueryList_iface.lpVtbl = &media_query_list_vtbl;
media_query_list->ref = 1;
list_init(&media_query_list->listeners);
init_dispatch(&media_query_list->dispex, (IUnknown*)&media_query_list->IWineMSHTMLMediaQueryList_iface,
&media_query_list_dispex, dispex_compat_mode(&window->inner_window->event_target.dispex));

View file

@ -2071,8 +2071,8 @@ sync_test("console", function() {
ok(except, "console.timeLog: expected exception");
});
sync_test("matchMedia", function() {
var i, r, mql;
async_test("matchMedia", function() {
var i, r, mql, expect, event_fired, event2_fired;
try {
mql = window.matchMedia("");
@ -2094,6 +2094,65 @@ sync_test("matchMedia", function() {
}
mql = window.matchMedia("(max-width: 1000px)");
ok(mql.matches === true, "(max-width: 1000px) does not match");
mql = window.matchMedia("(max-width: 50px)");
ok(mql.matches === false, "(max-width: 50px) matches");
ok(!("addEventListener" in mql), "addEventListener in MediaQueryList");
ok(!("removeEventListener" in mql), "removeEventListener in MediaQueryList");
r = mql.addListener(null);
ok(r === undefined, "addListener with null returned " + r);
r = mql.addListener("function() { ok(false, 'string handler called'); }");
ok(r === undefined, "addListener with string returned " + r);
var handler = function(e) {
ok(this === window, "handler this = " + this);
ok(e === mql, "handler argument = " + e);
event_fired = true;
ok(event2_fired !== true, "second handler fired before first");
}
var handler2 = function(e) {
ok(this === window, "handler2 this = " + this);
ok(e === mql, "handler2 argument = " + e);
event2_fired = true;
}
var tests = [
[ 20, 20, function() {
var r = mql.addListener(handler);
ok(r === undefined, "addListener with function returned " + r);
}],
[ 120, 120, function() {
ok(event_fired === true, "event not fired after changing from 20x20 to 120x120 view");
mql.addListener(null);
mql.addListener("function() { ok(false, 'second string handler called'); }");
mql.addListener(handler2);
}],
[ 30, 30, function() {
ok(event_fired === true, "event not fired after changing from 120x120 to 30x30 view");
ok(event2_fired === true, "event not fired from second handler after changing from 120x120 to 30x30 view");
}],
[ 300, 300, function() {
}]
];
function test() {
tests[i][2]();
if(++i >= tests.length) {
next_test();
return;
}
expect = !expect;
event_fired = event2_fired = false;
external.setViewSize(tests[i][0], tests[i][1]);
window.setTimeout(check);
}
// async dispatch once even after change confirmed, to ensure that any possible listeners are dispatched first (or not)
function check() { window.setTimeout(mql.matches === expect ? test : check); }
i = 0;
expect = !mql.matches;
external.setViewSize(tests[i][0], tests[i][1]);
window.setTimeout(check);
});
sync_test("initProgressEvent", function() {

View file

@ -170,6 +170,7 @@ DEFINE_EXPECT(GetTypeInfo);
#define DISPID_EXTERNAL_TEST_VARS 0x30000B
#define DISPID_EXTERNAL_TESTHOSTCTX 0x30000C
#define DISPID_EXTERNAL_GETMIMETYPE 0x30000D
#define DISPID_EXTERNAL_SETVIEWSIZE 0x30000E
static const GUID CLSID_TestScript[] = {
{0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}},
@ -897,6 +898,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName,
*pid = DISPID_EXTERNAL_GETMIMETYPE;
return S_OK;
}
if(!lstrcmpW(bstrName, L"setViewSize")) {
*pid = DISPID_EXTERNAL_SETVIEWSIZE;
return S_OK;
}
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
return DISP_E_UNKNOWNNAME;
@ -1158,6 +1163,23 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID
V_VT(pvarRes) = V_BSTR(pvarRes) ? VT_BSTR : VT_NULL;
return S_OK;
case DISPID_EXTERNAL_SETVIEWSIZE: {
RECT rect = { 0 };
ok(pdp != NULL, "pdp == NULL\n");
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs);
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
ok(pei != NULL, "pei == NULL\n");
ok(V_VT(&pdp->rgvarg[1]) == VT_I4, "width VT = %d\n", V_VT(&pdp->rgvarg[1]));
ok(V_VT(&pdp->rgvarg[0]) == VT_I4, "height VT = %d\n", V_VT(&pdp->rgvarg[0]));
rect.right = V_I4(&pdp->rgvarg[1]);
rect.bottom = V_I4(&pdp->rgvarg[0]);
return IOleDocumentView_SetRect(view, &rect);
}
default:
ok(0, "unexpected call\n");
return E_NOTIMPL;