blob: 76d484f6ab857510bed7695be0fea087c6968b6d [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(CSSPrimitiveValue* primitiveValue, const CSSToLengthConversionData& conversionData)
{
ASSERT(primitiveValue);
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(CSSValue& inValue, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations)
{
ASSERT(!outOperations.size());
if (!inValue.isValueList()) {
ASSERT(inValue.isPrimitiveValue() && toCSSPrimitiveValue(inValue).getValueID() == CSSValueNone);
return;
}
float zoomFactor = conversionData.zoom();
for (auto& value : toCSSValueList(inValue)) {
CSSFunctionValue* transformValue = toCSSFunctionValue(value.get());
TransformOperation::OperationType transformType = getTransformOperationType(transformValue->functionType());
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) {
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) {
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: {
CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2));
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) {
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