Index: ui/gfx/interpolated_transform.cc |
diff --git a/ui/gfx/interpolated_transform.cc b/ui/gfx/interpolated_transform.cc |
index 1f37f84909a35d6e12c290aad8fb1e614474af05..6378082962bcb9492af12df0e7ad1c7da38bb72f 100644 |
--- a/ui/gfx/interpolated_transform.cc |
+++ b/ui/gfx/interpolated_transform.cc |
@@ -4,9 +4,17 @@ |
#include "ui/gfx/interpolated_transform.h" |
+#include <cmath> |
+ |
#include "base/logging.h" |
#include "ui/base/animation/tween.h" |
+namespace { |
+ |
+static const float EPSILON = 1e-6f; |
+ |
+} // namespace |
+ |
namespace ui { |
/////////////////////////////////////////////////////////////////////////////// |
@@ -38,6 +46,61 @@ void InterpolatedTransform::SetChild(InterpolatedTransform* child) { |
child_.reset(child); |
} |
+bool InterpolatedTransform::FactorTRS(const ui::Transform& transform, |
+ gfx::Point* translation, |
+ float* rotation, |
+ gfx::Point3f* scale) { |
+ const SkMatrix44& m = transform.matrix(); |
+ float m00 = m.get(0, 0); |
+ float m01 = m.get(0, 1); |
+ float m10 = m.get(1, 0); |
+ float m11 = m.get(1, 1); |
+ |
+ // A factorable 2D TRS matrix must be of the form: |
+ // [ sx*cos_theta -(sy*sin_theta) 0 tx ] |
+ // [ sx*sin_theta sy*cos_theta 0 ty ] |
+ // [ 0 0 1 0 ] |
+ // [ 0 0 0 1 ] |
+ if (m.get(0, 2) != 0 || |
+ m.get(1, 2) != 0 || |
+ m.get(2, 0) != 0 || |
+ m.get(2, 1) != 0 || |
+ m.get(2, 2) != 1 || |
+ m.get(2, 3) != 0 || |
+ m.get(3, 0) != 0 || |
+ m.get(3, 1) != 0 || |
+ m.get(3, 2) != 0 || |
+ m.get(3, 3) != 1) { |
+ return false; |
+ } |
+ |
+ float scale_x = sqrt(m00 * m00 + m10 * m10); |
+ float scale_y = sqrt(m01 * m01 + m11 * m11); |
+ |
+ if (scale_x == 0 || scale_y == 0) |
+ return false; |
+ |
+ float cos_theta = m00 / scale_x; |
+ float sin_theta = m10 / scale_x; |
+ |
+ if ((fabs(cos_theta - (m11 / scale_y))) > EPSILON || |
+ (fabs(sin_theta + (m01 / scale_y))) > EPSILON || |
+ (fabs(cos_theta*cos_theta + sin_theta*sin_theta - 1.0f) > EPSILON)) { |
+ return false; |
+ } |
+ |
+ float radians = atan2(sin_theta, cos_theta); |
+ |
+ if (translation) |
+ *translation = gfx::Point(m.get(0, 3), m.get(1, 3)); |
+ if (rotation) |
+ *rotation = radians * 180 / M_PI; |
+ if (scale) |
+ *scale = gfx::Point3f(scale_x, scale_y, 1.0f); |
+ |
+ return true; |
+} |
+ |
inline float InterpolatedTransform::ValueBetween(float time, |
float start_value, |
float end_value) const { |
@@ -94,15 +157,28 @@ ui::Transform InterpolatedRotation::InterpolateButDoNotCompose(float t) const { |
// InterpolatedScale |
// |
-InterpolatedScale::InterpolatedScale(float start_scale, |
- float end_scale) |
+InterpolatedScale::InterpolatedScale(float start_scale, float end_scale) |
+ : InterpolatedTransform(), |
+ start_scale_(gfx::Point3f(start_scale, start_scale, start_scale)), |
+ end_scale_(gfx::Point3f(end_scale, end_scale, end_scale)) { |
+} |
+ |
+InterpolatedScale::InterpolatedScale(float start_scale, float end_scale, |
+ float start_time, float end_time) |
+ : InterpolatedTransform(start_time, end_time), |
+ start_scale_(gfx::Point3f(start_scale, start_scale, start_scale)), |
+ end_scale_(gfx::Point3f(end_scale, end_scale, end_scale)) { |
+} |
+ |
+InterpolatedScale::InterpolatedScale(const gfx::Point3f& start_scale, |
+ const gfx::Point3f& end_scale) |
: InterpolatedTransform(), |
start_scale_(start_scale), |
end_scale_(end_scale) { |
} |
-InterpolatedScale::InterpolatedScale(float start_scale, |
- float end_scale, |
+InterpolatedScale::InterpolatedScale(const gfx::Point3f& start_scale, |
+ const gfx::Point3f& end_scale, |
float start_time, |
float end_time) |
: InterpolatedTransform(start_time, end_time), |
@@ -114,9 +190,10 @@ InterpolatedScale::~InterpolatedScale() {} |
ui::Transform InterpolatedScale::InterpolateButDoNotCompose(float t) const { |
ui::Transform result; |
- float interpolated_scale = ValueBetween(t, start_scale_, end_scale_); |
+ float scale_x = ValueBetween(t, start_scale_.x(), end_scale_.x()); |
+ float scale_y = ValueBetween(t, start_scale_.y(), end_scale_.y()); |
// TODO(vollick) 3d xforms. |
- result.SetScale(interpolated_scale, interpolated_scale); |
+ result.SetScale(scale_x, scale_y); |
return result; |
} |
@@ -196,7 +273,7 @@ InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const { |
if (transform_.get()) { |
return transform_->Interpolate(t); |
} |
- return ui::Transform(); |
+ return Transform(); |
} |
void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot, |
@@ -216,4 +293,63 @@ void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot, |
transform_.reset(pre_transform.release()); |
} |
+InterpolatedTRSTransform::InterpolatedTRSTransform( |
+ const ui::Transform& start_transform, |
+ const ui::Transform& end_transform) |
+ : InterpolatedTransform() { |
+ Init(start_transform, end_transform); |
+} |
+ |
+InterpolatedTRSTransform::InterpolatedTRSTransform( |
+ const ui::Transform& start_transform, |
+ const ui::Transform& end_transform, |
+ float start_time, |
+ float end_time) |
+ : InterpolatedTransform() { |
+ Init(start_transform, end_transform); |
+} |
+ |
+InterpolatedTRSTransform::~InterpolatedTRSTransform() {} |
+ |
+ui::Transform |
+InterpolatedTRSTransform::InterpolateButDoNotCompose(float t) const { |
+ if (transform_.get()) { |
+ return transform_->Interpolate(t); |
+ } |
+ return Transform(); |
+} |
+ |
+void InterpolatedTRSTransform::Init(const Transform& start_transform, |
+ const Transform& end_transform) { |
+ gfx::Point start_translation, end_translation; |
+ gfx::Point3f start_scale, end_scale; |
+ float start_degrees, end_degrees; |
+ if (FactorTRS(start_transform, |
+ &start_translation, |
+ &start_degrees, |
+ &start_scale) && |
+ FactorTRS(end_transform, |
+ &end_translation, |
+ &end_degrees, |
+ &end_scale)) { |
+ scoped_ptr<InterpolatedTranslation> translation( |
+ new InterpolatedTranslation(start_translation, end_translation, |
+ start_time(), end_time())); |
+ |
+ scoped_ptr<InterpolatedScale> scale( |
+ new InterpolatedScale(start_scale, end_scale, |
+ start_time(), end_time())); |
+ |
+ scoped_ptr<InterpolatedRotation> rotation( |
+ new InterpolatedRotation(start_degrees, end_degrees, |
+ start_time(), end_time())); |
+ |
+ rotation->SetChild(translation.release()); |
+ scale->SetChild(rotation.release()); |
+ transform_.reset(scale.release()); |
+ } else { |
+ transform_.reset(new InterpolatedConstantTransform(end_transform)); |
+ } |
+} |
+ |
} // namespace ui |