diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c
index e535cd54bd6..4c57d457e41 100644
--- a/dlls/mshtml/htmlwindow.c
+++ b/dlls/mshtml/htmlwindow.c
@@ -3170,6 +3170,9 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex,
return DISP_E_UNKNOWNNAME;
}
+/* DISPIDs not exposed by interfaces */
+#define DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME 1300
+
static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
{
HTMLWindow *This = impl_from_IDispatchEx(iface);
@@ -3186,6 +3189,13 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName,
if(hres != DISP_E_UNKNOWNNAME)
return hres;
+ if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE10 &&
+ !wcscmp(bstrName, L"requestAnimationFrame")) {
+ TRACE("requestAnimationFrame\n");
+ *pid = DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME;
+ return S_OK;
+ }
+
if(This->outer_window) {
HTMLOuterWindow *frame;
@@ -3272,6 +3282,25 @@ static HRESULT WINAPI WindowDispEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID
return IDispatchEx_InvokeEx(&window->event_target.dispex.IDispatchEx_iface, id, lcid,
wFlags, &dp, pvarRes, pei, pspCaller);
}
+ case DISPID_IHTMLWINDOW_IE10_REQUESTANIMATIONFRAME: {
+ HRESULT hres;
+ LONG r;
+
+ FIXME("requestAnimationFrame: semi-stub\n");
+
+ if(!(wFlags & DISPATCH_METHOD) || pdp->cArgs != 1 || pdp->cNamedArgs) {
+ FIXME("unsupported args\n");
+ return E_INVALIDARG;
+ }
+
+ hres = window_set_timer(window, pdp->rgvarg, 50, NULL, TIMER_ANIMATION_FRAME, &r);
+ if(SUCCEEDED(hres) && pvarRes) {
+ V_VT(pvarRes) = VT_I4;
+ V_I4(pvarRes) = r;
+ }
+
+ return hres;
+ }
}
return IDispatchEx_InvokeEx(&window->event_target.dispex.IDispatchEx_iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 9d1737cc81f..7bc645e549f 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -1217,6 +1217,7 @@ ULONGLONG get_time_stamp(void) DECLSPEC_HIDDEN;
enum timer_type {
TIMER_TIMEOUT,
TIMER_INTERVAL,
+ TIMER_ANIMATION_FRAME,
};
HRESULT set_task_timer(HTMLInnerWindow*,LONG,enum timer_type,IDispatch*,LONG*) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c
index b7616058461..28cb88ab5f1 100644
--- a/dlls/mshtml/task.c
+++ b/dlls/mshtml/task.c
@@ -218,9 +218,20 @@ HRESULT clear_task_timer(HTMLInnerWindow *window, DWORD id)
return S_OK;
}
-static void call_timer_disp(IDispatch *disp)
+static const char *debugstr_timer_type(enum timer_type type)
+{
+ switch(type) {
+ case TIMER_TIMEOUT: return "timeout";
+ case TIMER_INTERVAL: return "interval";
+ case TIMER_ANIMATION_FRAME: return "animation-frame";
+ DEFAULT_UNREACHABLE;
+ }
+}
+
+static void call_timer_disp(IDispatch *disp, enum timer_type timer_type)
{
DISPPARAMS dp = {NULL, NULL, 0, 0};
+ VARIANT timestamp;
EXCEPINFO ei;
VARIANT res;
HRESULT hres;
@@ -228,12 +239,19 @@ static void call_timer_disp(IDispatch *disp)
V_VT(&res) = VT_EMPTY;
memset(&ei, 0, sizeof(ei));
- TRACE(">>>\n");
+ if(timer_type == TIMER_ANIMATION_FRAME) {
+ dp.cArgs = 1;
+ dp.rgvarg = ×tamp;
+ V_VT(×tamp) = VT_R8;
+ V_R8(×tamp) = get_time_stamp();
+ }
+
+ TRACE("%p %s >>>\n", disp, debugstr_timer_type(timer_type));
hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 0, DISPATCH_METHOD, &dp, &res, &ei, NULL);
if(hres == S_OK)
- TRACE("<<<\n");
+ TRACE("%p %s <<<\n", disp, debugstr_timer_type(timer_type));
else
- WARN("<<< %08x\n", hres);
+ WARN("%p %s <<< %08x\n", disp, debugstr_timer_type(timer_type), hres);
VariantClear(&res);
}
@@ -241,6 +259,7 @@ static void call_timer_disp(IDispatch *disp)
static LRESULT process_timer(void)
{
thread_data_t *thread_data;
+ enum timer_type timer_type;
IDispatch *disp;
DWORD tc;
task_timer_t *timer=NULL, *last_timer;
@@ -273,6 +292,7 @@ static LRESULT process_timer(void)
disp = timer->disp;
IDispatch_AddRef(disp);
+ timer_type = timer->type;
if(timer->interval) {
timer->time += timer->interval;
@@ -281,7 +301,7 @@ static LRESULT process_timer(void)
release_task_timer(thread_data->thread_hwnd, timer);
}
- call_timer_disp(disp);
+ call_timer_disp(disp, timer_type);
IDispatch_Release(disp);
}while(!list_empty(&thread_data->timer_list));
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js
index 35b4a001fed..7074b1f62f2 100644
--- a/dlls/mshtml/tests/documentmode.js
+++ b/dlls/mshtml/tests/documentmode.js
@@ -115,6 +115,7 @@ sync_test("window_props", function() {
test_exposed("getSelection", v >= 9);
test_exposed("onfocusout", v >= 9);
test_exposed("getComputedStyle", v >= 9);
+ test_exposed("requestAnimationFrame", v >= 10);
test_exposed("Set", v >= 11);
if(v >= 9) /* FIXME: native exposes it in all compat modes */
test_exposed("performance", true);
diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js
index f5e4f393b58..b30d1a8fbed 100644
--- a/dlls/mshtml/tests/dom.js
+++ b/dlls/mshtml/tests/dom.js
@@ -448,3 +448,13 @@ sync_test("elem_props", function() {
elem.accessKey = "q";
ok(elem.accessKey === "q", "accessKey = " + elem.accessKey + " expected q");
});
+
+async_test("animation_frame", function() {
+ var id = requestAnimationFrame(function(x) {
+ ok(this === window, "this != window");
+ ok(typeof(x) === "number", "x = " + x);
+ ok(arguments.length === 1, "arguments.lenght = " + arguments.length);
+ next_test();
+ });
+ ok(typeof(id) === "number", "id = " + id);
+});