Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(525)

Side by Side Diff: services/view_manager/scheduled_animation_group.cc

Issue 772893004: Adds constants and runner for animations (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Merge Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/view_manager/scheduled_animation_group.h"
6
7 #include <set>
8
9 #include "mojo/converters/geometry/geometry_type_converters.h"
10 #include "services/view_manager/server_view.h"
11
12 namespace mojo {
13 namespace service {
14 namespace {
15
16 using Sequences = std::vector<ScheduledAnimationSequence>;
17
18 // Gets the value of |property| from |view| into |value|.
19 void GetValueFromView(const ServerView* view,
20 AnimationProperty property,
21 ScheduledAnimationValue* value) {
22 switch (property) {
23 case ANIMATION_PROPERTY_NONE:
24 NOTREACHED();
25 break;
26 case ANIMATION_PROPERTY_OPACITY:
27 value->float_value = view->opacity();
28 break;
29 case ANIMATION_PROPERTY_TRANSFORM:
30 value->transform = view->transform();
31 break;
32 }
33 }
34
35 // Sets the value of |property| from |value| into |view|.
36 void SetViewPropertyFromValue(ServerView* view,
37 AnimationProperty property,
38 const ScheduledAnimationValue& value) {
39 switch (property) {
40 case ANIMATION_PROPERTY_NONE:
41 break;
42 case ANIMATION_PROPERTY_OPACITY:
43 view->SetOpacity(value.float_value);
44 break;
45 case ANIMATION_PROPERTY_TRANSFORM:
46 view->SetTransform(value.transform);
47 break;
48 }
49 }
50
51 // Sets the value of |property| into |view| between two points.
52 void SetViewPropertyFromValueBetween(ServerView* view,
53 AnimationProperty property,
54 double value,
55 gfx::Tween::Type tween_type,
56 const ScheduledAnimationValue& start,
57 const ScheduledAnimationValue& target) {
58 const double tween_value = gfx::Tween::CalculateValue(tween_type, value);
59 switch (property) {
60 case ANIMATION_PROPERTY_NONE:
61 break;
62 case ANIMATION_PROPERTY_OPACITY:
63 view->SetOpacity(gfx::Tween::FloatValueBetween(
64 tween_value, start.float_value, target.float_value));
65 break;
66 case ANIMATION_PROPERTY_TRANSFORM:
67 view->SetTransform(gfx::Tween::TransformValueBetween(
68 tween_value, start.transform, target.transform));
69 break;
70 }
71 }
72
73 gfx::Tween::Type AnimationTypeToTweenType(AnimationTweenType type) {
74 switch (type) {
75 case ANIMATION_TWEEN_TYPE_LINEAR:
76 return gfx::Tween::LINEAR;
77 case ANIMATION_TWEEN_TYPE_EASE_IN:
78 return gfx::Tween::EASE_IN;
79 case ANIMATION_TWEEN_TYPE_EASE_OUT:
80 return gfx::Tween::EASE_OUT;
81 case ANIMATION_TWEEN_TYPE_EASE_IN_OUT:
82 return gfx::Tween::EASE_IN_OUT;
83 }
84 }
85
86 void ConvertToScheduledValue(const AnimationValue& transport_value,
87 ScheduledAnimationValue* value) {
88 value->float_value = transport_value.float_value;
89 value->transform = transport_value.transform.To<gfx::Transform>();
90 }
91
92 void ConvertToScheduledElement(const AnimationElement& transport_element,
93 ScheduledAnimationElement* element) {
94 element->property = transport_element.property;
95 element->duration =
96 base::TimeDelta::FromMicroseconds(transport_element.duration);
97 element->tween_type = AnimationTypeToTweenType(transport_element.tween_type);
98 if (transport_element.property != ANIMATION_PROPERTY_NONE) {
99 if (transport_element.start_value.get()) {
100 element->is_start_valid = true;
101 ConvertToScheduledValue(*transport_element.start_value,
102 &(element->start_value));
103 } else {
104 element->is_start_valid = false;
105 }
106 ConvertToScheduledValue(*transport_element.target_value,
107 &(element->target_value));
108 }
109 }
110
111 bool IsAnimationValueValid(AnimationProperty property,
112 const AnimationValue& value) {
113 switch (property) {
114 case ANIMATION_PROPERTY_NONE:
115 NOTREACHED();
116 return false;
117 case ANIMATION_PROPERTY_OPACITY:
118 return value.float_value >= 0.f && value.float_value <= 1.f;
119 case ANIMATION_PROPERTY_TRANSFORM:
120 return value.transform.get() && value.transform->matrix.size() == 16u;
121 }
122 }
123
124 bool IsAnimationElementValid(const AnimationElement& element) {
125 if (element.property == ANIMATION_PROPERTY_NONE)
126 return true; // None is a pause and doesn't need any values.
127 if (element.start_value.get() &&
128 !IsAnimationValueValid(element.property, *element.start_value))
129 return false;
130 // For all other properties we require a target.
131 return element.target_value.get() &&
132 IsAnimationValueValid(element.property, *element.target_value);
133 }
134
135 bool IsAnimationSequenceValid(const AnimationSequence& sequence) {
136 if (sequence.elements.size() == 0u)
137 return false;
138
139 for (size_t i = 0; i < sequence.elements.size(); ++i) {
140 if (!IsAnimationElementValid(*sequence.elements[i]))
141 return false;
142 }
143 return true;
144 }
145
146 bool IsAnimationGroupValid(const AnimationGroup& transport_group) {
147 if (transport_group.sequences.size() == 0u)
148 return false;
149 for (size_t i = 0; i < transport_group.sequences.size(); ++i) {
150 if (!IsAnimationSequenceValid(*transport_group.sequences[i]))
151 return false;
152 }
153 return true;
154 }
155
156 // If the start value for |element| isn't valid, the value for the property
157 // is obtained from |view| and placed into |element|.
158 void GetStartValueFromViewIfNecessary(const ServerView* view,
159 ScheduledAnimationElement* element) {
160 if (element->property != ANIMATION_PROPERTY_NONE &&
161 !element->is_start_valid) {
162 GetValueFromView(view, element->property, &(element->start_value));
163 }
164 }
165
166 void GetScheduledAnimationProperties(const Sequences& sequences,
167 std::set<AnimationProperty>* properties) {
168 for (const ScheduledAnimationSequence& sequence : sequences) {
169 for (const ScheduledAnimationElement& element : sequence.elements)
170 properties->insert(element.property);
171 }
172 }
173
174 void SetPropertyToTargetProperty(ServerView* view,
175 AnimationProperty property,
176 const Sequences& sequences) {
177 // NOTE: this doesn't deal with |cycle_count| quite right, but I'm honestly
178 // not sure we really want to support the same property in multiple sequences
179 // animating at once so I'm not dealing.
180 base::TimeDelta max_end_duration;
181 scoped_ptr<ScheduledAnimationValue> value;
182 for (const ScheduledAnimationSequence& sequence : sequences) {
183 base::TimeDelta duration;
184 for (const ScheduledAnimationElement& element : sequence.elements) {
185 if (element.property != property)
186 continue;
187
188 duration += element.duration;
189 if (duration > max_end_duration) {
190 max_end_duration = duration;
191 value.reset(new ScheduledAnimationValue(element.target_value));
192 }
193 }
194 }
195 if (value.get())
196 SetViewPropertyFromValue(view, property, *value);
197 }
198
199 void ConvertSequenceToScheduled(const AnimationSequence& transport_sequence,
200 base::TimeTicks now,
201 ScheduledAnimationSequence* sequence) {
202 sequence->run_until_stopped = transport_sequence.cycle_count == 0u;
203 sequence->cycle_count = transport_sequence.cycle_count;
204 DCHECK_NE(0u, transport_sequence.elements.size());
205 sequence->elements.resize(transport_sequence.elements.size());
206
207 base::TimeTicks element_start_time = now;
208 for (size_t i = 0; i < transport_sequence.elements.size(); ++i) {
209 ConvertToScheduledElement(*(transport_sequence.elements[i].get()),
210 &(sequence->elements[i]));
211 sequence->elements[i].start_time = element_start_time;
212 sequence->duration += sequence->elements[i].duration;
213 element_start_time += sequence->elements[i].duration;
214 }
215 }
216
217 bool AdvanceSequence(ServerView* view,
218 ScheduledAnimationSequence* sequence,
219 base::TimeTicks now) {
220 ScheduledAnimationElement* element =
221 &(sequence->elements[sequence->current_index]);
222 while (element->start_time + element->duration < now) {
223 SetViewPropertyFromValue(view, element->property, element->target_value);
224 if (++sequence->current_index == sequence->elements.size()) {
225 if (!sequence->run_until_stopped && --sequence->cycle_count == 0) {
226 SetViewPropertyFromValue(view, element->property,
227 element->target_value);
228 return false;
229 }
230
231 sequence->current_index = 0;
232 }
233 sequence->elements[sequence->current_index].start_time =
234 element->start_time + element->duration;
235 element = &(sequence->elements[sequence->current_index]);
236 GetStartValueFromViewIfNecessary(view, element);
237
238 // It's possible for the delta between now and |last_tick_time_| to be very
239 // big (could happen if machine sleeps and is woken up much later). Normally
240 // the repeat count is smallish, so we don't bother optimizing it. OTOH if
241 // a sequence repeats forever we optimize it lest we get stuck in this loop
242 // for a very long time.
243 if (sequence->run_until_stopped && sequence->current_index == 0) {
244 element->start_time =
245 now - base::TimeDelta::FromMicroseconds(
246 (now - element->start_time).InMicroseconds() %
247 sequence->duration.InMicroseconds());
248 }
249 }
250 return true;
251 }
252
253 } // namespace
254
255 ScheduledAnimationValue::ScheduledAnimationValue() {
256 }
257 ScheduledAnimationValue::~ScheduledAnimationValue() {
258 }
259
260 ScheduledAnimationElement::ScheduledAnimationElement()
261 : property(ANIMATION_PROPERTY_OPACITY),
262 tween_type(gfx::Tween::EASE_IN),
263 is_start_valid(false) {
264 }
265 ScheduledAnimationElement::~ScheduledAnimationElement() {
266 }
267
268 ScheduledAnimationSequence::ScheduledAnimationSequence()
269 : run_until_stopped(false), cycle_count(0), current_index(0u) {
270 }
271 ScheduledAnimationSequence::~ScheduledAnimationSequence() {
272 }
273
274 ScheduledAnimationGroup::~ScheduledAnimationGroup() {
275 }
276
277 // static
278 scoped_ptr<ScheduledAnimationGroup> ScheduledAnimationGroup::Create(
279 ServerView* view,
280 base::TimeTicks now,
281 uint32_t id,
282 const AnimationGroup& transport_group) {
283 if (!IsAnimationGroupValid(transport_group))
284 return nullptr;
285
286 scoped_ptr<ScheduledAnimationGroup> group(
287 new ScheduledAnimationGroup(view, id, now));
288 group->sequences_.resize(transport_group.sequences.size());
289 for (size_t i = 0; i < transport_group.sequences.size(); ++i) {
290 const AnimationSequence& transport_sequence(
291 *(transport_group.sequences[i]));
292 DCHECK_NE(0u, transport_sequence.elements.size());
293 ConvertSequenceToScheduled(transport_sequence, now, &group->sequences_[i]);
294 }
295 return group.Pass();
296 }
297
298 void ScheduledAnimationGroup::ObtainStartValues() {
299 for (ScheduledAnimationSequence& sequence : sequences_)
300 GetStartValueFromViewIfNecessary(view_, &(sequence.elements[0]));
301 }
302
303 void ScheduledAnimationGroup::SetValuesToTargetValuesForPropertiesNotIn(
304 const ScheduledAnimationGroup& other) {
305 std::set<AnimationProperty> our_properties;
306 GetScheduledAnimationProperties(sequences_, &our_properties);
307
308 std::set<AnimationProperty> other_properties;
309 GetScheduledAnimationProperties(other.sequences_, &other_properties);
310
311 for (AnimationProperty property : our_properties) {
312 if (other_properties.count(property) == 0 &&
313 property != ANIMATION_PROPERTY_NONE) {
314 SetPropertyToTargetProperty(view_, property, sequences_);
315 }
316 }
317 }
318
319 bool ScheduledAnimationGroup::Tick(base::TimeTicks time) {
320 for (Sequences::iterator i = sequences_.begin(); i != sequences_.end();) {
321 if (!AdvanceSequence(view_, &(*i), time)) {
322 i = sequences_.erase(i);
323 continue;
324 }
325 const ScheduledAnimationElement& active_element(
326 i->elements[i->current_index]);
327 const double percent =
328 (time - active_element.start_time).InMillisecondsF() /
329 active_element.duration.InMillisecondsF();
330 SetViewPropertyFromValueBetween(
331 view_, active_element.property, percent, active_element.tween_type,
332 active_element.start_value, active_element.target_value);
333 ++i;
334 }
335 return sequences_.empty();
336 }
337
338 ScheduledAnimationGroup::ScheduledAnimationGroup(ServerView* view,
339 uint32_t id,
340 base::TimeTicks time_scheduled)
341 : view_(view), id_(id), time_scheduled_(time_scheduled) {
342 }
343
344 } // namespace service
345 } // namespace mojo
OLDNEW
« no previous file with comments | « services/view_manager/scheduled_animation_group.h ('k') | services/view_manager/scheduled_animation_group_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698