blob: 80b3af5367cc94bcb94bf81b156fd02233cdb515 [file] [log] [blame]
/*
* 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