| Index: cc/animation/transform_operation.cc
|
| diff --git a/cc/animation/transform_operation.cc b/cc/animation/transform_operation.cc
|
| deleted file mode 100644
|
| index 7421924aedcea56ef9658d47bc2e4c77225404d2..0000000000000000000000000000000000000000
|
| --- a/cc/animation/transform_operation.cc
|
| +++ /dev/null
|
| @@ -1,439 +0,0 @@
|
| -// Copyright 2013 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.
|
| -
|
| -// Needed on Windows to get |M_PI| from <cmath>
|
| -#ifdef _WIN32
|
| -#define _USE_MATH_DEFINES
|
| -#endif
|
| -
|
| -#include <algorithm>
|
| -#include <cmath>
|
| -#include <limits>
|
| -
|
| -#include "base/logging.h"
|
| -#include "cc/animation/transform_operation.h"
|
| -#include "cc/animation/transform_operations.h"
|
| -#include "ui/gfx/geometry/box_f.h"
|
| -#include "ui/gfx/geometry/vector3d_f.h"
|
| -#include "ui/gfx/transform_util.h"
|
| -
|
| -namespace {
|
| -const SkMScalar kAngleEpsilon = 1e-4f;
|
| -}
|
| -
|
| -namespace cc {
|
| -
|
| -bool TransformOperation::IsIdentity() const {
|
| - return matrix.IsIdentity();
|
| -}
|
| -
|
| -static bool IsOperationIdentity(const TransformOperation* operation) {
|
| - return !operation || operation->IsIdentity();
|
| -}
|
| -
|
| -static bool ShareSameAxis(const TransformOperation* from,
|
| - const TransformOperation* to,
|
| - SkMScalar* axis_x,
|
| - SkMScalar* axis_y,
|
| - SkMScalar* axis_z,
|
| - SkMScalar* angle_from) {
|
| - if (IsOperationIdentity(from) && IsOperationIdentity(to))
|
| - return false;
|
| -
|
| - if (IsOperationIdentity(from) && !IsOperationIdentity(to)) {
|
| - *axis_x = to->rotate.axis.x;
|
| - *axis_y = to->rotate.axis.y;
|
| - *axis_z = to->rotate.axis.z;
|
| - *angle_from = 0;
|
| - return true;
|
| - }
|
| -
|
| - if (!IsOperationIdentity(from) && IsOperationIdentity(to)) {
|
| - *axis_x = from->rotate.axis.x;
|
| - *axis_y = from->rotate.axis.y;
|
| - *axis_z = from->rotate.axis.z;
|
| - *angle_from = from->rotate.angle;
|
| - return true;
|
| - }
|
| -
|
| - SkMScalar length_2 = from->rotate.axis.x * from->rotate.axis.x +
|
| - from->rotate.axis.y * from->rotate.axis.y +
|
| - from->rotate.axis.z * from->rotate.axis.z;
|
| - SkMScalar other_length_2 = to->rotate.axis.x * to->rotate.axis.x +
|
| - to->rotate.axis.y * to->rotate.axis.y +
|
| - to->rotate.axis.z * to->rotate.axis.z;
|
| -
|
| - if (length_2 <= kAngleEpsilon || other_length_2 <= kAngleEpsilon)
|
| - return false;
|
| -
|
| - SkMScalar dot = to->rotate.axis.x * from->rotate.axis.x +
|
| - to->rotate.axis.y * from->rotate.axis.y +
|
| - to->rotate.axis.z * from->rotate.axis.z;
|
| - SkMScalar error =
|
| - std::abs(SK_MScalar1 - (dot * dot) / (length_2 * other_length_2));
|
| - bool result = error < kAngleEpsilon;
|
| - if (result) {
|
| - *axis_x = to->rotate.axis.x;
|
| - *axis_y = to->rotate.axis.y;
|
| - *axis_z = to->rotate.axis.z;
|
| - // If the axes are pointing in opposite directions, we need to reverse
|
| - // the angle.
|
| - *angle_from = dot > 0 ? from->rotate.angle : -from->rotate.angle;
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -static SkMScalar BlendSkMScalars(SkMScalar from,
|
| - SkMScalar to,
|
| - SkMScalar progress) {
|
| - return from * (1 - progress) + to * progress;
|
| -}
|
| -
|
| -bool TransformOperation::BlendTransformOperations(
|
| - const TransformOperation* from,
|
| - const TransformOperation* to,
|
| - SkMScalar progress,
|
| - gfx::Transform* result) {
|
| - if (IsOperationIdentity(from) && IsOperationIdentity(to))
|
| - return true;
|
| -
|
| - TransformOperation::Type interpolation_type =
|
| - TransformOperation::TRANSFORM_OPERATION_IDENTITY;
|
| - if (IsOperationIdentity(to))
|
| - interpolation_type = from->type;
|
| - else
|
| - interpolation_type = to->type;
|
| -
|
| - switch (interpolation_type) {
|
| - case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
|
| - SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
|
| - SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
|
| - SkMScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
|
| - SkMScalar to_x = IsOperationIdentity(to) ? 0 : to->translate.x;
|
| - SkMScalar to_y = IsOperationIdentity(to) ? 0 : to->translate.y;
|
| - SkMScalar to_z = IsOperationIdentity(to) ? 0 : to->translate.z;
|
| - result->Translate3d(BlendSkMScalars(from_x, to_x, progress),
|
| - BlendSkMScalars(from_y, to_y, progress),
|
| - BlendSkMScalars(from_z, to_z, progress));
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
|
| - SkMScalar axis_x = 0;
|
| - SkMScalar axis_y = 0;
|
| - SkMScalar axis_z = 1;
|
| - SkMScalar from_angle = 0;
|
| - SkMScalar to_angle = IsOperationIdentity(to) ? 0 : to->rotate.angle;
|
| - if (ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) {
|
| - result->RotateAbout(gfx::Vector3dF(axis_x, axis_y, axis_z),
|
| - BlendSkMScalars(from_angle, to_angle, progress));
|
| - } else {
|
| - gfx::Transform to_matrix;
|
| - if (!IsOperationIdentity(to))
|
| - to_matrix = to->matrix;
|
| - gfx::Transform from_matrix;
|
| - if (!IsOperationIdentity(from))
|
| - from_matrix = from->matrix;
|
| - *result = to_matrix;
|
| - if (!result->Blend(from_matrix, progress))
|
| - return false;
|
| - }
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_SCALE: {
|
| - SkMScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
|
| - SkMScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
|
| - SkMScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
|
| - SkMScalar to_x = IsOperationIdentity(to) ? 1 : to->scale.x;
|
| - SkMScalar to_y = IsOperationIdentity(to) ? 1 : to->scale.y;
|
| - SkMScalar to_z = IsOperationIdentity(to) ? 1 : to->scale.z;
|
| - result->Scale3d(BlendSkMScalars(from_x, to_x, progress),
|
| - BlendSkMScalars(from_y, to_y, progress),
|
| - BlendSkMScalars(from_z, to_z, progress));
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_SKEW: {
|
| - SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
|
| - SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
|
| - SkMScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
|
| - SkMScalar to_y = IsOperationIdentity(to) ? 0 : to->skew.y;
|
| - result->SkewX(BlendSkMScalars(from_x, to_x, progress));
|
| - result->SkewY(BlendSkMScalars(from_y, to_y, progress));
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
|
| - SkMScalar from_perspective_depth =
|
| - IsOperationIdentity(from) ? std::numeric_limits<SkMScalar>::max()
|
| - : from->perspective_depth;
|
| - SkMScalar to_perspective_depth =
|
| - IsOperationIdentity(to) ? std::numeric_limits<SkMScalar>::max()
|
| - : to->perspective_depth;
|
| - if (from_perspective_depth == 0.f || to_perspective_depth == 0.f)
|
| - return false;
|
| -
|
| - SkMScalar blended_perspective_depth = BlendSkMScalars(
|
| - 1.f / from_perspective_depth, 1.f / to_perspective_depth, progress);
|
| -
|
| - if (blended_perspective_depth == 0.f)
|
| - return false;
|
| -
|
| - result->ApplyPerspectiveDepth(1.f / blended_perspective_depth);
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
|
| - gfx::Transform to_matrix;
|
| - if (!IsOperationIdentity(to))
|
| - to_matrix = to->matrix;
|
| - gfx::Transform from_matrix;
|
| - if (!IsOperationIdentity(from))
|
| - from_matrix = from->matrix;
|
| - *result = to_matrix;
|
| - if (!result->Blend(from_matrix, progress))
|
| - return false;
|
| - break;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
|
| - // Do nothing.
|
| - break;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this
|
| -// function computes the angles we would have to rotate from p to get to
|
| -// (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is
|
| -// negative, these angles will need to be reversed.
|
| -static void FindCandidatesInPlane(float px,
|
| - float py,
|
| - float nz,
|
| - double* candidates,
|
| - int* num_candidates) {
|
| - double phi = atan2(px, py);
|
| - *num_candidates = 4;
|
| - candidates[0] = phi;
|
| - for (int i = 1; i < *num_candidates; ++i)
|
| - candidates[i] = candidates[i - 1] + M_PI_2;
|
| - if (nz < 0.f) {
|
| - for (int i = 0; i < *num_candidates; ++i)
|
| - candidates[i] *= -1.f;
|
| - }
|
| -}
|
| -
|
| -static float RadiansToDegrees(float radians) {
|
| - return (180.f * radians) / M_PI;
|
| -}
|
| -
|
| -static float DegreesToRadians(float degrees) {
|
| - return (M_PI * degrees) / 180.f;
|
| -}
|
| -
|
| -static void BoundingBoxForArc(const gfx::Point3F& point,
|
| - const TransformOperation* from,
|
| - const TransformOperation* to,
|
| - SkMScalar min_progress,
|
| - SkMScalar max_progress,
|
| - gfx::BoxF* box) {
|
| - const TransformOperation* exemplar = from ? from : to;
|
| - gfx::Vector3dF axis(exemplar->rotate.axis.x,
|
| - exemplar->rotate.axis.y,
|
| - exemplar->rotate.axis.z);
|
| -
|
| - const bool x_is_zero = axis.x() == 0.f;
|
| - const bool y_is_zero = axis.y() == 0.f;
|
| - const bool z_is_zero = axis.z() == 0.f;
|
| -
|
| - // We will have at most 6 angles to test (excluding from->angle and
|
| - // to->angle).
|
| - static const int kMaxNumCandidates = 6;
|
| - double candidates[kMaxNumCandidates];
|
| - int num_candidates = kMaxNumCandidates;
|
| -
|
| - if (x_is_zero && y_is_zero && z_is_zero)
|
| - return;
|
| -
|
| - SkMScalar from_angle = from ? from->rotate.angle : 0.f;
|
| - SkMScalar to_angle = to ? to->rotate.angle : 0.f;
|
| -
|
| - // If the axes of rotation are pointing in opposite directions, we need to
|
| - // flip one of the angles. Note, if both |from| and |to| exist, then axis will
|
| - // correspond to |from|.
|
| - if (from && to) {
|
| - gfx::Vector3dF other_axis(
|
| - to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z);
|
| - if (gfx::DotProduct(axis, other_axis) < 0.f)
|
| - to_angle *= -1.f;
|
| - }
|
| -
|
| - float min_degrees =
|
| - SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress));
|
| - float max_degrees =
|
| - SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress));
|
| - if (max_degrees < min_degrees)
|
| - std::swap(min_degrees, max_degrees);
|
| -
|
| - gfx::Transform from_transform;
|
| - from_transform.RotateAbout(axis, min_degrees);
|
| - gfx::Transform to_transform;
|
| - to_transform.RotateAbout(axis, max_degrees);
|
| -
|
| - *box = gfx::BoxF();
|
| -
|
| - gfx::Point3F point_rotated_from = point;
|
| - from_transform.TransformPoint(&point_rotated_from);
|
| - gfx::Point3F point_rotated_to = point;
|
| - to_transform.TransformPoint(&point_rotated_to);
|
| -
|
| - box->set_origin(point_rotated_from);
|
| - box->ExpandTo(point_rotated_to);
|
| -
|
| - if (x_is_zero && y_is_zero) {
|
| - FindCandidatesInPlane(
|
| - point.x(), point.y(), axis.z(), candidates, &num_candidates);
|
| - } else if (x_is_zero && z_is_zero) {
|
| - FindCandidatesInPlane(
|
| - point.z(), point.x(), axis.y(), candidates, &num_candidates);
|
| - } else if (y_is_zero && z_is_zero) {
|
| - FindCandidatesInPlane(
|
| - point.y(), point.z(), axis.x(), candidates, &num_candidates);
|
| - } else {
|
| - gfx::Vector3dF normal = axis;
|
| - normal.Scale(1.f / normal.Length());
|
| -
|
| - // First, find center of rotation.
|
| - gfx::Point3F origin;
|
| - gfx::Vector3dF to_point = point - origin;
|
| - gfx::Point3F center =
|
| - origin + gfx::ScaleVector3d(normal, gfx::DotProduct(to_point, normal));
|
| -
|
| - // Now we need to find two vectors in the plane of rotation. One pointing
|
| - // towards point and another, perpendicular vector in the plane.
|
| - gfx::Vector3dF v1 = point - center;
|
| - float v1_length = v1.Length();
|
| - if (v1_length == 0.f)
|
| - return;
|
| -
|
| - v1.Scale(1.f / v1_length);
|
| - gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1);
|
| - // v1 is the basis vector in the direction of the point.
|
| - // i.e. with a rotation of 0, v1 is our +x vector.
|
| - // v2 is a perpenticular basis vector of our plane (+y).
|
| -
|
| - // Take the parametric equation of a circle.
|
| - // x = r*cos(t); y = r*sin(t);
|
| - // We can treat that as a circle on the plane v1xv2.
|
| - // From that we get the parametric equations for a circle on the
|
| - // plane in 3d space of:
|
| - // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
|
| - // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
|
| - // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
|
| - // Taking the derivative of (x, y, z) and solving for 0 gives us our
|
| - // maximum/minimum x, y, z values.
|
| - // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
|
| - // tan(t) = v2.x/v1.x
|
| - // t = atan2(v2.x, v1.x) + n*M_PI;
|
| - candidates[0] = atan2(v2.x(), v1.x());
|
| - candidates[1] = candidates[0] + M_PI;
|
| - candidates[2] = atan2(v2.y(), v1.y());
|
| - candidates[3] = candidates[2] + M_PI;
|
| - candidates[4] = atan2(v2.z(), v1.z());
|
| - candidates[5] = candidates[4] + M_PI;
|
| - }
|
| -
|
| - double min_radians = DegreesToRadians(min_degrees);
|
| - double max_radians = DegreesToRadians(max_degrees);
|
| -
|
| - for (int i = 0; i < num_candidates; ++i) {
|
| - double radians = candidates[i];
|
| - while (radians < min_radians)
|
| - radians += 2.0 * M_PI;
|
| - while (radians > max_radians)
|
| - radians -= 2.0 * M_PI;
|
| - if (radians < min_radians)
|
| - continue;
|
| -
|
| - gfx::Transform rotation;
|
| - rotation.RotateAbout(axis, RadiansToDegrees(radians));
|
| - gfx::Point3F rotated = point;
|
| - rotation.TransformPoint(&rotated);
|
| -
|
| - box->ExpandTo(rotated);
|
| - }
|
| -}
|
| -
|
| -bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
|
| - const TransformOperation* from,
|
| - const TransformOperation* to,
|
| - SkMScalar min_progress,
|
| - SkMScalar max_progress,
|
| - gfx::BoxF* bounds) {
|
| - bool is_identity_from = IsOperationIdentity(from);
|
| - bool is_identity_to = IsOperationIdentity(to);
|
| - if (is_identity_from && is_identity_to) {
|
| - *bounds = box;
|
| - return true;
|
| - }
|
| -
|
| - TransformOperation::Type interpolation_type =
|
| - TransformOperation::TRANSFORM_OPERATION_IDENTITY;
|
| - if (is_identity_to)
|
| - interpolation_type = from->type;
|
| - else
|
| - interpolation_type = to->type;
|
| -
|
| - switch (interpolation_type) {
|
| - case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
|
| - *bounds = box;
|
| - return true;
|
| - case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
|
| - case TransformOperation::TRANSFORM_OPERATION_SKEW:
|
| - case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
|
| - case TransformOperation::TRANSFORM_OPERATION_SCALE: {
|
| - gfx::Transform from_transform;
|
| - gfx::Transform to_transform;
|
| - if (!BlendTransformOperations(from, to, min_progress, &from_transform) ||
|
| - !BlendTransformOperations(from, to, max_progress, &to_transform))
|
| - return false;
|
| -
|
| - *bounds = box;
|
| - from_transform.TransformBox(bounds);
|
| -
|
| - gfx::BoxF to_box = box;
|
| - to_transform.TransformBox(&to_box);
|
| - bounds->ExpandTo(to_box);
|
| -
|
| - return true;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
|
| - SkMScalar axis_x = 0;
|
| - SkMScalar axis_y = 0;
|
| - SkMScalar axis_z = 1;
|
| - SkMScalar from_angle = 0;
|
| - if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle))
|
| - return false;
|
| -
|
| - bool first_point = true;
|
| - for (int i = 0; i < 8; ++i) {
|
| - gfx::Point3F corner = box.origin();
|
| - corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f,
|
| - i & 2 ? box.height() : 0.f,
|
| - i & 4 ? box.depth() : 0.f);
|
| - gfx::BoxF box_for_arc;
|
| - BoundingBoxForArc(
|
| - corner, from, to, min_progress, max_progress, &box_for_arc);
|
| - if (first_point)
|
| - *bounds = box_for_arc;
|
| - else
|
| - bounds->Union(box_for_arc);
|
| - first_point = false;
|
| - }
|
| - return true;
|
| - }
|
| - case TransformOperation::TRANSFORM_OPERATION_MATRIX:
|
| - return false;
|
| - }
|
| - NOTREACHED();
|
| - return false;
|
| -}
|
| -
|
| -} // namespace cc
|
|
|