mshtml: Implement MediaQueryList's addListener method.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
parent
8b8d787d7d
commit
1a01fb23a3
6 changed files with 240 additions and 5 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue