blob: 2acfe0469ffefc23fa3a10a3924123b20c824c1d [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/animation/TimingInput.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/unrestricted_double_or_keyframe_animation_options.h"
#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "core/animation/AnimationInputHelpers.h"
#include "core/animation/KeyframeEffectOptions.h"
namespace blink {
void TimingInput::SetStartDelay(Timing& timing, double start_delay) {
if (std::isfinite(start_delay))
timing.start_delay = start_delay / 1000;
else
timing.start_delay = Timing::Defaults().start_delay;
}
void TimingInput::SetEndDelay(Timing& timing, double end_delay) {
if (std::isfinite(end_delay))
timing.end_delay = end_delay / 1000;
else
timing.end_delay = Timing::Defaults().end_delay;
}
void TimingInput::SetFillMode(Timing& timing, const String& fill_mode) {
if (fill_mode == "none") {
timing.fill_mode = Timing::FillMode::NONE;
} else if (fill_mode == "backwards") {
timing.fill_mode = Timing::FillMode::BACKWARDS;
} else if (fill_mode == "both") {
timing.fill_mode = Timing::FillMode::BOTH;
} else if (fill_mode == "forwards") {
timing.fill_mode = Timing::FillMode::FORWARDS;
} else {
timing.fill_mode = Timing::Defaults().fill_mode;
}
}
bool TimingInput::SetIterationStart(Timing& timing,
double iteration_start,
ExceptionState& exception_state) {
DCHECK(std::isfinite(iteration_start));
if (std::isnan(iteration_start) || iteration_start < 0) {
exception_state.ThrowTypeError("iterationStart must be non-negative.");
return false;
}
timing.iteration_start = iteration_start;
return true;
}
bool TimingInput::SetIterationCount(Timing& timing,
double iteration_count,
ExceptionState& exception_state) {
if (std::isnan(iteration_count) || iteration_count < 0) {
exception_state.ThrowTypeError("iterationCount must be non-negative.");
return false;
}
timing.iteration_count = iteration_count;
return true;
}
bool TimingInput::SetIterationDuration(
Timing& timing,
const UnrestrictedDoubleOrString& iteration_duration,
ExceptionState& exception_state) {
static const char* error_message = "duration must be non-negative or auto.";
if (iteration_duration.IsUnrestrictedDouble()) {
double duration_number = iteration_duration.GetAsUnrestrictedDouble();
if (std::isnan(duration_number) || duration_number < 0) {
exception_state.ThrowTypeError(error_message);
return false;
}
timing.iteration_duration = duration_number / 1000;
return true;
}
if (iteration_duration.GetAsString() != "auto") {
exception_state.ThrowTypeError(error_message);
return false;
}
timing.iteration_duration = Timing::Defaults().iteration_duration;
return true;
}
void TimingInput::SetPlaybackRate(Timing& timing, double playback_rate) {
if (std::isfinite(playback_rate))
timing.playback_rate = playback_rate;
else
timing.playback_rate = Timing::Defaults().playback_rate;
}
void TimingInput::SetPlaybackDirection(Timing& timing,
const String& direction) {
if (direction == "reverse") {
timing.direction = Timing::PlaybackDirection::REVERSE;
} else if (direction == "alternate") {
timing.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
} else if (direction == "alternate-reverse") {
timing.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
} else {
timing.direction = Timing::Defaults().direction;
}
}
bool TimingInput::SetTimingFunction(Timing& timing,
const String& timing_function_string,
Document* document,
ExceptionState& exception_state) {
if (scoped_refptr<TimingFunction> timing_function =
AnimationInputHelpers::ParseTimingFunction(
timing_function_string, document, exception_state)) {
timing.timing_function = timing_function;
return true;
}
return false;
}
bool TimingInput::Convert(
const UnrestrictedDoubleOrKeyframeEffectOptions& options,
Timing& timing_output,
Document* document,
ExceptionState& exception_state) {
if (options.IsKeyframeEffectOptions()) {
return Convert(options.GetAsKeyframeEffectOptions(), timing_output,
document, exception_state);
} else if (options.IsUnrestrictedDouble()) {
return Convert(options.GetAsUnrestrictedDouble(), timing_output,
exception_state);
} else if (options.IsNull()) {
return true;
}
NOTREACHED();
return false;
}
bool TimingInput::Convert(
const UnrestrictedDoubleOrKeyframeAnimationOptions& options,
Timing& timing_output,
Document* document,
ExceptionState& exception_state) {
if (options.IsKeyframeAnimationOptions()) {
return Convert(options.GetAsKeyframeAnimationOptions(), timing_output,
document, exception_state);
} else if (options.IsUnrestrictedDouble()) {
return Convert(options.GetAsUnrestrictedDouble(), timing_output,
exception_state);
} else if (options.IsNull()) {
return true;
}
NOTREACHED();
return false;
}
bool TimingInput::Convert(const KeyframeEffectOptions& timing_input,
Timing& timing_output,
Document* document,
ExceptionState& exception_state) {
SetStartDelay(timing_output, timing_input.delay());
SetEndDelay(timing_output, timing_input.endDelay());
SetFillMode(timing_output, timing_input.fill());
if (!SetIterationStart(timing_output, timing_input.iterationStart(),
exception_state))
return false;
if (!SetIterationCount(timing_output, timing_input.iterations(),
exception_state))
return false;
if (!SetIterationDuration(timing_output, timing_input.duration(),
exception_state))
return false;
SetPlaybackRate(timing_output, 1.0);
SetPlaybackDirection(timing_output, timing_input.direction());
if (!SetTimingFunction(timing_output, timing_input.easing(), document,
exception_state))
return false;
timing_output.AssertValid();
return true;
}
bool TimingInput::Convert(const KeyframeAnimationOptions& timing_input,
Timing& timing_output,
Document* document,
ExceptionState& exception_state) {
// The "id" field isn't used, so upcast to KeyframeEffectOptions.
const KeyframeEffectOptions* const timing_input_ptr = &timing_input;
return Convert(*timing_input_ptr, timing_output, document, exception_state);
}
bool TimingInput::Convert(double duration,
Timing& timing_output,
ExceptionState& exception_state) {
DCHECK(timing_output == Timing::Defaults());
return SetIterationDuration(
timing_output,
UnrestrictedDoubleOrString::FromUnrestrictedDouble(duration),
exception_state);
}
} // namespace blink