Skip to content

Commit 0b67b21

Browse files
committed
style: Add a new Timer structure to the shared style context, and basic infrastructure for controlling animations.
1 parent 2e68821 commit 0b67b21

20 files changed

Lines changed: 178 additions & 26 deletions

File tree

components/layout/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ smallvec = "0.1"
3838
string_cache = {version = "0.2.20", features = ["heap_size"]}
3939
style = {path = "../style"}
4040
style_traits = {path = "../style_traits"}
41-
time = "0.1"
4241
unicode-bidi = "0.2"
4342
unicode-script = {version = "0.1", features = ["harfbuzz"]}
4443
url = {version = "1.0.0", features = ["heap_size"]}

components/layout/animation.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
1414
use std::collections::HashMap;
1515
use std::sync::mpsc::Receiver;
1616
use style::animation::{Animation, update_style_for_animation};
17-
use time;
17+
use style::timer::Timer;
1818

1919
/// Processes any new animations that were discovered after style recalculation.
2020
/// Also expire any old animations that have completed, inserting them into
@@ -23,7 +23,8 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
2323
running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
2424
expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
2525
new_animations_receiver: &Receiver<Animation>,
26-
pipeline_id: PipelineId) {
26+
pipeline_id: PipelineId,
27+
timer: &Timer) {
2728
let mut new_running_animations = vec![];
2829
while let Ok(animation) = new_animations_receiver.try_recv() {
2930
let mut should_push = true;
@@ -37,7 +38,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
3738
if let Animation::Keyframes(_, ref anim_name, ref mut anim_state) = *anim {
3839
if *name == *anim_name {
3940
debug!("update_animation_state: Found other animation {}", name);
40-
anim_state.update_from_other(&state);
41+
anim_state.update_from_other(&state, timer);
4142
should_push = false;
4243
break;
4344
}
@@ -57,7 +58,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
5758
return
5859
}
5960

60-
let now = time::precise_time_s();
61+
let now = timer.seconds();
6162
// Expire old running animations.
6263
//
6364
// TODO: Do not expunge Keyframes animations, since we need that state if

components/layout/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ extern crate smallvec;
5050
#[macro_use(atom, ns)] extern crate string_cache;
5151
extern crate style;
5252
extern crate style_traits;
53-
extern crate time;
5453
extern crate unicode_bidi;
5554
extern crate unicode_script;
5655
extern crate url;

components/layout_thread/lib.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,13 @@ use style::refcell::RefCell;
110110
use style::selector_matching::Stylist;
111111
use style::servo_selector_impl::USER_OR_USER_AGENT_STYLESHEETS;
112112
use style::stylesheets::{Stylesheet, CSSRuleIteratorExt};
113+
use style::timer::Timer;
113114
use style::workqueue::WorkQueue;
114115
use url::Url;
115116
use util::geometry::MAX_RECT;
116117
use util::ipc::OptionalIpcSender;
117118
use util::opts;
119+
use util::prefs::PREFS;
118120
use util::thread;
119121
use util::thread_state;
120122

@@ -226,6 +228,10 @@ pub struct LayoutThread {
226228

227229
// Webrender interface, if enabled.
228230
webrender_api: Option<webrender_traits::RenderApi>,
231+
232+
/// The timer object to control the timing of the animations. This should
233+
/// only be a test-mode timer during testing for animations.
234+
timer: Timer,
229235
}
230236

231237
impl LayoutThreadFactory for LayoutThread {
@@ -459,13 +465,20 @@ impl LayoutThread {
459465
offset_parent_response: OffsetParentResponse::empty(),
460466
margin_style_response: MarginStyleResponse::empty(),
461467
stacking_context_scroll_offsets: HashMap::new(),
462-
})),
463-
error_reporter: CSSErrorReporter {
464-
pipelineid: id,
465-
script_chan: Arc::new(Mutex::new(script_chan)),
466-
},
467-
webrender_image_cache:
468-
Arc::new(RwLock::new(HashMap::with_hasher(Default::default()))),
468+
})),
469+
error_reporter: CSSErrorReporter {
470+
pipelineid: id,
471+
script_chan: Arc::new(Mutex::new(script_chan)),
472+
},
473+
webrender_image_cache:
474+
Arc::new(RwLock::new(HashMap::with_hasher(Default::default()))),
475+
timer:
476+
if PREFS.get("layout.animations.test.enabled")
477+
.as_boolean().unwrap_or(false) {
478+
Timer::test_mode()
479+
} else {
480+
Timer::new()
481+
},
469482
}
470483
}
471484

