static WebTransformationMatrix blendTransformOperations(const WebTransformOperation* from, const WebTransformOperation* to, double progress) { WebTransformationMatrix toReturn; if (isIdentity(from) && isIdentity(to)) return toReturn; WebTransformOperation::Type interpolationType = WebTransformOperation::WebTransformOperationIdentity; if (isIdentity(to)) interpolationType = from->type; else interpolationType = to->type; switch (interpolationType) { case WebTransformOperation::WebTransformOperationTranslate: { double fromX = isIdentity(from) ? 0 : from->translate.x; double fromY = isIdentity(from) ? 0 : from->translate.y; double fromZ = isIdentity(from) ? 0 : from->translate.z; double toX = isIdentity(to) ? 0 : to->translate.x; double toY = isIdentity(to) ? 0 : to->translate.y; double toZ = isIdentity(to) ? 0 : to->translate.z; toReturn.translate3d(blendDoubles(fromX, toX, progress), blendDoubles(fromY, toY, progress), blendDoubles(fromZ, toZ, progress)); break; } case WebTransformOperation::WebTransformOperationRotate: { double axisX = 0; double axisY = 0; double axisZ = 1; double fromAngle = 0; double toAngle = isIdentity(to) ? 0 : to->rotate.angle; if (shareSameAxis(from, to, axisX, axisY, axisZ, fromAngle)) toReturn.rotate3d(axisX, axisY, axisZ, blendDoubles(fromAngle, toAngle, progress)); else { WebTransformationMatrix toMatrix; if (!isIdentity(to)) toMatrix = to->matrix; WebTransformationMatrix fromMatrix; if (!isIdentity(from)) fromMatrix = from->matrix; toReturn = toMatrix; toReturn.blend(fromMatrix, progress); } break; } case WebTransformOperation::WebTransformOperationScale: { double fromX = isIdentity(from) ? 1 : from->scale.x; double fromY = isIdentity(from) ? 1 : from->scale.y; double fromZ = isIdentity(from) ? 1 : from->scale.z; double toX = isIdentity(to) ? 1 : to->scale.x; double toY = isIdentity(to) ? 1 : to->scale.y; double toZ = isIdentity(to) ? 1 : to->scale.z; toReturn.scale3d(blendDoubles(fromX, toX, progress), blendDoubles(fromY, toY, progress), blendDoubles(fromZ, toZ, progress)); break; } case WebTransformOperation::WebTransformOperationSkew: { double fromX = isIdentity(from) ? 0 : from->skew.x; double fromY = isIdentity(from) ? 0 : from->skew.y; double toX = isIdentity(to) ? 0 : to->skew.x; double toY = isIdentity(to) ? 0 : to->skew.y; toReturn.skewX(blendDoubles(fromX, toX, progress)); toReturn.skewY(blendDoubles(fromY, toY, progress)); break; } case WebTransformOperation::WebTransformOperationPerspective: { double fromPerspectiveDepth = isIdentity(from) ? numeric_limits<double>::max() : from->perspectiveDepth; double toPerspectiveDepth = isIdentity(to) ? numeric_limits<double>::max() : to->perspectiveDepth; toReturn.applyPerspective(blendDoubles(fromPerspectiveDepth, toPerspectiveDepth, progress)); break; } case WebTransformOperation::WebTransformOperationMatrix: { WebTransformationMatrix toMatrix; if (!isIdentity(to)) toMatrix = to->matrix; WebTransformationMatrix fromMatrix; if (!isIdentity(from)) fromMatrix = from->matrix; toReturn = toMatrix; toReturn.blend(fromMatrix, progress); break; } case WebTransformOperation::WebTransformOperationIdentity: // Do nothing. break; } return toReturn; }
PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) { if (from && !from->isSameType(*this)) return this; if (blendToIdentity) return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type); const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from); // Optimize for single axis rotation if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) || (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) || (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) { double fromAngle = fromOp ? fromOp->m_angle : 0; return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x, fromOp ? fromOp->m_y : m_y, fromOp ? fromOp->m_z : m_z, WebCore::blend(fromAngle, m_angle, progress), m_type); } double fromAngle; double toAngle; FloatPoint3D axis; if (shareSameAxis(fromOp, this, &axis, &fromAngle, &toAngle)) return RotateTransformOperation::create(axis.x(), axis.y(), axis.z(), WebCore::blend(fromAngle, toAngle, progress), m_type); const RotateTransformOperation* toOp = this; // Create the 2 rotation matrices TransformationMatrix fromT; TransformationMatrix toT; fromT.rotate3d((fromOp ? fromOp->m_x : 0), (fromOp ? fromOp->m_y : 0), (fromOp ? fromOp->m_z : 1), (fromOp ? fromOp->m_angle : 0)); toT.rotate3d((toOp ? toOp->m_x : 0), (toOp ? toOp->m_y : 0), (toOp ? toOp->m_z : 1), (toOp ? toOp->m_angle : 0)); // Blend them toT.blend(fromT, progress); // Extract the result as a quaternion TransformationMatrix::DecomposedType decomp; toT.decompose(decomp); // Convert that to Axis/Angle form double x = -decomp.quaternionX; double y = -decomp.quaternionY; double z = -decomp.quaternionZ; double length = sqrt(x * x + y * y + z * z); double angle = 0; if (length > 0.00001) { x /= length; y /= length; z /= length; angle = rad2deg(acos(decomp.quaternionW) * 2); } else { x = 0; y = 0; z = 1; } return RotateTransformOperation::create(x, y, z, angle, Rotate3D); }