blob: f989a0e1f366d00753bb27e298dfced6957323d3 [file] [log] [blame]
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h"
#include "third_party/blink/renderer/platform/transforms/rotation.h"
#include "ui/gfx/geometry/quaternion.h"
#include <algorithm>
namespace blink {
scoped_refptr<TransformOperation> Matrix3DTransformOperation::Accumulate(
const TransformOperation& other_op) {
DCHECK(other_op.IsSameType(*this));
const auto& other = To<Matrix3DTransformOperation>(other_op);
// If either matrix is non-invertible, fail and fallback to replace.
if (!matrix_.IsInvertible() || !other.matrix_.IsInvertible())
return nullptr;
// Similar to interpolation, accumulating 3D matrices is done by decomposing
// them, accumulating the individual functions, and then recomposing.
TransformationMatrix::DecomposedType from_decomp;
TransformationMatrix::DecomposedType to_decomp;
if (!matrix_.Decompose(from_decomp) || !other.matrix_.Decompose(to_decomp))
return nullptr;
// Scale is accumulated using 1-based addition.
from_decomp.scale_x += to_decomp.scale_x - 1;
from_decomp.scale_y += to_decomp.scale_y - 1;
from_decomp.scale_z += to_decomp.scale_z - 1;
// Skew can be added.
from_decomp.skew_xy += to_decomp.skew_xy;
from_decomp.skew_xz += to_decomp.skew_xz;
from_decomp.skew_yz += to_decomp.skew_yz;
// To accumulate quaternions, we multiply them. This is equivalent to 'adding'
// the rotations that they represent.
gfx::Quaternion from_quaternion(
from_decomp.quaternion_x, from_decomp.quaternion_y,
from_decomp.quaternion_z, from_decomp.quaternion_w);
gfx::Quaternion to_quaternion(to_decomp.quaternion_x, to_decomp.quaternion_y,
to_decomp.quaternion_z, to_decomp.quaternion_w);
gfx::Quaternion result_quaternion = from_quaternion * to_quaternion;
from_decomp.quaternion_x = result_quaternion.x();
from_decomp.quaternion_y = result_quaternion.y();
from_decomp.quaternion_z = result_quaternion.z();
from_decomp.quaternion_w = result_quaternion.w();
// Translate is a simple addition.
from_decomp.translate_x += to_decomp.translate_x;
from_decomp.translate_y += to_decomp.translate_y;
from_decomp.translate_z += to_decomp.translate_z;
// We sum the perspective components; note that w is 1-based.
from_decomp.perspective_x += to_decomp.perspective_x;
from_decomp.perspective_y += to_decomp.perspective_y;
from_decomp.perspective_z += to_decomp.perspective_z;
from_decomp.perspective_w += to_decomp.perspective_w - 1;
TransformationMatrix result;
result.Recompose(from_decomp);
return Matrix3DTransformOperation::Create(result);
}
scoped_refptr<TransformOperation> Matrix3DTransformOperation::Blend(
const TransformOperation* from,
double progress,
bool blend_to_identity) {
DCHECK(!from || CanBlendWith(*from));
// Convert the TransformOperations into matrices. Fail the blend operation
// if either of the matrices is non-invertible.
FloatSize size;
TransformationMatrix from_t;
TransformationMatrix to_t;
if (from) {
from->Apply(from_t, size);
if (!from_t.IsInvertible())
return nullptr;
}
Apply(to_t, size);
if (!to_t.IsInvertible())
return nullptr;
if (blend_to_identity)
std::swap(from_t, to_t);
to_t.Blend(from_t, progress);
return Matrix3DTransformOperation::Create(to_t);
}
scoped_refptr<TransformOperation> Matrix3DTransformOperation::Zoom(
double factor) {
TransformationMatrix result = matrix_;
result.Zoom(factor);
return Create(result);
}
} // namespace blink