@@ -501,6 +514,7 @@ impl LayoutThread {
501514
expired_animations: self.expired_animations.clone(),
502515
error_reporter: self.error_reporter.clone(),
503516
local_context_creation_data: Mutex::new(local_style_context_creation_data),
517+
timer: self.timer.clone(),
504518
},
505519
image_cache_thread: self.image_cache_thread.clone(),
506520
image_cache_sender: Mutex::new(self.image_cache_sender.clone()),
@@ -653,6 +667,9 @@ impl LayoutThread {
653667
let _rw_data = possibly_locked_rw_data.lock();
654668
sender.send(self.epoch).unwrap();
655669
},
670+
Msg::AdvanceClockMs(how_many) => {
671+
self.handle_advance_clock_ms(how_many, possibly_locked_rw_data);
672+
}
656673
Msg::GetWebFontLoadState(sender) => {
657674
let _rw_data = possibly_locked_rw_data.lock();
658675
let outstanding_web_fonts = self.outstanding_web_fonts.load(Ordering::SeqCst);
@@ -795,6 +812,14 @@ impl LayoutThread {
795812
possibly_locked_rw_data.block(rw_data);
796813
}
797814

815+
/// Advances the animation clock of the document.
816+
fn handle_advance_clock_ms<'a, 'b>(&mut self,
817+
how_many_ms: i32,
818+
possibly_locked_rw_data: &mut RwData<'a, 'b>) {
819+
self.timer.increment(how_many_ms as f64 / 1000.0);
820+
self.tick_all_animations(possibly_locked_rw_data);
821+
}
822+
798823
/// Sets quirks mode for the document, causing the quirks mode stylesheet to be used.
799824
fn handle_set_quirks_mode<'a, 'b>(&self, possibly_locked_rw_data: &mut RwData<'a, 'b>) {
800825
let mut rw_data = possibly_locked_rw_data.lock();
@@ -1350,7 +1375,8 @@ impl LayoutThread {
13501375
&mut *self.running_animations.write().unwrap(),
13511376
&mut *self.expired_animations.write().unwrap(),
13521377
&self.new_animations_receiver,
1353-
self.id);
1378+
self.id,
1379+
&self.timer);
13541380

13551381
profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
13561382
self.profiler_metadata(),

components/script/dom/testbinding.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,10 @@ impl TestBindingMethods for TestBinding {
581581
}
582582
}
583583

584+
fn AdvanceClock(&self, ms: i32) {
585+
self.global().r().as_window().advance_animation_clock(ms);
586+
}
587+
584588
fn Panic(&self) { panic!("explicit panic from script") }
585589
}
586590

components/script/dom/webidls/TestBinding.webidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ interface TestBinding {
424424
static void prefControlledStaticMethodDisabled();
425425
[Pref="dom.testbinding.prefcontrolled.enabled"]
426426
const unsigned short prefControlledConstDisabled = 0;
427+
[Pref="layout.animations.test.enabled"]
428+
void advanceClock(long millis);
427429

428430
[Pref="dom.testbinding.prefcontrolled2.enabled"]
429431
readonly attribute boolean prefControlledAttributeEnabled;

components/script/dom/window.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,12 @@ impl Window {
10301030
recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()))
10311031
}
10321032

1033+
/// Advances the layout animation clock by `delta` milliseconds, and then
1034+
/// forces a reflow.
1035+
pub fn advance_animation_clock(&self, delta: i32) {
1036+
self.layout_chan.send(Msg::AdvanceClockMs(delta)).unwrap();
1037+
}
1038+
10331039
/// Reflows the page unconditionally if possible and not suppressed. This
10341040
/// method will wait for the layout thread to complete (but see the `TODO`
10351041
/// below). If there is no window size yet, the page is presumed invisible

