Use a BTreeMap for Document::animation_frame_list (fixes #9834)

The callbacks must stay ordered.
This commit is contained in:
Anthony Ramine 2016-03-02 14:23:47 +01:00
parent f7db68eff7
commit 1d87f61350
4 changed files with 66 additions and 10 deletions

View file

@ -70,7 +70,7 @@ use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::boxed::FnBox; use std::boxed::FnBox;
use std::cell::{Cell, UnsafeCell}; use std::cell::{Cell, UnsafeCell};
use std::collections::{HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::ffi::CString; use std::ffi::CString;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::intrinsics::return_address; use std::intrinsics::return_address;
@ -246,6 +246,16 @@ impl<K, V, S> JSTraceable for HashMap<K, V, S>
} }
} }
impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> {
#[inline]
fn trace(&self, trc: *mut JSTracer) {
for (k, v) in self {
k.trace(trc);
v.trace(trc);
}
}
}
impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) { impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
#[inline] #[inline]
fn trace(&self, trc: *mut JSTracer) { fn trace(&self, trc: *mut JSTracer) {

View file

@ -98,10 +98,10 @@ use std::ascii::AsciiExt;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::boxed::FnBox; use std::boxed::FnBox;
use std::cell::{Cell, Ref, RefMut}; use std::cell::{Cell, Ref, RefMut};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BTreeMap, HashMap};
use std::default::Default; use std::default::Default;
use std::iter::FromIterator; use std::mem;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -185,7 +185,7 @@ pub struct Document {
/// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks /// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks
/// List of animation frame callbacks /// List of animation frame callbacks
#[ignore_heap_size_of = "closures are hard"] #[ignore_heap_size_of = "closures are hard"]
animation_frame_list: DOMRefCell<HashMap<u32, Box<FnBox(f64)>>>, animation_frame_list: DOMRefCell<BTreeMap<u32, Box<FnBox(f64)>>>,
/// Tracks all outstanding loads related to this document. /// Tracks all outstanding loads related to this document.
loader: DOMRefCell<DocumentLoader>, loader: DOMRefCell<DocumentLoader>,
/// The current active HTML parser, to allow resuming after interruptions. /// The current active HTML parser, to allow resuming after interruptions.
@ -1248,11 +1248,8 @@ impl Document {
/// https://html.spec.whatwg.org/multipage/#run-the-animation-frame-callbacks /// https://html.spec.whatwg.org/multipage/#run-the-animation-frame-callbacks
pub fn run_the_animation_frame_callbacks(&self) { pub fn run_the_animation_frame_callbacks(&self) {
let animation_frame_list; let animation_frame_list =
{ mem::replace(&mut *self.animation_frame_list.borrow_mut(), BTreeMap::new());
let mut list = self.animation_frame_list.borrow_mut();
animation_frame_list = Vec::from_iter(list.drain());
}
let performance = self.window.Performance(); let performance = self.window.Performance();
let performance = performance.r(); let performance = performance.r();
let timing = performance.Now(); let timing = performance.Now();
@ -1590,7 +1587,7 @@ impl Document {
asap_scripts_set: DOMRefCell::new(vec![]), asap_scripts_set: DOMRefCell::new(vec![]),
scripting_enabled: Cell::new(true), scripting_enabled: Cell::new(true),
animation_frame_ident: Cell::new(0), animation_frame_ident: Cell::new(0),
animation_frame_list: DOMRefCell::new(HashMap::new()), animation_frame_list: DOMRefCell::new(BTreeMap::new()),
loader: DOMRefCell::new(doc_loader), loader: DOMRefCell::new(doc_loader),
current_parser: Default::default(), current_parser: Default::default(),
reflow_timeout: Cell::new(None), reflow_timeout: Cell::new(None),

View file

@ -5562,6 +5562,12 @@
"url": "/_mozilla/mozilla/collections.html" "url": "/_mozilla/mozilla/collections.html"
} }
], ],
"mozilla/deterministic-raf.html": [
{
"path": "mozilla/deterministic-raf.html",
"url": "/_mozilla/mozilla/deterministic-raf.html"
}
],
"mozilla/documentElement.html": [ "mozilla/documentElement.html": [
{ {
"path": "mozilla/documentElement.html", "path": "mozilla/documentElement.html",

View file

@ -0,0 +1,43 @@
<!doctype html>
<meta charset="utf-8">
<title></title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(function (t) {
var i = 0;
var log = [];
var loopB_ended = false;
var loopA = function () {
log.push("A");
if (i++ < 5) {
requestAnimationFrame(loopA);
} else {
assert_true(loopB_ended);
t.step(function () {
assert_array_equals(log,
["A", "B", "A", "B", "A", "B", "A", "B", "A", "B", "A"]);
});
t.done();
}
};
var loopB = function () {
log.push("B");
if (i < 5) {
requestAnimationFrame(loopB);
} else {
assert_false(loopB_ended);
loopB_ended = true;
t.step(function () {
assert_array_equals(log,
["A", "B", "A", "B", "A", "B", "A", "B", "A", "B"]);
});
}
};
loopA();
loopB();
}, "Concurrent requestAnimationFrame loops are deterministic");
</script>