blob: dcbe627cf82f7e51a6a49fbc5e601c35b4fb6574 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
* All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "core/css/resolver/TransformBuilder.h"
#include "core/css/CSSFunctionValue.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "platform/heap/Handle.h"
#include "platform/transforms/Matrix3DTransformOperation.h"
#include "platform/transforms/MatrixTransformOperation.h"
#include "platform/transforms/PerspectiveTransformOperation.h"
#include "platform/transforms/RotateTransformOperation.h"
#include "platform/transforms/ScaleTransformOperation.h"
#include "platform/transforms/SkewTransformOperation.h"
#include "platform/transforms/TransformationMatrix.h"
#include "platform/transforms/TranslateTransformOperation.h"
namespace blink {
static Length convertToFloatLength(
const CSSPrimitiveValue& primitiveValue,
const CSSToLengthConversionData& conversionData) {
return primitiveValue.convertToLength(conversionData);
}
static TransformOperation::OperationType getTransformOperationType(
CSSValueID type) {
switch (type) {
case CSSValueScale:
return TransformOperation::Scale;
case CSSValueScaleX:
return TransformOperation::ScaleX;
case CSSValueScaleY:
return TransformOperation::ScaleY;
case CSSValueScaleZ:
return TransformOperation::ScaleZ;
case CSSValueScale3d:
return TransformOperation::Scale3D;
case CSSValueTranslate:
return TransformOperation::Translate;
case CSSValueTranslateX:
return TransformOperation::TranslateX;
case CSSValueTranslateY:
return TransformOperation::TranslateY;
case CSSValueTranslateZ:
return TransformOperation::TranslateZ;
case CSSValueTranslate3d:
return TransformOperation::Translate3D;
case CSSValueRotate:
return TransformOperation::Rotate;
case CSSValueRotateX:
return TransformOperation::RotateX;
case CSSValueRotateY:
return TransformOperation::RotateY;
case CSSValueRotateZ:
return TransformOperation::RotateZ;
case CSSValueRotate3d:
return TransformOperation::Rotate3D;
case CSSValueSkew:
return TransformOperation::Skew;
case CSSValueSkewX:
return TransformOperation::SkewX;
case CSSValueSkewY:
return TransformOperation::SkewY;
case CSSValueMatrix:
return TransformOperation::Matrix;
case CSSValueMatrix3d:
return TransformOperation::Matrix3D;
case CSSValuePerspective:
return TransformOperation::Perspective;
default:
ASSERT_NOT_REACHED();
// FIXME: We shouldn't have a type None since we never create them
return TransformOperation::None;
}
}
void TransformBuilder::createTransformOperations(
const CSSValue& inValue,
const CSSToLengthConversionData& conversionData,
TransformOperations& outOperations) {
ASSERT(!outOperations.size());
if (!inValue.isValueList()) {
DCHECK_EQ(toCSSIdentifierValue(inValue).getValueID(), CSSValueNone);
return;
}
float zoomFactor = conversionData.zoom();
for (auto& value : toCSSValueList(inValue)) {
const CSSFunctionValue* transformValue = toCSSFunctionValue(value.get());
TransformOperation::OperationType transformType =
getTransformOperationType(transformValue->functionType());
const CSSPrimitiveValue& firstValue =
toCSSPrimitiveValue(transformValue->item(0));
switch (transformType) {
case TransformOperation::Scale:
case TransformOperation::ScaleX:
case TransformOperation::ScaleY: {
double sx = 1.0;
double sy = 1.0;
if (transformType == TransformOperation::ScaleY) {
sy = firstValue.getDoubleValue();
} else {
sx = firstValue.getDoubleValue();
if (transformType != TransformOperation::ScaleX) {
if (transformValue->length() > 1) {
const CSSPrimitiveValue& secondValue =
toCSSPrimitiveValue(transformValue->item(1));
sy = secondValue.getDoubleValue();
} else {
sy = sx;
}
}
}
outOperations.operations().append(
ScaleTransformOperation::create(sx, sy, 1.0, transformType));
break;
}
case TransformOperation::ScaleZ:
case TransformOperation::Scale3D: {
double sx = 1.0;
double sy = 1.0;
double sz = 1.0;
if (transformType == TransformOperation::ScaleZ) {
sz = firstValue.getDoubleValue();
} else {
sx = firstValue.getDoubleValue();
sy = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue();
sz = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue();
}
outOperations.operations().append(
ScaleTransformOperation::create(sx, sy, sz, transformType));
break;
}
case TransformOperation::Translate:
case TransformOperation::TranslateX:
case TransformOperation::TranslateY: {
Length tx = Length(0, Fixed);
Length ty = Length(0, Fixed);
if (transformType == TransformOperation::TranslateY)
ty = convertToFloatLength(firstValue, conversionData);
else {
tx = convertToFloatLength(firstValue, conversionData);
if (transformType != TransformOperation::TranslateX) {
if (transformValue->length() > 1) {
const CSSPrimitiveValue& secondValue =
toCSSPrimitiveValue(transformValue->item(1));
ty = convertToFloatLength(secondValue, conversionData);
}
}
}
outOperations.operations().append(
TranslateTransformOperation::create(tx, ty, 0, transformType));
break;
}
case TransformOperation::TranslateZ:
case TransformOperation::Translate3D: {
Length tx = Length(0, Fixed);
Length ty = Length(0, Fixed);
double tz = 0;
if (transformType == TransformOperation::TranslateZ) {
tz = firstValue.computeLength<double>(conversionData);
} else {
tx = convertToFloatLength(firstValue, conversionData);
ty = convertToFloatLength(
toCSSPrimitiveValue(transformValue->item(1)), conversionData);
tz = toCSSPrimitiveValue(transformValue->item(2))
.computeLength<double>(conversionData);
}
outOperations.operations().append(
TranslateTransformOperation::create(tx, ty, tz, transformType));
break;
}
case TransformOperation::RotateX:
case TransformOperation::RotateY:
case TransformOperation::RotateZ: {
double angle = firstValue.computeDegrees();
double x = transformType == TransformOperation::RotateX;
double y = transformType == TransformOperation::RotateY;
double z = transformType == TransformOperation::RotateZ;
outOperations.operations().append(
RotateTransformOperation::create(x, y, z, angle, transformType));
break;
}
case TransformOperation::Rotate3D: {
const CSSPrimitiveValue& secondValue =
toCSSPrimitiveValue(transformValue->item(1));
const CSSPrimitiveValue& thirdValue =
toCSSPrimitiveValue(transformValue->item(2));
const CSSPrimitiveValue& fourthValue =
toCSSPrimitiveValue(transformValue->item(3));
double x = firstValue.getDoubleValue();
double y = secondValue.getDoubleValue();
double z = thirdValue.getDoubleValue();
double angle = fourthValue.computeDegrees();
outOperations.operations().append(
RotateTransformOperation::create(x, y, z, angle, transformType));
break;
}
case TransformOperation::Skew:
case TransformOperation::SkewX:
case TransformOperation::SkewY: {
double angleX = 0;
double angleY = 0;
double angle = firstValue.computeDegrees();
if (transformType == TransformOperation::SkewY)
angleY = angle;
else {
angleX = angle;
if (transformType == TransformOperation::Skew) {
if (transformValue->length() > 1) {
const CSSPrimitiveValue& secondValue =
toCSSPrimitiveValue(transformValue->item(1));
angleY = secondValue.computeDegrees();
}
}
}
outOperations.operations().append(
SkewTransformOperation::create(angleX, angleY, transformType));
break;
}
case TransformOperation::Matrix: {
double a = firstValue.getDoubleValue();
double b =
toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue();
double c =
toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue();
double d =
toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue();
double e =
zoomFactor *
toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue();
double f =
zoomFactor *
toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue();
outOperations.operations().append(
MatrixTransformOperation::create(a, b, c, d, e, f));
break;
}
case TransformOperation::Matrix3D: {
TransformationMatrix matrix(
toCSSPrimitiveValue(transformValue->item(0)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(6)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(7)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(8)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(9)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(10)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(11)).getDoubleValue(),
zoomFactor *
toCSSPrimitiveValue(transformValue->item(12)).getDoubleValue(),
zoomFactor *
toCSSPrimitiveValue(transformValue->item(13)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(14)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(15)).getDoubleValue());
outOperations.operations().append(
Matrix3DTransformOperation::create(matrix));
break;
}
case TransformOperation::Perspective: {
double p = firstValue.computeLength<double>(conversionData);
ASSERT(p >= 0);
outOperations.operations().append(
PerspectiveTransformOperation::create(p));
break;
}
default:
ASSERT_NOT_REACHED();
break;
}
}
}
} // namespace blink