mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
merge from origin/master
This commit is contained in:
commit
167d5777d8
7 changed files with 105 additions and 14 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -5096,7 +5096,8 @@ checksum = "a871f1e45a3a3f0c73fb60343c811238bb5143a81642e27c2ac7aac27ff01a63"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raqote"
|
name = "raqote"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
source = "git+https://github.com/jrmuizel/raqote#7b235e9a7721d5db6dbfd82ec69e390111653081"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5b6cb89f8be6a645e5834f3ad44a7960d12343d97b5b7fb07cb0365ae36aa2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"euclid",
|
"euclid",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
|
|
|
@ -33,7 +33,7 @@ lyon_geom = "1.0.4"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
pathfinder_geometry = "0.5"
|
pathfinder_geometry = "0.5"
|
||||||
pixels = { path = "../pixels" }
|
pixels = { path = "../pixels" }
|
||||||
raqote = { git = "https://github.com/jrmuizel/raqote" }
|
raqote = "0.8.2"
|
||||||
servo_arc = { path = "../servo_arc" }
|
servo_arc = { path = "../servo_arc" }
|
||||||
servo_config = { path = "../config" }
|
servo_config = { path = "../config" }
|
||||||
sparkle = "0.1.25"
|
sparkle = "0.1.25"
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub(crate) struct Animations {
|
||||||
pub sets: DocumentAnimationSet,
|
pub sets: DocumentAnimationSet,
|
||||||
|
|
||||||
/// Whether or not we have animations that are running.
|
/// Whether or not we have animations that are running.
|
||||||
have_running_animations: Cell<bool>,
|
has_running_animations: Cell<bool>,
|
||||||
|
|
||||||
/// A list of nodes with in-progress CSS transitions or pending events.
|
/// A list of nodes with in-progress CSS transitions or pending events.
|
||||||
rooted_nodes: DomRefCell<FxHashMap<OpaqueNode, Dom<Node>>>,
|
rooted_nodes: DomRefCell<FxHashMap<OpaqueNode, Dom<Node>>>,
|
||||||
|
@ -53,7 +53,7 @@ impl Animations {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Animations {
|
Animations {
|
||||||
sets: Default::default(),
|
sets: Default::default(),
|
||||||
have_running_animations: Cell::new(false),
|
has_running_animations: Cell::new(false),
|
||||||
rooted_nodes: Default::default(),
|
rooted_nodes: Default::default(),
|
||||||
pending_events: Default::default(),
|
pending_events: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ impl Animations {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.unroot_unused_nodes(&sets);
|
self.unroot_unused_nodes(&sets);
|
||||||
|
//self.update_running_animations_presence(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel animations for the given node, if any exist.
|
/// Cancel animations for the given node, if any exist.
|
||||||
|
@ -142,17 +143,25 @@ impl Animations {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_running_animations_presence(&self, window: &Window, new_value: bool) {
|
fn update_running_animations_presence(&self, window: &Window, new_value: bool) {
|
||||||
let have_running_animations = self.have_running_animations.get();
|
let had_running_animations = self.has_running_animations.get();
|
||||||
if new_value == have_running_animations {
|
if new_value == had_running_animations {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.have_running_animations.set(new_value);
|
self.has_running_animations.set(new_value);
|
||||||
let state = match new_value {
|
self.handle_animation_presence_or_pending_events_change(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_animation_presence_or_pending_events_change(&self, window: &Window) {
|
||||||
|
let has_running_animations = self.has_running_animations.get();
|
||||||
|
let has_pending_events = !self.pending_events.borrow().is_empty();
|
||||||
|
|
||||||
|
// Do not send the NoAnimationCallbacksPresent state until all pending
|
||||||
|
// animation events are delivered.
|
||||||
|
let state = match has_running_animations || has_pending_events {
|
||||||
true => AnimationsPresentState::AnimationsPresent,
|
true => AnimationsPresentState::AnimationsPresent,
|
||||||
false => AnimationsPresentState::NoAnimationsPresent,
|
false => AnimationsPresentState::NoAnimationsPresent,
|
||||||
};
|
};
|
||||||
|
|
||||||
window.send_to_constellation(ScriptMsg::ChangeRunningAnimationsState(state));
|
window.send_to_constellation(ScriptMsg::ChangeRunningAnimationsState(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,10 +434,13 @@ impl Animations {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_pending_events(&self) {
|
pub(crate) fn send_pending_events(&self, window: &Window) {
|
||||||
// Take all of the events here, in case sending one of these events
|
// Take all of the events here, in case sending one of these events
|
||||||
// triggers adding new events by forcing a layout.
|
// triggers adding new events by forcing a layout.
|
||||||
let events = std::mem::replace(&mut *self.pending_events.borrow_mut(), Vec::new());
|
let events = std::mem::replace(&mut *self.pending_events.borrow_mut(), Vec::new());
|
||||||
|
if events.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for event in events.into_iter() {
|
for event in events.into_iter() {
|
||||||
// We root the node here to ensure that sending this event doesn't
|
// We root the node here to ensure that sending this event doesn't
|
||||||
|
@ -488,6 +500,10 @@ impl Animations {
|
||||||
.fire(node.upcast());
|
.fire(node.upcast());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.pending_events.borrow().is_empty() {
|
||||||
|
self.handle_animation_presence_or_pending_events_change(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1705,11 +1705,11 @@ impl ScriptThread {
|
||||||
// Perform step 11.10 from https://html.spec.whatwg.org/multipage/#event-loops.
|
// Perform step 11.10 from https://html.spec.whatwg.org/multipage/#event-loops.
|
||||||
fn update_animations_and_send_events(&self) {
|
fn update_animations_and_send_events(&self) {
|
||||||
for (_, document) in self.documents.borrow().iter() {
|
for (_, document) in self.documents.borrow().iter() {
|
||||||
document.animations().send_pending_events();
|
document.update_animation_timeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, document) in self.documents.borrow().iter() {
|
for (_, document) in self.documents.borrow().iter() {
|
||||||
document.update_animation_timeline();
|
document.animations().send_pending_events(document.window());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,10 +65,9 @@ GSTREAMER_PLUGINS = [
|
||||||
("gstrtpmanager", "gst-plugins-good"),
|
("gstrtpmanager", "gst-plugins-good"),
|
||||||
("gsttheora", "gst-plugins-base"),
|
("gsttheora", "gst-plugins-base"),
|
||||||
("gsttypefindfunctions", "gst-plugins-base"),
|
("gsttypefindfunctions", "gst-plugins-base"),
|
||||||
("gstvideoconvert", "gst-plugins-base"),
|
("gstvideoconvertscale", "gst-plugins-base"),
|
||||||
("gstvideofilter", "gst-plugins-good"),
|
("gstvideofilter", "gst-plugins-good"),
|
||||||
("gstvideoparsersbad", "gst-plugins-bad"),
|
("gstvideoparsersbad", "gst-plugins-bad"),
|
||||||
("gstvideoscale", "gst-plugins-base"),
|
|
||||||
("gstvorbis", "gst-plugins-base"),
|
("gstvorbis", "gst-plugins-base"),
|
||||||
("gstvolume", "gst-plugins-base"),
|
("gstvolume", "gst-plugins-base"),
|
||||||
("gstvpx", "gst-plugins-good"),
|
("gstvpx", "gst-plugins-good"),
|
||||||
|
|
|
@ -12980,6 +12980,13 @@
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"css-transition-cancel-event.html": [
|
||||||
|
"23400c556d58bb21b78a9cbed3b56028c7d299c3",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"empty-keyframes.html": [
|
"empty-keyframes.html": [
|
||||||
"9f8935fb7f51219bb3ee07335e208a63c9edde81",
|
"9f8935fb7f51219bb3ee07335e208a63c9edde81",
|
||||||
[
|
[
|
||||||
|
|
68
tests/wpt/mozilla/tests/css/css-transition-cancel-event.html
Normal file
68
tests/wpt/mozilla/tests/css/css-transition-cancel-event.html
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const loaded = new Promise(resolve => {
|
||||||
|
addEventListener('load', () => {
|
||||||
|
setTimeout(resolve, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
await loaded;
|
||||||
|
|
||||||
|
const div1 = document.createElement('div');
|
||||||
|
const div2 = document.createElement('div');
|
||||||
|
|
||||||
|
div1.setAttribute('style', 'transition: all .01s linear; ' +
|
||||||
|
'padding-left: 1px');
|
||||||
|
div2.setAttribute('style', 'transition: all 50s linear; ' +
|
||||||
|
'padding-left: 1px');
|
||||||
|
document.body.appendChild(div1);
|
||||||
|
document.body.appendChild(div2);
|
||||||
|
|
||||||
|
getComputedStyle(div1).paddingLeft;
|
||||||
|
getComputedStyle(div2).paddingLeft;
|
||||||
|
div1.style.paddingLeft = '10px';
|
||||||
|
div2.style.paddingLeft = '10px';
|
||||||
|
|
||||||
|
div1.ontransitionend = () => {
|
||||||
|
// Cancel `div2`'s transition
|
||||||
|
div2.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
const watcher = new EventWatcher(t, div2, [ 'transitioncancel' ]);
|
||||||
|
|
||||||
|
// Check that we receive `transitioncancel` very soon.
|
||||||
|
//
|
||||||
|
// This test was written to catch a specific bug where the event loop blocks
|
||||||
|
// waiting for new incoming messages despite still having pending animation-
|
||||||
|
// related events (a `transitioncancel` event in this case) that need to be
|
||||||
|
// processed on a next "rendering opportunity".
|
||||||
|
//
|
||||||
|
// We want to check that the `transitioncancel` event is delivered soon
|
||||||
|
// enough, but we can't rely on test timeout because the timeout timer would
|
||||||
|
// unblock the event loop, resulting in a terribly belate delivery of the
|
||||||
|
// `transitioncancel` event. No matter how short the timeout is, it would
|
||||||
|
// look like the event was delivered just in time.
|
||||||
|
//
|
||||||
|
// Therefore, we are going to check the time taken to receive the event. If
|
||||||
|
// the test times out, we will probably receive the event anyway, but the
|
||||||
|
// duration will be some large value like 9800.
|
||||||
|
const start = Date.now();
|
||||||
|
await watcher.wait_for('transitioncancel');
|
||||||
|
|
||||||
|
assert_less_than(Date.now() - start, 1000);
|
||||||
|
}, 'transitioncancel is delivered promptly');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue