This doesn't implement the listeners (needs wine-gecko notification). Also "media" seems to return somewhat different strings on gecko in some cases, so some of the tests are todo_wine because of that, but I'm not sure if it's worth replicating in practice.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 10 ++ dlls/mshtml/mshtml_private.h | 4 +- dlls/mshtml/mshtml_private_iface.idl | 21 +++ dlls/mshtml/nsiface.idl | 11 ++ dlls/mshtml/omnavigator.c | 187 +++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 2 + dlls/mshtml/tests/es5.js | 12 ++ 7 files changed, 246 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index ef5d80ff512..64e6ae25849 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3166,6 +3166,15 @@ static HRESULT WINAPI window_private_cancelAnimationFrame(IWineHTMLWindowPrivate return S_OK; }
+static HRESULT WINAPI window_private_matchMedia(IWineHTMLWindowPrivate *iface, BSTR media_query, IDispatch **media_query_list) +{ + HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); + + TRACE("iface %p, media_query %s\n", iface, debugstr_w(media_query)); + + return create_media_query_list(This, media_query, media_query_list); +} + static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, IDispatch **console) { HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); @@ -3192,6 +3201,7 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_requestAnimationFrame, window_private_cancelAnimationFrame, window_private_get_console, + window_private_matchMedia, };
static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 0946c9d2ee4..05b37c6b9db 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -285,7 +285,8 @@ typedef struct EventTarget EventTarget; XIID(IWineHTMLWindowPrivate) \ XIID(IWineHTMLWindowCompatPrivate) \ XIID(IWineXMLHttpRequestPrivate) \ - XIID(IWineMSHTMLConsole) + XIID(IWineMSHTMLConsole) \ + XIID(IWineMSHTMLMediaQueryList)
typedef enum { #define XIID(iface) iface ## _tid, @@ -1432,3 +1433,4 @@ IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN;
extern HINSTANCE hInst DECLSPEC_HIDDEN; void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; +HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 8e9e3860b13..a17960e493b 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -76,6 +76,25 @@ interface IWineMSHTMLConsole : IDispatch HRESULT warn([in, optional] VARIANT *varargStart); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab0) +] +interface IWineMSHTMLMediaQueryList : IDispatch +{ + [propget, id(1)] + HRESULT media([retval, out] BSTR *p); + [propget, id(2)] + HRESULT matches([retval, out] VARIANT_BOOL *p); + [id(3)] + HRESULT addListener([in] VARIANT *listener); + [id(4)] + HRESULT removeListener([in] VARIANT *listener); +} + [ odl, oleautomation, @@ -91,6 +110,8 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT cancelAnimationFrame([in] VARIANT timer_id); [propget, id(52)] HRESULT console([retval, out] IDispatch **console); + [id(53)] + HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); }
[ diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index f6e0a909278..b28cce0ca09 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -900,6 +900,17 @@ interface nsIDOMStyleSheetList : nsISupports nsresult Item(uint32_t index, nsIDOMStyleSheet **_retval); }
+[ + object, + uuid(e0e49c52-915b-40f9-9cba-6026305cdf3e), + local +] +interface nsIDOMMediaQueryList : nsISupports +{ + nsresult GetMedia(nsAString *aMedia); + nsresult GetMatches(bool *_retval); +} + [ object, uuid(450cf0ba-de90-4f86-85bf-e10cc8b8713f), diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 4385c4c5bab..1dcd77ac11e 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2645,3 +2645,190 @@ void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret)
*ret = &obj->IWineMSHTMLConsole_iface; } + +struct media_query_list { + DispatchEx dispex; + IWineMSHTMLMediaQueryList IWineMSHTMLMediaQueryList_iface; + LONG ref; + nsIDOMMediaQueryList *nsquerylist; +}; + +static inline struct media_query_list *impl_from_IWineMSHTMLMediaQueryList(IWineMSHTMLMediaQueryList *iface) +{ + return CONTAINING_RECORD(iface, struct media_query_list, IWineMSHTMLMediaQueryList_iface); +} + +static HRESULT WINAPI media_query_list_QueryInterface(IWineMSHTMLMediaQueryList *iface, REFIID riid, void **ppv) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + TRACE("(%p)->(%s %p)\n", media_query_list, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IWineMSHTMLMediaQueryList, riid)) { + *ppv = &media_query_list->IWineMSHTMLMediaQueryList_iface; + }else if(dispex_query_interface(&media_query_list->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI media_query_list_AddRef(IWineMSHTMLMediaQueryList *iface) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + LONG ref = InterlockedIncrement(&media_query_list->ref); + + TRACE("(%p) ref=%ld\n", media_query_list, ref); + + return ref; +} + +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); + + TRACE("(%p) ref=%ld\n", media_query_list, ref); + + if(!ref) { + nsIDOMMediaQueryList_Release(media_query_list->nsquerylist); + release_dispex(&media_query_list->dispex); + heap_free(media_query_list); + } + + return ref; +} + +static HRESULT WINAPI media_query_list_GetTypeInfoCount(IWineMSHTMLMediaQueryList *iface, UINT *pctinfo) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + TRACE("(%p)->(%p)\n", media_query_list, pctinfo); + + return IDispatchEx_GetTypeInfoCount(&media_query_list->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI media_query_list_GetTypeInfo(IWineMSHTMLMediaQueryList *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + return IDispatchEx_GetTypeInfo(&media_query_list->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI media_query_list_GetIDsOfNames(IWineMSHTMLMediaQueryList *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + return IDispatchEx_GetIDsOfNames(&media_query_list->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI media_query_list_Invoke(IWineMSHTMLMediaQueryList *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + return IDispatchEx_Invoke(&media_query_list->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI media_query_list_get_media(IWineMSHTMLMediaQueryList *iface, BSTR *p) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + FIXME("(%p)->(%p)\n", media_query_list, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_query_list_get_matches(IWineMSHTMLMediaQueryList *iface, VARIANT_BOOL *p) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + FIXME("(%p)->(%p)\n", media_query_list, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_query_list_addListener(IWineMSHTMLMediaQueryList *iface, VARIANT *listener) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + FIXME("(%p)->(%s)", media_query_list, debugstr_variant(listener)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_query_list_removeListener(IWineMSHTMLMediaQueryList *iface, VARIANT *listener) +{ + struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + + FIXME("(%p)->(%s)", media_query_list, debugstr_variant(listener)); + + return E_NOTIMPL; +} + +static const IWineMSHTMLMediaQueryListVtbl media_query_list_vtbl = { + media_query_list_QueryInterface, + media_query_list_AddRef, + media_query_list_Release, + media_query_list_GetTypeInfoCount, + media_query_list_GetTypeInfo, + media_query_list_GetIDsOfNames, + media_query_list_Invoke, + media_query_list_get_media, + media_query_list_get_matches, + media_query_list_addListener, + media_query_list_removeListener +}; + +static const tid_t media_query_list_iface_tids[] = { + IWineMSHTMLMediaQueryList_tid, + 0 +}; +static dispex_static_data_t media_query_list_dispex = { + L"MediaQueryList", + NULL, + IWineMSHTMLMediaQueryList_tid, + media_query_list_iface_tids +}; + +HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) +{ + struct media_query_list *media_query_list; + nsISupports *nsunk; + nsAString nsstr; + nsresult nsres; + + if(!media_query || !media_query[0]) + return E_INVALIDARG; + + if(!(media_query_list = heap_alloc(sizeof(*media_query_list)))) + return E_OUTOFMEMORY; + + nsAString_InitDepend(&nsstr, media_query); + nsres = nsIDOMWindow_MatchMedia(window->outer_window->nswindow, &nsstr, &nsunk); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) { + heap_free(media_query_list); + return map_nsresult(nsres); + } + nsres = nsISupports_QueryInterface(nsunk, &IID_nsIDOMMediaQueryList, (void**)&media_query_list->nsquerylist); + assert(NS_SUCCEEDED(nsres)); + nsISupports_Release(nsunk); + + media_query_list->IWineMSHTMLMediaQueryList_iface.lpVtbl = &media_query_list_vtbl; + media_query_list->ref = 1; + 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)); + + *ret = (IDispatch*)&media_query_list->IWineMSHTMLMediaQueryList_iface; + return S_OK; +} diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index b9aea679258..76fa6bacac8 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -253,6 +253,7 @@ sync_test("builtin_toString", function() { if(v >= 10) { test("classList", e.classList, "DOMTokenList", "testclass another "); test("console", window.console, "Console"); + test("mediaQueryList", window.matchMedia("(hover:hover)"), "MediaQueryList"); } if(v >= 9) { document.body.innerHTML = "<!--...-->"; @@ -364,6 +365,7 @@ sync_test("window_props", function() { test_exposed("Set", v >= 11); test_exposed("performance", true); test_exposed("console", v >= 10); + test_exposed("matchMedia", v >= 10); });
sync_test("domimpl_props", function() { diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 822aeef1784..25883bf5757 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+var E_INVALIDARG = 0x80070057; var JS_E_PROP_DESC_MISMATCH = 0x800a01bd; var JS_E_NUMBER_EXPECTED = 0x800a1389; var JS_E_FUNCTION_EXPECTED = 0x800a138a; @@ -2016,3 +2017,14 @@ sync_test("console", function() { } ok(except, "console.timeLog: expected exception"); }); + +sync_test("matchMedia", function() { + var mql; + + try { + mql = window.matchMedia(""); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "matchMedia('') threw " + n); + } +});
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/omnavigator.c | 6 ++++-- dlls/mshtml/tests/es5.js | 13 ++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 1dcd77ac11e..00f6c72894e 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2742,10 +2742,12 @@ static HRESULT WINAPI media_query_list_Invoke(IWineMSHTMLMediaQueryList *iface, static HRESULT WINAPI media_query_list_get_media(IWineMSHTMLMediaQueryList *iface, BSTR *p) { struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + nsAString nsstr;
- FIXME("(%p)->(%p)\n", media_query_list, p); + TRACE("(%p)->(%p)\n", media_query_list, p);
- return E_NOTIMPL; + nsAString_InitDepend(&nsstr, NULL); + return return_nsstr(nsIDOMMediaQueryList_GetMedia(media_query_list->nsquerylist, &nsstr), &nsstr, p); }
static HRESULT WINAPI media_query_list_get_matches(IWineMSHTMLMediaQueryList *iface, VARIANT_BOOL *p) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 25883bf5757..5f9202b13c6 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2019,7 +2019,7 @@ sync_test("console", function() { });
sync_test("matchMedia", function() { - var mql; + var i, r, mql;
try { mql = window.matchMedia(""); @@ -2027,4 +2027,15 @@ sync_test("matchMedia", function() { var n = ex.number >>> 0; ok(n === E_INVALIDARG, "matchMedia('') threw " + n); } + r = [ + [ undefined, "unknown" ], + [ null, "unknown" ], + [ 42, "not all" ], + [{ toString: function() { return "(max-width: 0px)"; }}, "all and (max-width:0px)" ] + ]; + for(i = 0; i < r.length; i++) { + mql = window.matchMedia(r[i][0]); + todo_wine_if(r[i][0] !== 42). + ok(mql.media === r[i][1], r[i][0] + " media = " + mql.media); + } });
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/omnavigator.c | 10 ++++++++-- dlls/mshtml/tests/es5.js | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 00f6c72894e..42e8149a602 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2753,10 +2753,16 @@ static HRESULT WINAPI media_query_list_get_media(IWineMSHTMLMediaQueryList *ifac static HRESULT WINAPI media_query_list_get_matches(IWineMSHTMLMediaQueryList *iface, VARIANT_BOOL *p) { struct media_query_list *media_query_list = impl_from_IWineMSHTMLMediaQueryList(iface); + nsresult nsres; + cpp_bool b;
- FIXME("(%p)->(%p)\n", media_query_list, p); + TRACE("(%p)->(%p)\n", media_query_list, p);
- return E_NOTIMPL; + nsres = nsIDOMMediaQueryList_GetMatches(media_query_list->nsquerylist, &b); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + *p = b ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; }
static HRESULT WINAPI media_query_list_addListener(IWineMSHTMLMediaQueryList *iface, VARIANT *listener) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 5f9202b13c6..c18639582d0 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2037,5 +2037,8 @@ sync_test("matchMedia", function() { mql = window.matchMedia(r[i][0]); todo_wine_if(r[i][0] !== 42). ok(mql.media === r[i][1], r[i][0] + " media = " + mql.media); + ok(mql.matches === false, r[i][0] + " matches"); } + mql = window.matchMedia("(max-width: 1000px)"); + ok(mql.matches === true, "(max-width: 1000px) does not match"); });
This merge request was approved by Jacek Caban.