Example #1
0
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);
}