/* * 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 * Copyright (C) 2007, 2008 Eric Seidel * 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 "third_party/blink/renderer/core/css/resolver/transform_builder.h" #include "third_party/blink/renderer/core/css/css_function_value.h" #include "third_party/blink/renderer/core/css/css_math_expression_node.h" #include "third_party/blink/renderer/core/css/css_math_function_value.h" #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h" #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/matrix_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/perspective_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/rotate_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/scale_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/skew_transform_operation.h" #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" #include "third_party/blink/renderer/platform/transforms/translate_transform_operation.h" namespace blink { static Length ConvertToFloatLength( const CSSPrimitiveValue& primitive_value, const CSSToLengthConversionData& conversion_data) { return primitive_value.ConvertToLength(conversion_data); } static TransformOperation::OperationType GetTransformOperationType( CSSValueID type) { switch (type) { default: NOTREACHED(); FALLTHROUGH; case CSSValueID::kScale: return TransformOperation::kScale; case CSSValueID::kScaleX: return TransformOperation::kScaleX; case CSSValueID::kScaleY: return TransformOperation::kScaleY; case CSSValueID::kScaleZ: return TransformOperation::kScaleZ; case CSSValueID::kScale3d: return TransformOperation::kScale3D; case CSSValueID::kTranslate: return TransformOperation::kTranslate; case CSSValueID::kTranslateX: return TransformOperation::kTranslateX; case CSSValueID::kTranslateY: return TransformOperation::kTranslateY; case CSSValueID::kTranslateZ: return TransformOperation::kTranslateZ; case CSSValueID::kTranslate3d: return TransformOperation::kTranslate3D; case CSSValueID::kRotate: return TransformOperation::kRotate; case CSSValueID::kRotateX: return TransformOperation::kRotateX; case CSSValueID::kRotateY: return TransformOperation::kRotateY; case CSSValueID::kRotateZ: return TransformOperation::kRotateZ; case CSSValueID::kRotate3d: return TransformOperation::kRotate3D; case CSSValueID::kSkew: return TransformOperation::kSkew; case CSSValueID::kSkewX: return TransformOperation::kSkewX; case CSSValueID::kSkewY: return TransformOperation::kSkewY; case CSSValueID::kMatrix: return TransformOperation::kMatrix; case CSSValueID::kMatrix3d: return TransformOperation::kMatrix3D; case CSSValueID::kPerspective: return TransformOperation::kPerspective; } } bool TransformBuilder::HasRelativeLengths(const CSSValueList& value_list) { for (auto& value : value_list) { const auto* transform_value = To(value.Get()); for (const CSSValue* item : *transform_value) { const auto& primitive_value = To(*item); if (primitive_value.IsCalculated()) { if (To(primitive_value).MayHaveRelativeUnit()) return true; } else { CSSPrimitiveValue::UnitType unit_type = To(primitive_value).GetType(); if (CSSPrimitiveValue::IsRelativeUnit(unit_type)) return true; } } } return false; } TransformOperations TransformBuilder::CreateTransformOperations( const CSSValue& in_value, const CSSToLengthConversionData& conversion_data) { TransformOperations operations; auto* in_value_list = DynamicTo(in_value); if (!in_value_list) { DCHECK_EQ(To(in_value).GetValueID(), CSSValueID::kNone); return operations; } float zoom_factor = conversion_data.Zoom(); for (auto& value : *in_value_list) { const auto* transform_value = To(value.Get()); TransformOperation::OperationType transform_type = GetTransformOperationType(transform_value->FunctionType()); const auto& first_value = To(transform_value->Item(0)); switch (transform_type) { case TransformOperation::kScale: case TransformOperation::kScaleX: case TransformOperation::kScaleY: { double sx = 1.0; double sy = 1.0; if (transform_type == TransformOperation::kScaleY) { sy = first_value.GetDoubleValue(); } else { sx = first_value.GetDoubleValue(); if (transform_type != TransformOperation::kScaleX) { if (transform_value->length() > 1) { const auto& second_value = To(transform_value->Item(1)); sy = second_value.GetDoubleValue(); } else { sy = sx; } } } operations.Operations().push_back( ScaleTransformOperation::Create(sx, sy, 1.0, transform_type)); break; } case TransformOperation::kScaleZ: case TransformOperation::kScale3D: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transform_type == TransformOperation::kScaleZ) { sz = first_value.GetDoubleValue(); } else { sx = first_value.GetDoubleValue(); sy = To(transform_value->Item(1)).GetDoubleValue(); sz = To(transform_value->Item(2)).GetDoubleValue(); } operations.Operations().push_back( ScaleTransformOperation::Create(sx, sy, sz, transform_type)); break; } case TransformOperation::kTranslate: case TransformOperation::kTranslateX: case TransformOperation::kTranslateY: { Length tx = Length::Fixed(0); Length ty = Length::Fixed(0); if (transform_type == TransformOperation::kTranslateY) ty = ConvertToFloatLength(first_value, conversion_data); else { tx = ConvertToFloatLength(first_value, conversion_data); if (transform_type != TransformOperation::kTranslateX) { if (transform_value->length() > 1) { const auto& second_value = To(transform_value->Item(1)); ty = ConvertToFloatLength(second_value, conversion_data); } } } operations.Operations().push_back( TranslateTransformOperation::Create(tx, ty, 0, transform_type)); break; } case TransformOperation::kTranslateZ: case TransformOperation::kTranslate3D: { Length tx = Length::Fixed(0); Length ty = Length::Fixed(0); double tz = 0; if (transform_type == TransformOperation::kTranslateZ) { tz = first_value.ComputeLength(conversion_data); } else { tx = ConvertToFloatLength(first_value, conversion_data); ty = ConvertToFloatLength( To(transform_value->Item(1)), conversion_data); tz = To(transform_value->Item(2)) .ComputeLength(conversion_data); } operations.Operations().push_back( TranslateTransformOperation::Create(tx, ty, tz, transform_type)); break; } case TransformOperation::kRotateX: case TransformOperation::kRotateY: case TransformOperation::kRotateZ: { double angle = first_value.ComputeDegrees(); if (transform_value->length() == 1) { double x = transform_type == TransformOperation::kRotateX; double y = transform_type == TransformOperation::kRotateY; double z = transform_type == TransformOperation::kRotateZ; operations.Operations().push_back( RotateTransformOperation::Create(x, y, z, angle, transform_type)); } else { // For SVG 'transform' attributes we generate 3-argument rotate() // functions. DCHECK_EQ(transform_value->length(), 3u); const auto& second_value = To(transform_value->Item(1)); const CSSPrimitiveValue& third_value = To(transform_value->Item(2)); operations.Operations().push_back( RotateAroundOriginTransformOperation::Create( angle, second_value.ComputeLength(conversion_data), third_value.ComputeLength(conversion_data))); } break; } case TransformOperation::kRotate3D: { const auto& second_value = To(transform_value->Item(1)); const auto& third_value = To(transform_value->Item(2)); const auto& fourth_value = To(transform_value->Item(3)); double x = first_value.GetDoubleValue(); double y = second_value.GetDoubleValue(); double z = third_value.GetDoubleValue(); double angle = fourth_value.ComputeDegrees(); operations.Operations().push_back( RotateTransformOperation::Create(x, y, z, angle, transform_type)); break; } case TransformOperation::kSkew: case TransformOperation::kSkewX: case TransformOperation::kSkewY: { double angle_x = 0; double angle_y = 0; double angle = first_value.ComputeDegrees(); if (transform_type == TransformOperation::kSkewY) angle_y = angle; else { angle_x = angle; if (transform_type == TransformOperation::kSkew) { if (transform_value->length() > 1) { const auto& second_value = To(transform_value->Item(1)); angle_y = second_value.ComputeDegrees(); } } } operations.Operations().push_back( SkewTransformOperation::Create(angle_x, angle_y, transform_type)); break; } case TransformOperation::kMatrix: { double a = first_value.GetDoubleValue(); double b = To(transform_value->Item(1)).GetDoubleValue(); double c = To(transform_value->Item(2)).GetDoubleValue(); double d = To(transform_value->Item(3)).GetDoubleValue(); double e = zoom_factor * To(transform_value->Item(4)).GetDoubleValue(); double f = zoom_factor * To(transform_value->Item(5)).GetDoubleValue(); operations.Operations().push_back( MatrixTransformOperation::Create(a, b, c, d, e, f)); break; } case TransformOperation::kMatrix3D: { TransformationMatrix matrix( To(transform_value->Item(0)).GetDoubleValue(), To(transform_value->Item(1)).GetDoubleValue(), To(transform_value->Item(2)).GetDoubleValue(), To(transform_value->Item(3)).GetDoubleValue(), To(transform_value->Item(4)).GetDoubleValue(), To(transform_value->Item(5)).GetDoubleValue(), To(transform_value->Item(6)).GetDoubleValue(), To(transform_value->Item(7)).GetDoubleValue(), To(transform_value->Item(8)).GetDoubleValue(), To(transform_value->Item(9)).GetDoubleValue(), To(transform_value->Item(10)).GetDoubleValue(), To(transform_value->Item(11)).GetDoubleValue(), To(transform_value->Item(12)).GetDoubleValue(), To(transform_value->Item(13)).GetDoubleValue(), To(transform_value->Item(14)).GetDoubleValue(), To(transform_value->Item(15)).GetDoubleValue()); matrix.Zoom(zoom_factor); operations.Operations().push_back( Matrix3DTransformOperation::Create(matrix)); break; } case TransformOperation::kPerspective: { double p = first_value.ComputeLength(conversion_data); DCHECK_GE(p, 0); operations.Operations().push_back( PerspectiveTransformOperation::Create(p)); break; } default: NOTREACHED(); break; } } return operations; } } // namespace blink