diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c
index ecd530db7e2..235e29a3070 100644
--- a/dlls/mshtml/htmlwindow.c
+++ b/dlls/mshtml/htmlwindow.c
@@ -3152,6 +3152,20 @@ static HRESULT WINAPI window_private_requestAnimationFrame(IWineHTMLWindowPrivat
return hres;
}
+static HRESULT WINAPI window_private_cancelAnimationFrame(IWineHTMLWindowPrivate *iface, VARIANT timer_id)
+{
+ HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface);
+ HRESULT hres;
+
+ TRACE("iface %p, timer_id %s\n", iface, debugstr_variant(&timer_id));
+
+ hres = VariantChangeType(&timer_id, &timer_id, 0, VT_I4);
+ if(SUCCEEDED(hres))
+ clear_animation_timer(This->inner_window, V_I4(&timer_id));
+
+ return S_OK;
+}
+
static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, IDispatch **console)
{
HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface);
@@ -3176,6 +3190,7 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = {
window_private_GetIDsOfNames,
window_private_Invoke,
window_private_requestAnimationFrame,
+ window_private_cancelAnimationFrame,
window_private_get_console,
};
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index a94f1be1969..930ab3bbe19 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -1247,6 +1247,7 @@ enum timer_type {
HRESULT set_task_timer(HTMLInnerWindow*,LONG,enum timer_type,IDispatch*,LONG*) DECLSPEC_HIDDEN;
HRESULT clear_task_timer(HTMLInnerWindow*,DWORD) DECLSPEC_HIDDEN;
+HRESULT clear_animation_timer(HTMLInnerWindow*,DWORD) DECLSPEC_HIDDEN;
BOOL parse_compat_version(const WCHAR*,compat_mode_t*) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl
index b9039c956db..a273e330665 100644
--- a/dlls/mshtml/mshtml_private_iface.idl
+++ b/dlls/mshtml/mshtml_private_iface.idl
@@ -87,7 +87,9 @@ interface IWineHTMLWindowPrivate : IDispatch
{
[id(50)]
HRESULT requestAnimationFrame([in] VARIANT *expr, [retval, out] VARIANT *timer_id);
- [propget, id(51)]
+ [id(51)]
+ HRESULT cancelAnimationFrame([in] VARIANT timer_id);
+ [propget, id(52)]
HRESULT console([retval, out] IDispatch **console);
}
diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c
index 088742e902a..1bb761e1f0f 100644
--- a/dlls/mshtml/task.c
+++ b/dlls/mshtml/task.c
@@ -208,7 +208,8 @@ HRESULT clear_task_timer(HTMLInnerWindow *window, DWORD id)
LIST_FOR_EACH_ENTRY(iter, &thread_data->timer_list, task_timer_t, entry) {
if(iter->id == id && iter->window == window) {
- release_task_timer(thread_data->thread_hwnd, iter);
+ if(iter->type != TIMER_ANIMATION_FRAME)
+ release_task_timer(thread_data->thread_hwnd, iter);
return S_OK;
}
}
@@ -217,6 +218,26 @@ HRESULT clear_task_timer(HTMLInnerWindow *window, DWORD id)
return S_OK;
}
+HRESULT clear_animation_timer(HTMLInnerWindow *window, DWORD id)
+{
+ thread_data_t *thread_data = get_thread_data(FALSE);
+ task_timer_t *iter;
+
+ if(!thread_data)
+ return S_OK;
+
+ LIST_FOR_EACH_ENTRY(iter, &thread_data->timer_list, task_timer_t, entry) {
+ if(iter->id == id && iter->window == window) {
+ if(iter->type == TIMER_ANIMATION_FRAME)
+ release_task_timer(thread_data->thread_hwnd, iter);
+ return S_OK;
+ }
+ }
+
+ WARN("timer not found\n");
+ return S_OK;
+}
+
static const char *debugstr_timer_type(enum timer_type type)
{
switch(type) {
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js
index eeeb1c88430..5f104475f0d 100644
--- a/dlls/mshtml/tests/documentmode.js
+++ b/dlls/mshtml/tests/documentmode.js
@@ -357,6 +357,7 @@ sync_test("window_props", function() {
test_exposed("getSelection", v >= 9);
test_exposed("onfocusout", v >= 9);
test_exposed("getComputedStyle", v >= 9);
+ test_exposed("cancelAnimationFrame", v >= 10);
test_exposed("requestAnimationFrame", v >= 10);
test_exposed("Map", v >= 11);
test_exposed("Set", v >= 11);
diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js
index ed5f72c4376..3939dd95642 100644
--- a/dlls/mshtml/tests/dom.js
+++ b/dlls/mshtml/tests/dom.js
@@ -494,13 +494,21 @@ sync_test("elem_props", function() {
});
async_test("animation_frame", function() {
- var id = requestAnimationFrame(function(x) {
+ var id = requestAnimationFrame(function(x) { ok(false, "request was supposed to be cancelled"); });
+ id = cancelAnimationFrame(id);
+ ok(id === undefined, "cancelAnimationFrame returned " + id);
+
+ id = requestAnimationFrame(function(x) {
ok(this === window, "this != window");
ok(typeof(x) === "number", "x = " + x);
ok(arguments.length === 1, "arguments.length = " + arguments.length);
next_test();
});
+ cancelAnimationFrame(0);
+ clearInterval(id);
+ clearTimeout(id);
ok(typeof(id) === "number", "id = " + id);
+ ok(id !== 0, "id = 0");
});
sync_test("title", function() {