| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/cssom/transform_matrix.h" |
| |
| #include "base/logging.h" |
| #include "cobalt/cssom/matrix_function.h" |
| #include "cobalt/cssom/rotate_function.h" |
| #include "cobalt/cssom/scale_function.h" |
| #include "cobalt/cssom/transform_function.h" |
| #include "cobalt/cssom/transform_function_visitor.h" |
| #include "cobalt/cssom/translate_function.h" |
| #include "cobalt/math/matrix_interpolation.h" |
| #include "cobalt/math/transform_2d.h" |
| |
| namespace cobalt { |
| namespace cssom { |
| |
| TransformMatrix::TransformMatrix() : matrix_(math::Matrix3F::Identity()) {} |
| |
| TransformMatrix::TransformMatrix(const math::Matrix3F& matrix) |
| : matrix_(matrix) {} |
| |
| math::Matrix3F TransformMatrix::ToMatrix3F(const math::SizeF& used_size) const { |
| math::Matrix3F result(matrix_); |
| for (int i = 0; i < 2; ++i) { |
| result.Set(i, 2, |
| width_percentage_translation_[i] * used_size.width() + |
| height_percentage_translation_[i] * used_size.height() + |
| matrix_.Get(i, 2)); |
| } |
| return result; |
| } |
| |
| TransformMatrix InterpolateTransformMatrices(const TransformMatrix& a, |
| const TransformMatrix& b, |
| float progress) { |
| // By interpolating the matrix and percentage translate vectors separately, |
| // we achieve the same results as if we had decomposed the matrix with |
| // the multi-component translate values embedded within it. |
| math::Matrix3F interpolated_matrix( |
| math::InterpolateMatrices(a.matrix_, b.matrix_, progress)); |
| |
| math::Vector2dF interpolated_width_percentage_translation = |
| a.width_percentage_translation_ + |
| ScaleVector2d( |
| b.width_percentage_translation_ - a.width_percentage_translation_, |
| progress); |
| |
| math::Vector2dF interpolated_height_percentage_translation = |
| a.height_percentage_translation_ + |
| ScaleVector2d( |
| b.height_percentage_translation_ - a.height_percentage_translation_, |
| progress); |
| |
| return TransformMatrix(interpolated_matrix, |
| interpolated_width_percentage_translation, |
| interpolated_height_percentage_translation); |
| } |
| |
| namespace { |
| |
| // The PostMultiplyMatrixVisitor will post-multiply the passed in matrix |
| // with a matrix representing the transformation that is visited. |
| class PostMultiplyMatrixVisitor : public TransformFunctionVisitor { |
| public: |
| explicit PostMultiplyMatrixVisitor( |
| math::Matrix3F* matrix, math::Vector2dF* width_percentage_translation, |
| math::Vector2dF* height_percentage_translation) |
| : matrix_(matrix), |
| width_percentage_translation_(width_percentage_translation), |
| height_percentage_translation_(height_percentage_translation) {} |
| |
| void VisitMatrix(const MatrixFunction* matrix_function) OVERRIDE; |
| void VisitRotate(const RotateFunction* rotate_function) OVERRIDE; |
| void VisitScale(const ScaleFunction* scale_function) OVERRIDE; |
| void VisitTranslate(const TranslateFunction* translate_function) OVERRIDE; |
| |
| private: |
| math::Matrix3F* matrix_; |
| math::Vector2dF* width_percentage_translation_; |
| math::Vector2dF* height_percentage_translation_; |
| }; |
| |
| void PostMultiplyMatrixVisitor::VisitMatrix( |
| const MatrixFunction* matrix_function) { |
| *matrix_ = *matrix_ * matrix_function->value(); |
| } |
| |
| void PostMultiplyMatrixVisitor::VisitRotate( |
| const RotateFunction* rotate_function) { |
| // Since RotateMatrix()'s parameter is interpreted as counter-clockwise, we |
| // must negate our clockwise angle before passing it in. |
| *matrix_ = *matrix_ * |
| math::RotateMatrix(-rotate_function->clockwise_angle_in_radians()); |
| } |
| |
| void PostMultiplyMatrixVisitor::VisitScale( |
| const ScaleFunction* scale_function) { |
| *matrix_ = *matrix_ * math::ScaleMatrix(scale_function->x_factor(), |
| scale_function->y_factor()); |
| } |
| |
| void PostMultiplyMatrixVisitor::VisitTranslate( |
| const TranslateFunction* translate_function) { |
| if (translate_function->length_component_in_pixels() == 0.0f && |
| translate_function->percentage_component() == 0.0f) { |
| // If we are translating by 0, there is nothing to be done here, this |
| // is the identity matrix. |
| return; |
| } |
| |
| if (translate_function->axis() == TranslateFunction::kZAxis) { |
| NOTIMPLEMENTED() << "translateZ is currently a noop in Cobalt."; |
| return; |
| } |
| |
| int axis_index = |
| translate_function->axis() == TranslateFunction::kXAxis ? 0 : 1; |
| |
| math::Vector2dF* target_percentage_translation = |
| axis_index == 0 ? width_percentage_translation_ |
| : height_percentage_translation_; |
| |
| // We manually apply the translation matrix transformation here, so that |
| // we can have it correctly apply to the percentage components as well. |
| for (int i = 0; i < 2; ++i) { |
| float scale = matrix_->Get(i, axis_index); |
| (*matrix_)(i, 2) += |
| translate_function->length_component_in_pixels() * scale; |
| (*target_percentage_translation)[i] += |
| translate_function->percentage_component() * scale; |
| } |
| } |
| |
| } // namespace |
| |
| void TransformMatrix::PostMultiplyByTransform( |
| const TransformFunction* function) { |
| PostMultiplyMatrixVisitor visitor(&matrix_, &width_percentage_translation_, |
| &height_percentage_translation_); |
| function->Accept(&visitor); |
| } |
| |
| } // namespace cssom |
| } // namespace cobalt |