blob: 03be3142c7fb2096cc062ca0e929fdff510b25a5 [file] [log] [blame]
/*
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
* Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#include "TransformFunctions.h"
#include "CSSPrimitiveValueMappings.h"
#include "CSSValueList.h"
#include "CSSValuePool.h"
#include "Matrix3DTransformOperation.h"
#include "MatrixTransformOperation.h"
#include "PerspectiveTransformOperation.h"
#include "RenderStyle.h"
#include "RotateTransformOperation.h"
#include "ScaleTransformOperation.h"
#include "SkewTransformOperation.h"
#include "TranslateTransformOperation.h"
#include "WebKitCSSTransformValue.h"
namespace WebCore {
static TransformOperation::OperationType transformOperationType(WebKitCSSTransformValue::TransformOperationType type)
{
switch (type) {
case WebKitCSSTransformValue::ScaleTransformOperation: return TransformOperation::SCALE;
case WebKitCSSTransformValue::ScaleXTransformOperation: return TransformOperation::SCALE_X;
case WebKitCSSTransformValue::ScaleYTransformOperation: return TransformOperation::SCALE_Y;
case WebKitCSSTransformValue::ScaleZTransformOperation: return TransformOperation::SCALE_Z;
case WebKitCSSTransformValue::Scale3DTransformOperation: return TransformOperation::SCALE_3D;
case WebKitCSSTransformValue::TranslateTransformOperation: return TransformOperation::TRANSLATE;
case WebKitCSSTransformValue::TranslateXTransformOperation: return TransformOperation::TRANSLATE_X;
case WebKitCSSTransformValue::TranslateYTransformOperation: return TransformOperation::TRANSLATE_Y;
case WebKitCSSTransformValue::TranslateZTransformOperation: return TransformOperation::TRANSLATE_Z;
case WebKitCSSTransformValue::Translate3DTransformOperation: return TransformOperation::TRANSLATE_3D;
case WebKitCSSTransformValue::RotateTransformOperation: return TransformOperation::ROTATE;
case WebKitCSSTransformValue::RotateXTransformOperation: return TransformOperation::ROTATE_X;
case WebKitCSSTransformValue::RotateYTransformOperation: return TransformOperation::ROTATE_Y;
case WebKitCSSTransformValue::RotateZTransformOperation: return TransformOperation::ROTATE_Z;
case WebKitCSSTransformValue::Rotate3DTransformOperation: return TransformOperation::ROTATE_3D;
case WebKitCSSTransformValue::SkewTransformOperation: return TransformOperation::SKEW;
case WebKitCSSTransformValue::SkewXTransformOperation: return TransformOperation::SKEW_X;
case WebKitCSSTransformValue::SkewYTransformOperation: return TransformOperation::SKEW_Y;
case WebKitCSSTransformValue::MatrixTransformOperation: return TransformOperation::MATRIX;
case WebKitCSSTransformValue::Matrix3DTransformOperation: return TransformOperation::MATRIX_3D;
case WebKitCSSTransformValue::PerspectiveTransformOperation: return TransformOperation::PERSPECTIVE;
case WebKitCSSTransformValue::UnknownTransformOperation: return TransformOperation::NONE;
}
return TransformOperation::NONE;
}
Length convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const CSSToLengthConversionData& conversionData)
{
return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion>(conversionData) : Length(Undefined);
}
bool transformsForValue(CSSValue& value, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations)
{
if (!is<CSSValueList>(value)) {
outOperations.clear();
return false;
}
TransformOperations operations;
for (auto& currentValue : downcast<CSSValueList>(value)) {
if (!is<WebKitCSSTransformValue>(currentValue.get()))
continue;
auto& transformValue = downcast<WebKitCSSTransformValue>(currentValue.get());
if (!transformValue.length())
continue;
bool haveNonPrimitiveValue = false;
for (unsigned j = 0; j < transformValue.length(); ++j) {
if (!is<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(j))) {
haveNonPrimitiveValue = true;
break;
}
}
if (haveNonPrimitiveValue)
continue;
CSSPrimitiveValue& firstValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(0));
switch (transformValue.operationType()) {
case WebKitCSSTransformValue::ScaleTransformOperation:
case WebKitCSSTransformValue::ScaleXTransformOperation:
case WebKitCSSTransformValue::ScaleYTransformOperation: {
double sx = 1.0;
double sy = 1.0;
if (transformValue.operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
sy = firstValue.getDoubleValue();
else {
sx = firstValue.getDoubleValue();
if (transformValue.operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
if (transformValue.length() > 1) {
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
sy = secondValue.getDoubleValue();
} else
sy = sx;
}
}
operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::ScaleZTransformOperation:
case WebKitCSSTransformValue::Scale3DTransformOperation: {
double sx = 1.0;
double sy = 1.0;
double sz = 1.0;
if (transformValue.operationType() == WebKitCSSTransformValue::ScaleZTransformOperation)
sz = firstValue.getDoubleValue();
else if (transformValue.operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
sy = firstValue.getDoubleValue();
else {
sx = firstValue.getDoubleValue();
if (transformValue.operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
if (transformValue.length() > 2) {
CSSPrimitiveValue& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
sz = thirdValue.getDoubleValue();
}
if (transformValue.length() > 1) {
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
sy = secondValue.getDoubleValue();
} else
sy = sx;
}
}
operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::TranslateTransformOperation:
case WebKitCSSTransformValue::TranslateXTransformOperation:
case WebKitCSSTransformValue::TranslateYTransformOperation: {
Length tx = Length(0, Fixed);
Length ty = Length(0, Fixed);
if (transformValue.operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
ty = convertToFloatLength(&firstValue, conversionData);
else {
tx = convertToFloatLength(&firstValue, conversionData);
if (transformValue.operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
if (transformValue.length() > 1) {
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
ty = convertToFloatLength(&secondValue, conversionData);
}
}
}
if (tx.isUndefined() || ty.isUndefined())
return false;
operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::TranslateZTransformOperation:
case WebKitCSSTransformValue::Translate3DTransformOperation: {
Length tx = Length(0, Fixed);
Length ty = Length(0, Fixed);
Length tz = Length(0, Fixed);
if (transformValue.operationType() == WebKitCSSTransformValue::TranslateZTransformOperation)
tz = convertToFloatLength(&firstValue, conversionData);
else if (transformValue.operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
ty = convertToFloatLength(&firstValue, conversionData);
else {
tx = convertToFloatLength(&firstValue, conversionData);
if (transformValue.operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
if (transformValue.length() > 2) {
CSSPrimitiveValue& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
tz = convertToFloatLength(&thirdValue, conversionData);
}
if (transformValue.length() > 1) {
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
ty = convertToFloatLength(&secondValue, conversionData);
}
}
}
if (tx.isUndefined() || ty.isUndefined() || tz.isUndefined())
return false;
operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::RotateTransformOperation: {
double angle = firstValue.computeDegrees();
operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::RotateXTransformOperation:
case WebKitCSSTransformValue::RotateYTransformOperation:
case WebKitCSSTransformValue::RotateZTransformOperation: {
double x = 0;
double y = 0;
double z = 0;
double angle = firstValue.computeDegrees();
if (transformValue.operationType() == WebKitCSSTransformValue::RotateXTransformOperation)
x = 1;
else if (transformValue.operationType() == WebKitCSSTransformValue::RotateYTransformOperation)
y = 1;
else
z = 1;
operations.operations().append(RotateTransformOperation::create(x, y, z, angle, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::Rotate3DTransformOperation: {
if (transformValue.length() < 4)
break;
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
CSSPrimitiveValue& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
CSSPrimitiveValue& fourthValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(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, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::SkewTransformOperation:
case WebKitCSSTransformValue::SkewXTransformOperation:
case WebKitCSSTransformValue::SkewYTransformOperation: {
double angleX = 0;
double angleY = 0;
double angle = firstValue.computeDegrees();
if (transformValue.operationType() == WebKitCSSTransformValue::SkewYTransformOperation)
angleY = angle;
else {
angleX = angle;
if (transformValue.operationType() == WebKitCSSTransformValue::SkewTransformOperation) {
if (transformValue.length() > 1) {
CSSPrimitiveValue& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
angleY = secondValue.computeDegrees();
}
}
}
operations.operations().append(SkewTransformOperation::create(angleX, angleY, transformOperationType(transformValue.operationType())));
break;
}
case WebKitCSSTransformValue::MatrixTransformOperation: {
if (transformValue.length() < 6)
break;
double a = firstValue.getDoubleValue();
double b = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1)).getDoubleValue();
double c = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2)).getDoubleValue();
double d = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(3)).getDoubleValue();
double e = conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(4)).getDoubleValue();
double f = conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(5)).getDoubleValue();
operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f));
break;
}
case WebKitCSSTransformValue::Matrix3DTransformOperation: {
if (transformValue.length() < 16)
break;
TransformationMatrix matrix(downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(0)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(3)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(4)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(5)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(6)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(7)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(8)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(9)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(10)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(11)).getDoubleValue(),
conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(12)).getDoubleValue(),
conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(13)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(14)).getDoubleValue(),
downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(15)).getDoubleValue());
operations.operations().append(Matrix3DTransformOperation::create(matrix));
break;
}
case WebKitCSSTransformValue::PerspectiveTransformOperation: {
Length p = Length(0, Fixed);
if (firstValue.isLength())
p = convertToFloatLength(&firstValue, conversionData);
else {
// This is a quirk that should go away when 3d transforms are finalized.
double val = firstValue.getDoubleValue();
p = val >= 0 ? Length(clampToPositiveInteger(val), Fixed) : Length(Undefined);
}
if (p.isUndefined())
return false;
operations.operations().append(PerspectiveTransformOperation::create(p));
break;
}
case WebKitCSSTransformValue::UnknownTransformOperation:
ASSERT_NOT_REACHED();
break;
}
}
outOperations = operations;
return true;
}
}