blob: 3bea8d9fc973114d183019b4383d37792f7a4fd3 [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;
}
}
bool TransformBuilder::hasRelativeLengths(const CSSValueList& valueList) {
for (auto& value : valueList) {
const CSSFunctionValue* transformValue = toCSSFunctionValue(value.get());
for (const CSSValue* item : *transformValue) {
const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(*item);
// TODO(hs1217.lee) : to prevent relative unit like calc(10px + 1em).
// but when calc() not take parameter of ralative unit like calc(1px +1
// px),
// shoud be return false;
if (primitiveValue.isCalculated()) {
return true;
}
if (CSSPrimitiveValue::isRelativeUnit(
primitiveValue.typeWithCalcResolved())) {
return true;
}
}
}
return false;
}
TransformOperations TransformBuilder::createTransformOperations(
const CSSValue& inValue,
const CSSToLengthConversionData& conversionData) {
TransformOperations operations;
if (!inValue.isValueList()) {
DCHECK_EQ(toCSSIdentifierValue(inValue).getValueID(), CSSValueNone);
return operations;
}
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;
}
}
}
operations.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();
}
operations.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);
}
}
}
operations.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);
}
operations.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;
operations.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();
operations.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();
}
}
}
operations.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();
operations.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(),
toCSSPrimitiveValue(transformValue->item(12)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(13)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(14)).getDoubleValue(),
toCSSPrimitiveValue(transformValue->item(15)).getDoubleValue());
matrix.zoom(zoomFactor);
operations.operations().append(
Matrix3DTransformOperation::create(matrix));
break;
}
case TransformOperation::Perspective: {
double p = firstValue.computeLength<double>(conversionData);
ASSERT(p >= 0);
operations.operations().append(
PerspectiveTransformOperation::create(p));
break;
}
default:
ASSERT_NOT_REACHED();
break;
}
}
return operations;
}
} // namespace blink