// Copyright (c) 2012 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 "ui/gfx/animation/tween.h" #include <math.h> #if defined(OS_WIN) #include <float.h> #endif #include <algorithm> #include "base/basictypes.h" #include "base/logging.h" #include "ui/gfx/safe_integer_conversions.h" namespace gfx { // static double Tween::CalculateValue(Tween::Type type, double state) { DCHECK_GE(state, 0); DCHECK_LE(state, 1); switch (type) { case EASE_IN: return pow(state, 2); case EASE_IN_2: return pow(state, 4); case EASE_IN_OUT: if (state < 0.5) return pow(state * 2, 2) / 2.0; return 1.0 - (pow((state - 1.0) * 2, 2) / 2.0); case FAST_IN_OUT: return (pow(state - 0.5, 3) + 0.125) / 0.25; case LINEAR: return state; case EASE_OUT_SNAP: state = 0.95 * (1.0 - pow(1.0 - state, 2)); return state; case EASE_OUT: return 1.0 - pow(1.0 - state, 2); case SMOOTH_IN_OUT: return sin(state); case ZERO: return 0; } NOTREACHED(); return state; } namespace { uint8 FloatToColorByte(float f) { return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255); } uint8 BlendColorComponents(uint8 start, uint8 target, float start_alpha, float target_alpha, float blended_alpha, double progress) { // Since progress can be outside [0, 1], blending can produce a value outside // [0, 255]. float blended_premultiplied = Tween::FloatValueBetween( progress, start / 255.f * start_alpha, target / 255.f * target_alpha); return FloatToColorByte(blended_premultiplied / blended_alpha); } } // namespace // static SkColor Tween::ColorValueBetween(double value, SkColor start, SkColor target) { float start_a = SkColorGetA(start) / 255.f; float target_a = SkColorGetA(target) / 255.f; float blended_a = FloatValueBetween(value, start_a, target_a); if (blended_a <= 0.f) return SkColorSetARGB(0, 0, 0, 0); blended_a = std::min(blended_a, 1.f); uint8 blended_r = BlendColorComponents(SkColorGetR(start), SkColorGetR(target), start_a, target_a, blended_a, value); uint8 blended_g = BlendColorComponents(SkColorGetG(start), SkColorGetG(target), start_a, target_a, blended_a, value); uint8 blended_b = BlendColorComponents(SkColorGetB(start), SkColorGetB(target), start_a, target_a, blended_a, value); return SkColorSetARGB( FloatToColorByte(blended_a), blended_r, blended_g, blended_b); } // static double Tween::DoubleValueBetween(double value, double start, double target) { return start + (target - start) * value; } // static float Tween::FloatValueBetween(double value, float start, float target) { return static_cast<float>(start + (target - start) * value); } // static int Tween::IntValueBetween(double value, int start, int target) { if (start == target) return start; double delta = static_cast<double>(target - start); if (delta < 0) delta--; else delta++; #if defined(OS_WIN) return start + static_cast<int>(value * _nextafter(delta, 0)); #else return start + static_cast<int>(value * nextafter(delta, 0)); #endif } //static int Tween::LinearIntValueBetween(double value, int start, int target) { return std::floor(0.5 + DoubleValueBetween(value, start, target)); } // static gfx::Rect Tween::RectValueBetween(double value, const gfx::Rect& start_bounds, const gfx::Rect& target_bounds) { return gfx::Rect( LinearIntValueBetween(value, start_bounds.x(), target_bounds.x()), LinearIntValueBetween(value, start_bounds.y(), target_bounds.y()), LinearIntValueBetween(value, start_bounds.width(), target_bounds.width()), LinearIntValueBetween( value, start_bounds.height(), target_bounds.height())); } // static gfx::Transform Tween::TransformValueBetween( double value, const gfx::Transform& start_transform, const gfx::Transform& end_transform) { if (value >= 1.0) return end_transform; if (value <= 0.0) return start_transform; gfx::Transform to_return = end_transform; to_return.Blend(start_transform, value); return to_return; } } // namespace gfx