components/script_layout_interface/message.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ pub enum Msg {
4040
/// Requests that the layout thread render the next frame of all animations.
4141
TickAnimations,
4242

43+
/// Updates layout's timer for animation testing from script.
44+
///
45+
/// The inner field is the number of *milliseconds* to advance.
46+
AdvanceClockMs(i32),
47+
4348
/// Requests that the layout thread reflow with a newly-loaded Web font.
4449
ReflowWithNewlyLoadedWebFont,
4550

components/servo/Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/style/animation.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use selectors::matching::DeclarationBlock;
2020
use std::sync::Arc;
2121
use std::sync::mpsc::Sender;
2222
use string_cache::Atom;
23-
use time;
23+
use timer::Timer;
2424
use values::computed::Time;
2525

2626
/// This structure represents a keyframes animation current iteration state.
@@ -122,7 +122,9 @@ impl KeyframesAnimationState {
122122
///
123123
/// There are some bits of state we can't just replace, over all taking in
124124
/// account times, so here's that logic.
125-
pub fn update_from_other(&mut self, other: &Self) {
125+
pub fn update_from_other(&mut self,
126+
other: &Self,
127+
timer: &Timer) {
126128
use self::KeyframesRunningState::*;
127129

128130
debug!("KeyframesAnimationState::update_from_other({:?}, {:?})", self, other);
@@ -146,11 +148,11 @@ impl KeyframesAnimationState {
146148
// If we're pausing the animation, compute the progress value.
147149
match (&mut self.running_state, old_running_state) {
148150
(&mut Running, Paused(progress))
149-
=> new_started_at = time::precise_time_s() - (self.duration * progress),
151+
=> new_started_at = timer.seconds() - (self.duration * progress),
150152
(&mut Paused(ref mut new), Paused(old))
151153
=> *new = old,
152154
(&mut Paused(ref mut progress), Running)
153-
=> *progress = (time::precise_time_s() - old_started_at) / old_duration,
155+
=> *progress = (timer.seconds() - old_started_at) / old_duration,
154156
_ => {},
155157
}
156158

@@ -341,7 +343,8 @@ impl PropertyAnimation {
341343
pub fn start_transitions_if_applicable(new_animations_sender: &Sender<Animation>,
342344
node: OpaqueNode,
343345
old_style: &ComputedValues,
344-
new_style: &mut Arc<ComputedValues>)
346+
new_style: &mut Arc<ComputedValues>,
347+
timer: &Timer)
345348
-> bool {
346349
let mut had_animations = false;
347350
for i in 0..new_style.get_box().transition_property_count() {
@@ -355,7 +358,7 @@ pub fn start_transitions_if_applicable(new_animations_sender: &Sender<Animation>
355358

356359
// Kick off the animation.
357360
let box_style = new_style.get_box();
358-
let now = time::precise_time_s();
361+
let now = timer.seconds();
359362
let start_time =
360363
now + (box_style.transition_delay_mod(i).seconds() as f64);
361364
new_animations_sender
@@ -424,7 +427,7 @@ pub fn maybe_start_animations(context: &SharedStyleContext,
424427
}
425428

426429
let delay = box_style.animation_delay_mod(i).seconds();
427-
let now = time::precise_time_s();
430+
let now = context.timer.seconds();
428431
let animation_start = now + delay as f64;
429432
let duration = box_style.animation_duration_mod(i).seconds();
430433
let iteration_state = match box_style.animation_iteration_count_mod(i) {
@@ -497,7 +500,7 @@ where Damage: TRestyleDamage {
497500
match *animation {
498501
Animation::Transition(_, start_time, ref frame, _) => {
499502
debug!("update_style_for_animation: transition found");
500-
let now = time::precise_time_s();
503+
let now = context.timer.seconds();
501504
let mut new_style = (*style).clone();
502505
let updated_style = update_style_for_animation_frame(&mut new_style,
503506
now, start_time,
@@ -516,7 +519,7 @@ where Damage: TRestyleDamage {
516519
let started_at = state.started_at;
517520

518521
let now = match state.running_state {
519-
KeyframesRunningState::Running => time::precise_time_s(),
522+
KeyframesRunningState::Running => context.timer.seconds(),
520523
KeyframesRunningState::Paused(progress) => started_at + duration * progress,
521524
};
522525

0 commit comments

Comments
 (0)