Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Unified Diff: cc/transform_operations.cc

Issue 11745018: Not for review: Move the implementation of WebTransformOperations into chromium (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: New approach Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/transform_operations.h ('k') | cc/transform_operations_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/transform_operations.cc
diff --git a/cc/transform_operations.cc b/cc/transform_operations.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2e57d5152ceaeecc35a232dec13c658ebd0980b9
--- /dev/null
+++ b/cc/transform_operations.cc
@@ -0,0 +1,383 @@
+// 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.
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <vector>
+
+#include "cc/transform_operations.h"
+
+using WebKit::WebTransformationMatrix;
+
+namespace {
+const double EPSILON = 1e-4;
jamesr 2013/01/14 22:03:00 use chromium style kEpsilon it's pretty weird for
Ian Vollick 2013/01/15 15:02:38 I used this epsilon when checking if two rotations
+}
+
+namespace cc {
+
+struct TransformOperation {
+ enum Type {
+ TransformOperationTranslate,
+ TransformOperationRotate,
+ TransformOperationScale,
+ TransformOperationSkew,
+ TransformOperationPerspective,
+ TransformOperationMatrix,
+ TransformOperationIdentity
+ };
+
+ TransformOperation()
+ : type(TransformOperationIdentity) {
jamesr 2013/01/14 22:03:00 this should be indented 4 spaces from the previous
+ }
+
+ Type type;
+ WebKit::WebTransformationMatrix matrix;
+
+ union {
+ double perspective_depth;
+
+ struct {
+ double x, y;
+ } skew;
+
+ struct {
+ double x, y, z;
+ } scale;
+
+ struct {
+ double x, y, z;
+ } translate;
+
+ struct {
+ struct {
+ double x, y, z;
+ } axis;
+
+ double angle;
+ } rotate;
+ };
+
+ bool IsIdentity() const { return matrix.isIdentity(); }
+};
+
+TransformOperations::TransformOperations() {
+ Initialize();
+}
+
+TransformOperations::TransformOperations(const TransformOperations& other) {
+ Initialize(other);
+}
+
+TransformOperations::~TransformOperations() {
+}
+
+struct TransformOperationsPrivate {
+ std::vector<TransformOperation> operations;
+};
+
+WebTransformationMatrix TransformOperations::Apply() const {
+ WebTransformationMatrix to_return;
+ for (size_t i = 0; i < private_->operations.size(); ++i)
+ to_return.multiply(private_->operations[i].matrix);
+ return to_return;
+}
+
+static bool IsIdentity(const TransformOperation* operation) {
+ return !operation || operation->IsIdentity();
+}
+
+static bool ShareSameAxis(const TransformOperation* from,
+ const TransformOperation* to,
+ double& axis_x, double& axis_y, double& axis_z,
+ double& angle_from) {
+ if (IsIdentity(from) && IsIdentity(to))
+ return false;
+
+ if (IsIdentity(from) && !IsIdentity(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 (!IsIdentity(from) && IsIdentity(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;
+ }
+
+ double 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;
+ double 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 <= EPSILON || other_length_2 <= EPSILON)
+ return false;
+
+ double 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;
+ double error = std::fabs(1.0 - (dot * dot) / (length_2 * other_length_2));
+ bool result = error < EPSILON;
+ 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 double BlendDoubles(double from, double to, double progress) {
+ return from * (1 - progress) + to * progress;
+}
+
+static bool BlendTransformOperations(const TransformOperation* from,
+ const TransformOperation* to,
+ double progress,
+ WebTransformationMatrix& result) {
+ if (IsIdentity(from) && IsIdentity(to))
+ return true;
+
+ TransformOperation::Type interpolation_type =
+ TransformOperation::TransformOperationIdentity;
+ if (IsIdentity(to))
+ interpolation_type = from->type;
+ else
+ interpolation_type = to->type;
+
+ switch (interpolation_type) {
+ case TransformOperation::TransformOperationTranslate: {
+ double from_x = IsIdentity(from) ? 0 : from->translate.x;
+ double from_y = IsIdentity(from) ? 0 : from->translate.y;
+ double from_z = IsIdentity(from) ? 0 : from->translate.z;
+ double to_x = IsIdentity(to) ? 0 : to->translate.x;
+ double to_y = IsIdentity(to) ? 0 : to->translate.y;
+ double to_z = IsIdentity(to) ? 0 : to->translate.z;
+ result.translate3d(BlendDoubles(from_x, to_x, progress),
+ BlendDoubles(from_y, to_y, progress),
+ BlendDoubles(from_z, to_z, progress));
+ break;
+ }
+ case TransformOperation::TransformOperationRotate: {
+ double axis_x = 0;
+ double axis_y = 0;
+ double axis_z = 1;
+ double from_angle = 0;
+ double to_angle = IsIdentity(to) ? 0 : to->rotate.angle;
+ if (ShareSameAxis(from, to, axis_x, axis_y, axis_z, from_angle))
+ result.rotate3d(axis_x, axis_y, axis_z,
+ BlendDoubles(from_angle, to_angle, progress));
+ else {
+ WebTransformationMatrix to_matrix;
+ if (!IsIdentity(to))
+ to_matrix = to->matrix;
+ WebTransformationMatrix from_matrix;
+ if (!IsIdentity(from))
+ from_matrix = from->matrix;
+ result = to_matrix;
+ if (!result.blend(from_matrix, progress))
+ return false;
+ }
+ break;
+ }
+ case TransformOperation::TransformOperationScale: {
+ double from_x = IsIdentity(from) ? 1 : from->scale.x;
+ double from_y = IsIdentity(from) ? 1 : from->scale.y;
+ double from_z = IsIdentity(from) ? 1 : from->scale.z;
+ double to_x = IsIdentity(to) ? 1 : to->scale.x;
+ double to_y = IsIdentity(to) ? 1 : to->scale.y;
+ double to_z = IsIdentity(to) ? 1 : to->scale.z;
+ result.scale3d(BlendDoubles(from_x, to_x, progress),
+ BlendDoubles(from_y, to_y, progress),
+ BlendDoubles(from_z, to_z, progress));
+ break;
+ }
+ case TransformOperation::TransformOperationSkew: {
+ double from_x = IsIdentity(from) ? 0 : from->skew.x;
+ double from_y = IsIdentity(from) ? 0 : from->skew.y;
+ double to_x = IsIdentity(to) ? 0 : to->skew.x;
+ double to_y = IsIdentity(to) ? 0 : to->skew.y;
+ result.skewX(BlendDoubles(from_x, to_x, progress));
+ result.skewY(BlendDoubles(from_y, to_y, progress));
+ break;
+ }
+ case TransformOperation::TransformOperationPerspective: {
+ double from_perspective_depth = IsIdentity(from) ?
+ std::numeric_limits<double>::max() : from->perspective_depth;
+ double to_perspective_depth = IsIdentity(to) ?
+ std::numeric_limits<double>::max() : to->perspective_depth;
+ result.applyPerspective(
+ BlendDoubles(from_perspective_depth, to_perspective_depth, progress));
+ break;
+ }
+ case TransformOperation::TransformOperationMatrix: {
+ WebTransformationMatrix to_matrix;
+ if (!IsIdentity(to))
+ to_matrix = to->matrix;
+ WebTransformationMatrix from_matrix;
+ if (!IsIdentity(from))
+ from_matrix = from->matrix;
+ result = to_matrix;
+ if (!result.blend(from_matrix, progress))
+ return false;
+ break;
+ }
+ case TransformOperation::TransformOperationIdentity:
+ // Do nothing.
+ break;
+ }
+
+ return true;
+}
+
+WebTransformationMatrix TransformOperations::Blend(
+ const TransformOperations& from, double progress) const {
+ WebTransformationMatrix to_return;
+ BlendInternal(from, progress, to_return);
+ return to_return;
+}
+
+bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
+ if (IsIdentity() || other.IsIdentity())
+ return true;
+
+ if (private_->operations.size() != other.private_->operations.size())
+ return false;
+
+ for (size_t i = 0; i < private_->operations.size(); ++i) {
+ if (private_->operations[i].type != other.private_->operations[i].type
+ && !private_->operations[i].IsIdentity()
+ && !other.private_->operations[i].IsIdentity())
+ return false;
+ }
+
+ return true;
+}
+
+bool TransformOperations::CanBlendWith(
+ const TransformOperations& other) const {
+ WebTransformationMatrix dummy;
+ return BlendInternal(other, 0.5, dummy);
+}
+
+void TransformOperations::AppendTranslate(double x, double y, double z) {
+ TransformOperation to_add;
+ to_add.matrix.translate3d(x, y, z);
+ to_add.type = TransformOperation::TransformOperationTranslate;
+ to_add.translate.x = x;
+ to_add.translate.y = y;
+ to_add.translate.z = z;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendRotate(double x, double y, double z,
+ double degrees) {
+ TransformOperation to_add;
+ to_add.matrix.rotate3d(x, y, z, degrees);
+ to_add.type = TransformOperation::TransformOperationRotate;
+ to_add.rotate.axis.x = x;
+ to_add.rotate.axis.y = y;
+ to_add.rotate.axis.z = z;
+ to_add.rotate.angle = degrees;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendScale(double x, double y, double z) {
+ TransformOperation to_add;
+ to_add.matrix.scale3d(x, y, z);
+ to_add.type = TransformOperation::TransformOperationScale;
+ to_add.scale.x = x;
+ to_add.scale.y = y;
+ to_add.scale.z = z;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendSkew(double x, double y) {
+ TransformOperation to_add;
+ to_add.matrix.skewX(x);
+ to_add.matrix.skewY(y);
+ to_add.type = TransformOperation::TransformOperationSkew;
+ to_add.skew.x = x;
+ to_add.skew.y = y;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendPerspective(double depth) {
+ TransformOperation to_add;
+ to_add.matrix.applyPerspective(depth);
+ to_add.type = TransformOperation::TransformOperationPerspective;
+ to_add.perspective_depth = depth;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendMatrix(const WebTransformationMatrix& matrix) {
+ TransformOperation to_add;
+ to_add.matrix = matrix;
+ to_add.type = TransformOperation::TransformOperationMatrix;
+ private_->operations.push_back(to_add);
+}
+
+void TransformOperations::AppendIdentity() {
+ private_->operations.push_back(TransformOperation());
+}
+
+bool TransformOperations::IsIdentity() const {
+ for (size_t i = 0; i < private_->operations.size(); ++i) {
+ if (!private_->operations[i].IsIdentity())
+ return false;
+ }
+ return true;
+}
+
+void TransformOperations::Initialize() {
+ private_.reset(new TransformOperationsPrivate);
+}
+
+void TransformOperations::Initialize(const TransformOperations& other) {
+ if (private_.get() != other.private_.get())
+ private_.reset(new TransformOperationsPrivate(*other.private_.get()));
+ else
+ Initialize();
+}
+
+bool TransformOperations::BlendInternal(const TransformOperations& from,
+ double progress,
+ WebTransformationMatrix& result) const {
+ bool from_identity = from.IsIdentity();
+ bool to_identity = IsIdentity();
+ if (from_identity && to_identity)
+ return true;
+
+ if (MatchesTypes(from)) {
+ size_t num_operations =
+ std::max(from_identity ? 0 : from.private_->operations.size(),
+ to_identity ? 0 : private_->operations.size());
+ for (size_t i = 0; i < num_operations; ++i) {
+ WebTransformationMatrix blended;
+ if (!BlendTransformOperations(
+ from_identity ? 0 : &from.private_->operations[i],
+ to_identity ? 0 : &private_->operations[i],
+ progress,
+ blended))
+ return false;
+ result.multiply(blended);
+ }
+ return true;
+ }
+
+ result = Apply();
+ WebTransformationMatrix from_transform = from.Apply();
+ return result.blend(from_transform, progress);
+}
+
+} // namespace cc
« no previous file with comments | « cc/transform_operations.h ('k') | cc/transform_operations_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698