| /* |
| * Copyright 2015 Google Inc. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "cobalt/dom/css_transitions_adapter.h" |
| |
| #include <vector> |
| |
| #include "cobalt/base/tokens.h" |
| #include "cobalt/dom/document.h" |
| #include "cobalt/dom/dom_animatable.h" |
| #include "cobalt/dom/element.h" |
| #include "cobalt/dom/html_element.h" |
| #include "cobalt/dom/pseudo_element.h" |
| #include "cobalt/dom/transition_event.h" |
| #include "cobalt/web_animations/keyframe.h" |
| #include "cobalt/web_animations/keyframe_effect_read_only.h" |
| |
| namespace cobalt { |
| namespace dom { |
| |
| CSSTransitionsAdapter::CSSTransitionsAdapter( |
| const scoped_refptr<dom::DOMAnimatable>& target) |
| : animatable_(target) {} |
| |
| CSSTransitionsAdapter::~CSSTransitionsAdapter() { |
| for (PropertyValueAnimationMap::iterator iter = animation_map_.begin(); |
| iter != animation_map_.end(); ++iter) { |
| delete iter->second; |
| } |
| } |
| |
| void CSSTransitionsAdapter::OnTransitionStarted( |
| const cssom::Transition& transition) { |
| // The process for constructing web animations from CSS transitions is |
| // described here: |
| // https://drafts.csswg.org/date/2015-03-02/web-animations-css-integration/#css-transitions |
| |
| // Create our timing structure using the timing information from the |
| // transition. |
| scoped_refptr<web_animations::AnimationEffectTimingReadOnly> timing_input( |
| new web_animations::AnimationEffectTimingReadOnly( |
| transition.delay(), base::TimeDelta(), |
| web_animations::AnimationEffectTimingReadOnly::kBoth, 0.0, 1.0, |
| transition.duration(), |
| web_animations::AnimationEffectTimingReadOnly::kNormal, |
| cssom::TimingFunction::GetLinear())); |
| |
| // Setup a KeyframeEffect with 2 keyframes, a start and end frame that hold |
| // the start and end transition property values. In general keyframes can |
| // contain values for many properties, but for transitions they will only |
| // ever have the transition's target property. |
| std::vector<web_animations::Keyframe::Data> frames; |
| |
| web_animations::Keyframe::Data start_frame(0.0); |
| start_frame.set_easing(transition.timing_function()); |
| start_frame.AddPropertyValue(transition.target_property(), |
| transition.start_value()); |
| frames.push_back(start_frame); |
| |
| web_animations::Keyframe::Data end_frame(1.0); |
| end_frame.AddPropertyValue(transition.target_property(), |
| transition.end_value()); |
| frames.push_back(end_frame); |
| |
| scoped_refptr<web_animations::KeyframeEffectReadOnly> keyframe_effect( |
| new web_animations::KeyframeEffectReadOnly(timing_input, animatable_, |
| frames)); |
| |
| // Finally setup and play our animation. |
| scoped_refptr<web_animations::Animation> animation( |
| new web_animations::Animation(keyframe_effect, |
| animatable_->GetDefaultTimeline())); |
| |
| // Setup an event handler on the animation so we can watch for when it enters |
| // the after phase, allowing us to then trigger the transitionend event. |
| scoped_ptr<web_animations::Animation::EventHandler> event_handler = |
| animation->AttachEventHandler( |
| base::Bind(&CSSTransitionsAdapter::HandleAnimationEnterAfterPhase, |
| base::Unretained(this), transition)); |
| |
| // Track the animation in our map of all CSS Transitions-created animations. |
| DCHECK(animation_map_.find(transition.target_property()) == |
| animation_map_.end()); |
| |
| animation_map_.insert(std::make_pair( |
| transition.target_property(), |
| new AnimationWithEventHandler(animation, event_handler.Pass()))); |
| |
| animation->Play(); |
| } |
| |
| void CSSTransitionsAdapter::OnTransitionRemoved( |
| const cssom::Transition& transition) { |
| // As described in the process for cancelling/stopping a transition here: |
| // https://drafts.csswg.org/date/2015-03-02/web-animations-css-integration/Overview.html#css-transitions |
| // We find the animation corresponding to the removed transition, cancel it, |
| // and then remove it from our record of animations. |
| PropertyValueAnimationMap::iterator found = |
| animation_map_.find(transition.target_property()); |
| DCHECK(animation_map_.end() != found); |
| |
| found->second->animation->Cancel(); |
| delete found->second; |
| animation_map_.erase(found); |
| } |
| |
| void CSSTransitionsAdapter::HandleAnimationEnterAfterPhase( |
| const cssom::Transition& transition) { |
| // An animation corresponding to a transition has entered the "after phase", |
| // so we should correspondingly fire the transitionend event. |
| // https://drafts.csswg.org/date/2015-03-02/web-animations-css-integration/#css-transitions-events |
| animatable_->GetEventTarget()->DispatchEvent(new TransitionEvent( |
| base::Tokens::transitionend(), transition.target_property(), |
| static_cast<float>(transition.duration().InMillisecondsF()))); |
| } |
| |
| } // namespace dom |
| } // namespace cobalt |